xref: /netbsd/sys/arch/hpcsh/hpcsh/machdep.c (revision 8ad7f8ea)
1 /*	$NetBSD: machdep.c,v 1.78 2017/11/06 03:47:46 christos 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.78 2017/11/06 03:47:46 christos 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 		 * If we've been adjusting the clock, the todr
401 		 * will be out of synch; adjust it now.
402 		 */
403 		resettodr();
404 	}
405 
406 	/* Disable interrupts. */
407 	splhigh();
408 
409 	/* If rebooting and a dump is requested do it. */
410 #if notyet
411 	if (howto & RB_DUMP)
412 		dumpsys();
413 #endif
414 
415  haltsys:
416 	/* run any shutdown hooks */
417 	doshutdownhooks();
418 
419 	pmf_system_shutdown(boothowto);
420 
421 	/* Finally, halt/reboot the system. */
422 	if ((howto & RB_HALT) != 0) {
423 		printf("halted.\n");
424 	} else {
425 #ifdef KLOADER
426 		kloader_reboot();
427 		/* NOTREACHED */
428 #endif
429 	}
430 
431 #if NHD64465IF > 0
432 	hd64465_shutdown();
433 #endif
434 
435 	cpu_reset();
436 
437 	/* NOTREACHED */
438 	for (;;)
439 		continue;
440 }
441 
442 /* return # of physical pages. */
443 static int
mem_cluster_init(paddr_t addr)444 mem_cluster_init(paddr_t addr)
445 {
446 	phys_ram_seg_t *seg;
447 	int npages, i;
448 
449 	/* cluster 0 is always the kernel itself. */
450 	mem_clusters[0].start = SH_CS3_START;
451 	mem_clusters[0].size = addr - SH_CS3_START;
452 	mem_cluster_cnt = 1;
453 
454 	/* search CS3 */
455 #ifdef SH3
456 	/* SH7709A's CS3 is split to 2 banks. */
457 	if (CPU_IS_SH3) {
458 		__find_dram_shadow(addr, SH7709_CS3_BANK0_END);
459 		__find_dram_shadow(SH7709_CS3_BANK1_START,
460 		    SH7709_CS3_BANK1_END);
461 	}
462 #endif
463 #ifdef SH4
464 	/* contiguous CS3 */
465 	if (CPU_IS_SH4) {
466 		__find_dram_shadow(addr, SH_CS3_END);
467 	}
468 #endif
469 	_DPRINTF("mem_cluster_cnt = %d\n", mem_cluster_cnt);
470 	npages = 0;
471 	for (i = 0, seg = mem_clusters; i < mem_cluster_cnt; i++, seg++) {
472 		_DPRINTF("mem_clusters[%d] = {0x%lx+0x%lx <0x%lx}", i,
473 		    (paddr_t)seg->start, (paddr_t)seg->size,
474 		    (paddr_t)seg->start + (paddr_t)seg->size);
475 		npages += sh3_btop(seg->size);
476 #ifdef NARLY_MEMORY_PROBE
477 		if (i == 0) {
478 			_DPRINTF(" don't check.\n");
479 			continue;
480 		}
481 		if (__check_dram((paddr_t)seg->start, (paddr_t)seg->start +
482 		    (paddr_t)seg->size) != 0)
483 			panic("D-RAM check failed.");
484 #else
485 		_DPRINTF("\n");
486 #endif /* NARLY_MEMORY_PROBE */
487 	}
488 
489 	return (npages);
490 }
491 
492 static void
mem_cluster_load(void)493 mem_cluster_load(void)
494 {
495 	paddr_t start, end;
496 	psize_t size;
497 	int i;
498 
499 	/* Cluster 0 is always the kernel, which doesn't get loaded. */
500 	sh_dcache_wbinv_all();
501 	for (i = 1; i < mem_cluster_cnt; i++) {
502 		start = (paddr_t)mem_clusters[i].start;
503 		size = (psize_t)mem_clusters[i].size;
504 
505 		_DPRINTF("loading 0x%lx,0x%lx\n", start, size);
506 		memset((void *)SH3_PHYS_TO_P1SEG(start), 0, size);
507 		end = atop(start + size);
508 		start = atop(start);
509 		uvm_page_physload(start, end, start, end, VM_FREELIST_DEFAULT);
510 	}
511 	sh_dcache_wbinv_all();
512 }
513 
514 static void
__find_dram_shadow(paddr_t start,paddr_t end)515 __find_dram_shadow(paddr_t start, paddr_t end)
516 {
517 	vaddr_t page, startaddr, endaddr;
518 	int x;
519 
520 	_DPRINTF("search D-RAM from 0x%08lx for 0x%08lx\n", start, end);
521 	startaddr = SH3_PHYS_TO_P2SEG(start);
522 	endaddr = SH3_PHYS_TO_P2SEG(end);
523 
524 	page = startaddr;
525 
526 	x = random();
527 	*(volatile int *)(page + 0) = x;
528 	*(volatile int *)(page + 4) = ~x;
529 
530 	if (*(volatile int *)(page + 0) != x ||
531 	    *(volatile int *)(page + 4) != ~x)
532 		return;
533 
534 	for (page += PAGE_SIZE; page < endaddr; page += PAGE_SIZE) {
535 		if (*(volatile int *)(page + 0) == x &&
536 		    *(volatile int *)(page + 4) == ~x) {
537 			goto memend_found;
538 		}
539 	}
540 
541 	page -= PAGE_SIZE;
542 	*(volatile int *)(page + 0) = x;
543 	*(volatile int *)(page + 4) = ~x;
544 
545 	if (*(volatile int *)(page + 0) != x ||
546 	    *(volatile int *)(page + 4) != ~x)
547 		return; /* no memory in this bank */
548 
549  memend_found:
550 	KASSERT(mem_cluster_cnt < VM_PHYSSEG_MAX);
551 
552 	mem_clusters[mem_cluster_cnt].start = start;
553 	mem_clusters[mem_cluster_cnt].size = page - startaddr;
554 
555 	/* skip kernel area */
556 	if (mem_cluster_cnt == 1)
557 		mem_clusters[1].size -= mem_clusters[0].size;
558 
559 	mem_cluster_cnt++;
560 }
561 
562 #ifdef NARLY_MEMORY_PROBE
563 static int
__check_dram(paddr_t start,paddr_t end)564 __check_dram(paddr_t start, paddr_t end)
565 {
566 	uint8_t *page;
567 	int i, x;
568 
569 	_DPRINTF(" checking...");
570 	for (; start < end; start += PAGE_SIZE) {
571 		page = (uint8_t *)SH3_PHYS_TO_P2SEG (start);
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 		x = random();
579 		for (i = 0; i < PAGE_SIZE; i += 4)
580 			*(volatile int *)(page + i) = (x ^ i);
581 		for (i = 0; i < PAGE_SIZE; i += 4)
582 			if (*(volatile int *)(page + i) != (x ^ i))
583 				goto bad;
584 	}
585 	_DPRINTF("success.\n");
586 	return (0);
587  bad:
588 	_DPRINTF("failed.\n");
589 	return (1);
590 }
591 #endif /* NARLY_MEMORY_PROBE */
592 
593 void
intc_intr(int ssr,int spc,int ssp)594 intc_intr(int ssr, int spc, int ssp)
595 {
596 	struct intc_intrhand *ih;
597 	int evtcode;
598 	uint16_t r;
599 
600 	curcpu()->ci_data.cpu_nintr++;
601 
602 	evtcode = _reg_read_4(CPU_IS_SH3 ? SH7709_INTEVT2 : SH4_INTEVT);
603 
604 	ih = EVTCODE_IH(evtcode);
605 	KDASSERT(ih->ih_func);
606 	/*
607 	 * On entry, all interrrupts are disabled,
608 	 * and exception is enabled for P3 access. (kernel stack is P3,
609 	 * SH3 may or may not cause TLB miss when access stack.)
610 	 * Enable higher level interrupt here.
611 	 */
612 	r = _reg_read_2(HD6446X_NIRR);
613 
614 	splx(ih->ih_level);
615 
616 	if (evtcode == SH_INTEVT_TMU0_TUNI0) {
617 		struct clockframe cf;
618 		cf.spc = spc;
619 		cf.ssr = ssr;
620 		cf.ssp = ssp;
621 		(*ih->ih_func)(&cf);
622 		__dbg_heart_beat(HEART_BEAT_RED);
623 	} else if (evtcode ==
624 	    (CPU_IS_SH3 ? SH7709_INTEVT2_IRQ4 : SH_INTEVT_IRL11)) {
625 		struct hd6446x_intrhand *hh;
626 		int cause;
627 
628 		cause = r & hd6446x_ienable;
629 		if (cause == 0) {
630 			printf("masked HD6446x interrupt 0x%04x\n",
631 			       r & ~hd6446x_ienable);
632 			_reg_write_2(HD6446X_NIRR, 0x0000);
633 			return;
634 		}
635 		/* Enable higher level interrupt*/
636 		hh = &hd6446x_intrhand[ffs(cause) - 1];
637 		hd6446x_intr_resume(hh->hh_ipl);
638 		KDASSERT(hh->hh_func != NULL);
639 		(*hh->hh_func)(hh->hh_arg);
640 		__dbg_heart_beat(HEART_BEAT_GREEN);
641 	} else {
642 		(*ih->ih_func)(ih->ih_arg);
643 		__dbg_heart_beat(HEART_BEAT_BLUE);
644 	}
645 }
646 
647 
648 #ifdef MODULAR
649 /*
650  * Push any modules loaded by the boot loader.
651  */
652 void
module_init_md(void)653 module_init_md(void)
654 {
655 }
656 #endif /* MODULAR */
657