1 /* $NetBSD: machdep.c,v 1.81 2026/04/08 04:06:40 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002, 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.81 2026/04/08 04:06:40 thorpej Exp $"); 31 32 #include "opt_md.h" 33 #include "opt_ddb.h" 34 #include "opt_kgdb.h" 35 #include "opt_modular.h" 36 #include "biconsdev.h" 37 #include "debug_hpc.h" 38 #include "hd64465if.h" 39 40 #include "opt_kloader.h" 41 #include "opt_kloader_kernel_path.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/device.h> 47 #include <sys/lwp.h> 48 49 #include <sys/reboot.h> 50 #include <sys/mount.h> 51 #include <sys/sysctl.h> 52 #include <sys/kcore.h> 53 #include <sys/boot_flag.h> 54 #include <sys/ksyms.h> 55 #include <sys/module.h> 56 #include <sys/cpu.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <ufs/mfs/mfs_extern.h> /* mfs_initminiroot() */ 61 62 #include <sh3/cpu.h> 63 #include <sh3/exception.h> 64 #include <sh3/cache.h> 65 #include <sh3/clock.h> 66 #include <sh3/intcreg.h> 67 #include <sh3/proc.h> 68 69 #ifdef KGDB 70 #include <sys/kgdb.h> 71 #endif 72 73 #include "ksyms.h" 74 75 #if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB) 76 #include <machine/db_machdep.h> 77 #include <ddb/db_sym.h> 78 #include <ddb/db_extern.h> 79 #include <sys/exec_elf.h> 80 #endif /* NKSYMS || MODULAR || DDB || KGDB */ 81 82 #include <dev/cons.h> /* consdev */ 83 #include <dev/md.h> 84 85 #include <machine/bootinfo.h> 86 #include <machine/platid.h> 87 #include <machine/platid_mask.h> 88 #ifdef KLOADER 89 #include <machine/kloader.h> 90 #endif 91 #include <machine/autoconf.h> /* makebootdev() */ 92 #include <machine/intr.h> 93 #include <machine/pcb.h> 94 95 #include <nfs/rpcv2.h> 96 #include <nfs/nfsproto.h> 97 #include <nfs/nfs.h> 98 #include <nfs/nfsmount.h> 99 100 #include <dev/hpc/apm/apmvar.h> 101 102 #include <hpcsh/dev/hd6446x/hd6446xintcvar.h> 103 #include <hpcsh/dev/hd6446x/hd6446xintcreg.h> 104 #include <hpcsh/dev/hd64465/hd64465var.h> 105 106 #ifdef DEBUG 107 #define DPRINTF_ENABLE 108 #define DPRINTF_DEBUG machdep_debug 109 #endif /* DEBUG */ 110 #include <machine/debug.h> 111 112 /* 113 * D-RAM location (Windows CE machine specific) 114 * 115 * Jornada 690 (32MB model) SH7709A 116 * + SH7709A split CS3 to 2 banks. 117 * 118 * CS3 (0x0c000000-0x0fffffff 119 * 0x0c000000 --- onboard 16MByte 120 * 0x0d000000 --- onboard 16MByte (shadow) 121 * 0x0e000000 --- extension 16MByte 122 * 0x0f000000 --- extension 16MByte (shadow) 123 * 124 * PERSONA HPW-650PA (16MB model) SH7750 125 * SH7750 126 * 127 * CS3 (0x0c000000-0x0fffffff 128 * 0x0c000000 --- onboard 16MByte 129 * 0x0d000000 --- onboard 16MByte (shadow) 130 * 0x0e000000 --- onboard 16MByte (shadow) 131 * 0x0f000000 --- onboard 16MByte (shadow) 132 */ 133 134 #define SH_CS3_START 0x0c000000 135 #define SH_CS3_END (SH_CS3_START + 0x04000000) 136 137 #define SH7709_CS3_BANK0_START 0x0c000000 138 #define SH7709_CS3_BANK0_END (SH7709_CS3_BANK0_START + 0x02000000) 139 #define SH7709_CS3_BANK1_START 0x0e000000 140 #define SH7709_CS3_BANK1_END (SH7709_CS3_BANK1_START + 0x02000000) 141 142 /* Machine */ 143 char machine[] = MACHINE; 144 char machine_arch[] = MACHINE_ARCH; 145 146 /* Physical memory */ 147 static int mem_cluster_init(paddr_t); 148 static void mem_cluster_load(void); 149 static void __find_dram_shadow(paddr_t, paddr_t); 150 #ifdef NARLY_MEMORY_PROBE 151 static int __check_dram(paddr_t, paddr_t); 152 #endif 153 int mem_cluster_cnt; 154 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 155 156 /* bootinfo */ 157 static struct bootinfo bootinfo_storage; 158 struct bootinfo *bootinfo = &bootinfo_storage; 159 160 /* hpcapm: machine_sleep() */ 161 void (*__sleep_func)(void *); /* model dependent sleep function holder */ 162 void *__sleep_ctx; 163 164 extern void main(void) __attribute__((__noreturn__)); 165 void machine_startup(int, char *[], struct bootinfo *) 166 __attribute__((__noreturn__)); 167 168 #ifdef KLOADER 169 #if !defined(KLOADER_KERNEL_PATH) 170 #define KLOADER_KERNEL_PATH "/netbsd" 171 #endif /* !KLOADER_KERNEL_PATH */ 172 static const char kernel_path[] = KLOADER_KERNEL_PATH; 173 #endif /* KLOADER */ 174 175 void 176 machine_startup(int argc, char *argv[], struct bootinfo *bi) 177 { 178 extern char edata[], end[]; 179 vaddr_t kernend; 180 size_t symbolsize; 181 int i; 182 char *p; 183 184 #ifdef KLOADER 185 /* 186 * this routines stack is never polluted since stack pointer 187 * is lower than kernel text segment, and at exiting, stack pointer 188 * is changed to proc0. 189 */ 190 struct kloader_bootinfo kbi; 191 #endif 192 193 /* Symbol table size */ 194 symbolsize = 0; 195 #if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB) 196 if (memcmp(&end, ELFMAG, SELFMAG) == 0) { 197 Elf_Ehdr *eh = (void *)end; 198 Elf_Shdr *sh = (void *)(end + eh->e_shoff); 199 for(i = 0; i < eh->e_shnum; i++, sh++) 200 if (sh->sh_offset > 0 && 201 (sh->sh_offset + sh->sh_size) > symbolsize) 202 symbolsize = sh->sh_offset + sh->sh_size; 203 } 204 #endif 205 206 /* Clear BSS */ 207 memset(edata, 0, end - edata); 208 209 /* Setup bootinfo */ 210 memcpy(&bootinfo_storage, bi, sizeof(struct bootinfo)); 211 if (bootinfo->magic == BOOTINFO_MAGIC) { 212 platid.dw.dw0 = bootinfo->platid_cpu; 213 platid.dw.dw1 = bootinfo->platid_machine; 214 } 215 216 /* CPU initialize */ 217 if (platid_match(&platid, &platid_mask_CPU_SH_3)) 218 sh_cpu_init(CPU_ARCH_SH3, CPU_PRODUCT_7709A); 219 else if (platid_match(&platid, &platid_mask_CPU_SH_4)) 220 sh_cpu_init(CPU_ARCH_SH4, CPU_PRODUCT_7750); 221 222 #ifndef RTC_OFFSET 223 /* 224 * rtc_offset from bootinfo.timezone set by hpcboot.exe 225 */ 226 if (rtc_offset == 0 227 && bootinfo->timezone > (-12*60) 228 && bootinfo->timezone <= (12*60)) 229 rtc_offset = bootinfo->timezone; 230 #endif 231 232 /* Start to determine heap area */ 233 kernend = (vaddr_t)sh3_round_page(end + symbolsize); 234 235 /* Setup bootstrap options */ 236 makebootdev("wd0"); /* default boot device */ 237 boothowto = 0; 238 for (i = 1; i < argc; i++) { /* skip 1st arg (kernel name). */ 239 char *cp = argv[i]; 240 switch (*cp) { 241 case 'b': 242 /* boot device: -b=sd0 etc. */ 243 p = cp + 2; 244 if (strcmp(p, "nfs") == 0) 245 rootfstype = MOUNT_NFS; 246 else 247 makebootdev(p); 248 break; 249 default: 250 BOOT_FLAG(*cp, boothowto); 251 break; 252 } 253 } 254 255 /* 256 * Check to see if a mini-root was loaded into memory. It resides 257 * at the start of the next page just after the end of BSS. 258 */ 259 if (boothowto & RB_MINIROOT) { 260 size_t fssz; 261 fssz = sh3_round_page(mfs_initminiroot((void *)kernend)); 262 #ifdef MEMORY_DISK_DYNAMIC 263 md_root_setconf((void *)kernend, fssz); 264 #endif 265 kernend += fssz; 266 } 267 268 /* Console */ 269 consinit(); 270 #ifdef HPC_DEBUG_LCD 271 dbg_lcd_test(); 272 #endif 273 274 #ifdef KLOADER 275 /* copy boot parameter for kloader */ 276 kloader_bootinfo_set(&kbi, argc, argv, bootinfo, true); 277 #endif 278 279 /* Find memory cluster. and load to UVM */ 280 physmem = mem_cluster_init(SH3_P1SEG_TO_PHYS(kernend)); 281 _DPRINTF("total memory = %dMbyte\n", (int)(sh3_ptob(physmem) >> 20)); 282 mem_cluster_load(); 283 284 /* Initialize proc0 u-area */ 285 sh_proc0_init(); 286 287 /* Initialize pmap and start to address translation */ 288 pmap_bootstrap(); 289 290 #if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB) 291 if (symbolsize) { 292 ksyms_addsyms_elf(symbolsize, &end, end + symbolsize); 293 _DPRINTF("symbol size = %d byte\n", symbolsize); 294 } 295 #endif 296 #ifdef DDB 297 /* Debugger. */ 298 if (boothowto & RB_KDB) 299 Debugger(); 300 #endif /* DDB */ 301 #ifdef KGDB 302 if (boothowto & RB_KDB) { 303 if (kgdb_dev == NODEV) { 304 printf("no kgdb console.\n"); 305 } else { 306 kgdb_debug_init = 1; 307 kgdb_connect(1); 308 } 309 } 310 #endif /* KGDB */ 311 312 /* Jump to main */ 313 __asm volatile( 314 "jmp @%0;" 315 "mov %1, sp" 316 :: "r"(main),"r"(lwp0.l_md.md_pcb->pcb_sf.sf_r7_bank)); 317 318 /* NOTREACHED */ 319 for (;;) 320 continue; 321 } 322 323 void 324 cpu_startup(void) 325 { 326 327 cpu_setmodel("%s", platid_name(&platid)); 328 329 sh_startup(); 330 } 331 332 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 333 { 334 335 sysctl_createv(clog, 0, NULL, NULL, 336 CTLFLAG_PERMANENT, 337 CTLTYPE_NODE, "machdep", NULL, 338 NULL, 0, NULL, 0, 339 CTL_MACHDEP, CTL_EOL); 340 341 sysctl_createv(clog, 0, NULL, NULL, 342 CTLFLAG_PERMANENT, 343 CTLTYPE_STRUCT, "console_device", NULL, 344 sysctl_consdev, 0, NULL, sizeof(dev_t), 345 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 346 } 347 348 /* hpcapm */ 349 void 350 machine_sleep(void) 351 { 352 353 if (__sleep_func != NULL) 354 __sleep_func(__sleep_ctx); 355 } 356 357 /* hpcapm */ 358 void 359 machine_standby(void) 360 { 361 /* notyet */ 362 } 363 364 void 365 cpu_reboot(int howto, char *bootstr) 366 { 367 368 /* take a snap shot before clobbering any registers */ 369 if (curlwp) 370 savectx(curpcb); 371 372 /* If system is cold, just halt. */ 373 if (cold) { 374 howto |= RB_HALT; 375 goto haltsys; 376 } 377 378 /* If "always halt" was specified as a boot flag, obey. */ 379 if ((boothowto & RB_HALT) != 0) { 380 howto |= RB_HALT; 381 } 382 383 #ifdef KLOADER 384 if ((howto & RB_HALT) == 0) { 385 if ((howto & RB_STRING) != 0) 386 kloader_reboot_setup(bootstr); 387 else 388 kloader_reboot_setup(kernel_path); 389 } 390 #endif 391 392 boothowto = howto; 393 if ((howto & RB_NOSYNC) == 0) { 394 /* 395 * Synchronize the disks.... 396 */ 397 vfs_shutdown(); 398 } 399 400 /* Disable interrupts. */ 401 splhigh(); 402 403 /* If rebooting and a dump is requested do it. */ 404 #if notyet 405 if (howto & RB_DUMP) 406 dumpsys(); 407 #endif 408 409 haltsys: 410 /* run any shutdown hooks */ 411 doshutdownhooks(); 412 413 pmf_system_shutdown(boothowto); 414 415 /* Finally, halt/reboot the system. */ 416 if ((howto & RB_HALT) != 0) { 417 printf("halted.\n"); 418 } else { 419 #ifdef KLOADER 420 kloader_reboot(); 421 /* NOTREACHED */ 422 #endif 423 } 424 425 #if NHD64465IF > 0 426 hd64465_shutdown(); 427 #endif 428 429 cpu_reset(); 430 431 /* NOTREACHED */ 432 for (;;) 433 continue; 434 } 435 436 /* return # of physical pages. */ 437 static int 438 mem_cluster_init(paddr_t addr) 439 { 440 phys_ram_seg_t *seg; 441 int npages, i; 442 443 /* cluster 0 is always the kernel itself. */ 444 mem_clusters[0].start = SH_CS3_START; 445 mem_clusters[0].size = addr - SH_CS3_START; 446 mem_cluster_cnt = 1; 447 448 /* search CS3 */ 449 #ifdef SH3 450 /* SH7709A's CS3 is split to 2 banks. */ 451 if (CPU_IS_SH3) { 452 __find_dram_shadow(addr, SH7709_CS3_BANK0_END); 453 __find_dram_shadow(SH7709_CS3_BANK1_START, 454 SH7709_CS3_BANK1_END); 455 } 456 #endif 457 #ifdef SH4 458 /* contiguous CS3 */ 459 if (CPU_IS_SH4) { 460 __find_dram_shadow(addr, SH_CS3_END); 461 } 462 #endif 463 _DPRINTF("mem_cluster_cnt = %d\n", mem_cluster_cnt); 464 npages = 0; 465 for (i = 0, seg = mem_clusters; i < mem_cluster_cnt; i++, seg++) { 466 _DPRINTF("mem_clusters[%d] = {0x%lx+0x%lx <0x%lx}", i, 467 (paddr_t)seg->start, (paddr_t)seg->size, 468 (paddr_t)seg->start + (paddr_t)seg->size); 469 npages += sh3_btop(seg->size); 470 #ifdef NARLY_MEMORY_PROBE 471 if (i == 0) { 472 _DPRINTF(" don't check.\n"); 473 continue; 474 } 475 if (__check_dram((paddr_t)seg->start, (paddr_t)seg->start + 476 (paddr_t)seg->size) != 0) 477 panic("D-RAM check failed."); 478 #else 479 _DPRINTF("\n"); 480 #endif /* NARLY_MEMORY_PROBE */ 481 } 482 483 return (npages); 484 } 485 486 static void 487 mem_cluster_load(void) 488 { 489 paddr_t start, end; 490 psize_t size; 491 int i; 492 493 /* Cluster 0 is always the kernel, which doesn't get loaded. */ 494 sh_dcache_wbinv_all(); 495 for (i = 1; i < mem_cluster_cnt; i++) { 496 start = (paddr_t)mem_clusters[i].start; 497 size = (psize_t)mem_clusters[i].size; 498 499 _DPRINTF("loading 0x%lx,0x%lx\n", start, size); 500 memset((void *)SH3_PHYS_TO_P1SEG(start), 0, size); 501 end = atop(start + size); 502 start = atop(start); 503 uvm_page_physload(start, end, start, end, VM_FREELIST_DEFAULT); 504 } 505 sh_dcache_wbinv_all(); 506 } 507 508 static void 509 __find_dram_shadow(paddr_t start, paddr_t end) 510 { 511 vaddr_t page, startaddr, endaddr; 512 int x; 513 514 _DPRINTF("search D-RAM from 0x%08lx for 0x%08lx\n", start, end); 515 startaddr = SH3_PHYS_TO_P2SEG(start); 516 endaddr = SH3_PHYS_TO_P2SEG(end); 517 518 page = startaddr; 519 520 x = random(); 521 *(volatile int *)(page + 0) = x; 522 *(volatile int *)(page + 4) = ~x; 523 524 if (*(volatile int *)(page + 0) != x || 525 *(volatile int *)(page + 4) != ~x) 526 return; 527 528 for (page += PAGE_SIZE; page < endaddr; page += PAGE_SIZE) { 529 if (*(volatile int *)(page + 0) == x && 530 *(volatile int *)(page + 4) == ~x) { 531 goto memend_found; 532 } 533 } 534 535 page -= PAGE_SIZE; 536 *(volatile int *)(page + 0) = x; 537 *(volatile int *)(page + 4) = ~x; 538 539 if (*(volatile int *)(page + 0) != x || 540 *(volatile int *)(page + 4) != ~x) 541 return; /* no memory in this bank */ 542 543 memend_found: 544 KASSERT(mem_cluster_cnt < VM_PHYSSEG_MAX); 545 546 mem_clusters[mem_cluster_cnt].start = start; 547 mem_clusters[mem_cluster_cnt].size = page - startaddr; 548 549 /* skip kernel area */ 550 if (mem_cluster_cnt == 1) 551 mem_clusters[1].size -= mem_clusters[0].size; 552 553 mem_cluster_cnt++; 554 } 555 556 #ifdef NARLY_MEMORY_PROBE 557 static int 558 __check_dram(paddr_t start, paddr_t end) 559 { 560 uint8_t *page; 561 int i, x; 562 563 _DPRINTF(" checking..."); 564 for (; start < end; start += PAGE_SIZE) { 565 page = (uint8_t *)SH3_PHYS_TO_P2SEG (start); 566 x = random(); 567 for (i = 0; i < PAGE_SIZE; i += 4) 568 *(volatile int *)(page + i) = (x ^ i); 569 for (i = 0; i < PAGE_SIZE; i += 4) 570 if (*(volatile int *)(page + i) != (x ^ i)) 571 goto bad; 572 x = random(); 573 for (i = 0; i < PAGE_SIZE; i += 4) 574 *(volatile int *)(page + i) = (x ^ i); 575 for (i = 0; i < PAGE_SIZE; i += 4) 576 if (*(volatile int *)(page + i) != (x ^ i)) 577 goto bad; 578 } 579 _DPRINTF("success.\n"); 580 return (0); 581 bad: 582 _DPRINTF("failed.\n"); 583 return (1); 584 } 585 #endif /* NARLY_MEMORY_PROBE */ 586 587 void 588 intc_intr(int ssr, int spc, int ssp) 589 { 590 struct intc_intrhand *ih; 591 int evtcode; 592 uint16_t r; 593 594 curcpu()->ci_data.cpu_nintr++; 595 596 evtcode = _reg_read_4(CPU_IS_SH3 ? SH7709_INTEVT2 : SH4_INTEVT); 597 598 ih = EVTCODE_IH(evtcode); 599 KDASSERT(ih->ih_func); 600 /* 601 * On entry, all interrupts are disabled, 602 * and exception is enabled for P3 access. (kernel stack is P3, 603 * SH3 may or may not cause TLB miss when access stack.) 604 * Enable higher level interrupt here. 605 */ 606 r = _reg_read_2(HD6446X_NIRR); 607 608 splx(ih->ih_level); 609 610 if (evtcode == SH_INTEVT_TMU0_TUNI0) { 611 struct clockframe cf; 612 cf.spc = spc; 613 cf.ssr = ssr; 614 cf.ssp = ssp; 615 (*ih->ih_func)(&cf); 616 __dbg_heart_beat(HEART_BEAT_RED); 617 } else if (evtcode == 618 (CPU_IS_SH3 ? SH7709_INTEVT2_IRQ4 : SH_INTEVT_IRL11)) { 619 struct hd6446x_intrhand *hh; 620 int cause; 621 622 cause = r & hd6446x_ienable; 623 if (cause == 0) { 624 printf("masked HD6446x interrupt 0x%04x\n", 625 r & ~hd6446x_ienable); 626 _reg_write_2(HD6446X_NIRR, 0x0000); 627 return; 628 } 629 /* Enable higher level interrupt*/ 630 hh = &hd6446x_intrhand[ffs(cause) - 1]; 631 hd6446x_intr_resume(hh->hh_ipl); 632 KDASSERT(hh->hh_func != NULL); 633 (*hh->hh_func)(hh->hh_arg); 634 __dbg_heart_beat(HEART_BEAT_GREEN); 635 } else { 636 (*ih->ih_func)(ih->ih_arg); 637 __dbg_heart_beat(HEART_BEAT_BLUE); 638 } 639 } 640