1 /* $NetBSD: machdep.c,v 1.80 2024/03/05 14:15:32 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.80 2024/03/05 14:15:32 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
machine_startup(int argc,char * argv[],struct bootinfo * bi)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
cpu_startup(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
machine_sleep(void)350 machine_sleep(void)
351 {
352
353 if (__sleep_func != NULL)
354 __sleep_func(__sleep_ctx);
355 }
356
357 /* hpcapm */
358 void
machine_standby(void)359 machine_standby(void)
360 {
361 /* notyet */
362 }
363
364 void
cpu_reboot(int howto,char * bootstr)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
mem_cluster_init(paddr_t addr)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
mem_cluster_load(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
__find_dram_shadow(paddr_t start,paddr_t end)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
__check_dram(paddr_t start,paddr_t end)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
intc_intr(int ssr,int spc,int ssp)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
641
642 #ifdef MODULAR
643 /*
644 * Push any modules loaded by the boot loader.
645 */
646 void
module_init_md(void)647 module_init_md(void)
648 {
649 }
650 #endif /* MODULAR */
651