xref: /netbsd/sys/arch/arc/arc/machdep.c (revision bf9ec67e)
1 /*	$NetBSD: machdep.c,v 1.67 2002/03/17 04:41:57 tsutsui Exp $	*/
2 /*	$OpenBSD: machdep.c,v 1.36 1999/05/22 21:22:19 weingart Exp $	*/
3 
4 /*
5  * Copyright (c) 1988 University of Utah.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * the Systems Programming Group of the University of Utah Computer
11  * Science Department, The Mach Operating System project at
12  * Carnegie-Mellon University and Ralph Campbell.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *	This product includes software developed by the University of
25  *	California, Berkeley and its contributors.
26  * 4. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	from: @(#)machdep.c	8.3 (Berkeley) 1/12/94
43  */
44 
45 /* from: Utah Hdr: machdep.c 1.63 91/04/24 */
46 
47 #include "fs_mfs.h"
48 #include "opt_ddb.h"
49 #include "opt_md.h"
50 
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/signalvar.h>
54 #include <sys/kernel.h>
55 #include <sys/map.h>
56 #include <sys/proc.h>
57 #include <sys/buf.h>
58 #include <sys/reboot.h>
59 #include <sys/conf.h>
60 #include <sys/file.h>
61 #include <sys/malloc.h>
62 #include <sys/mbuf.h>
63 #include <sys/msgbuf.h>
64 #include <sys/ioctl.h>
65 #include <sys/time.h>
66 #include <sys/tty.h>
67 #include <sys/user.h>
68 #include <sys/exec.h>
69 #include <uvm/uvm_extern.h>
70 #include <sys/sysctl.h>
71 #include <sys/mount.h>
72 #include <sys/device.h>
73 #include <sys/syscallargs.h>
74 #include <sys/kcore.h>
75 #ifdef MFS
76 #include <ufs/mfs/mfs_extern.h>
77 #endif
78 
79 #include <ufs/mfs/mfs_extern.h>		/* mfs_initminiroot() */
80 
81 #include <machine/cpu.h>
82 #include <machine/reg.h>
83 #include <machine/pio.h>
84 #include <machine/bus.h>
85 #include <machine/trap.h>
86 #include <machine/autoconf.h>
87 #include <machine/platform.h>
88 #include <mips/pte.h>
89 #include <mips/locore.h>
90 #include <mips/cpuregs.h>
91 #include <mips/psl.h>
92 #include <mips/cache.h>
93 #ifdef DDB
94 #include <mips/db_machdep.h>
95 #include <ddb/db_extern.h>
96 #endif
97 
98 #include <dev/cons.h>
99 
100 #include <dev/ic/i8042reg.h>
101 #include <dev/isa/isareg.h>
102 
103 #include <arc/arc/arcbios.h>
104 #include <arc/arc/wired_map.h>
105 
106 #include "com.h"
107 #if NCOM > 0
108 #include <sys/termios.h>
109 #include <dev/ic/comreg.h>
110 #include <dev/ic/comvar.h>
111 
112 #ifndef COMCONSOLE
113 #define COMCONSOLE	0
114 #endif
115 
116 #ifndef CONADDR
117 #define CONADDR	0	/* use default address if CONADDR isn't configured */
118 #endif
119 
120 #ifndef CONSPEED
121 #define CONSPEED TTYDEF_SPEED
122 #endif
123 #ifndef CONMODE
124 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
125 #endif
126 #endif /* NCOM */
127 
128 /* the following is used externally (sysctl_hw) */
129 char	machine[] = MACHINE;		/* from <machine/param.h> */
130 char	machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
131 char	cpu_model[80];
132 
133 /* Our exported CPU info; we can have only one. */
134 struct cpu_info cpu_info_store;
135 
136 /* maps for VM objects */
137 struct vm_map *exec_map = NULL;
138 struct vm_map *mb_map = NULL;
139 struct vm_map *phys_map = NULL;
140 
141 int	maxmem;			/* max memory per process */
142 int	physmem;		/* max supported memory, changes to actual */
143 int	ncpu = 1;		/* At least one cpu in the system */
144 int	cpuspeed = 150;		/* approx CPU clock [MHz] */
145 vaddr_t kseg2iobufsize = 0;	/* to reserve PTEs for KSEG2 I/O space */
146 struct arc_bus_space arc_bus_io;/* Bus tag for bus.h macros */
147 struct arc_bus_space arc_bus_mem;/* Bus tag for bus.h macros */
148 
149 #if NCOM > 0
150 int	com_freq = COM_FREQ;	/* unusual clock frequency of dev/ic/com.c */
151 int	com_console = COMCONSOLE;
152 int	com_console_address = CONADDR;
153 int	com_console_speed = CONSPEED;
154 int	com_console_mode = CONMODE;
155 #else
156 #ifndef COMCONSOLE
157 #error COMCONSOLE is defined without com driver configured.
158 #endif
159 int	com_console = 0;
160 #endif /* NCOM */
161 
162 char **environment;		/* On some arches, pointer to environment */
163 
164 int mem_reserved[VM_PHYSSEG_MAX]; /* the cluster is reserved, i.e. not free */
165 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
166 int mem_cluster_cnt;
167 
168 /* initialize bss, etc. from kernel start, before main() is called. */
169 extern void mach_init __P((int, char **argv, char **));
170 
171 char *firmware_getenv __P((char *env));
172 void arc_sysreset __P((bus_addr_t, bus_size_t));
173 
174 /*
175  * safepri is a safe priority for sleep to set for a spin-wait
176  * during autoconfiguration or after a panic.
177  * Used as an argument to splx().
178  * XXX disables interrupt 5 to disable mips3 on-chip clock.
179  */
180 int	safepri = MIPS3_PSL_LOWIPL;
181 
182 struct splvec	splvec = {			/* XXX will go XXX */
183 	MIPS_INT_MASK_SPLHIGH, /* splbio */
184 	MIPS_INT_MASK_SPLHIGH, /* splnet */
185 	MIPS_INT_MASK_SPLHIGH, /* spltty */
186 	MIPS_INT_MASK_SPLHIGH, /* splvm */
187 	MIPS_INT_MASK_SPLHIGH, /* splclock */
188 	MIPS_INT_MASK_SPLHIGH, /* splstatclock */
189 };
190 
191 extern char kernel_text[], edata[], end[];
192 extern struct user *proc0paddr;
193 
194 /*
195  * Do all the stuff that locore normally does before calling main().
196  * Process arguments passed to us by the BIOS.
197  * Reset mapping and set up mapping to hardware and init "wired" reg.
198  * Return the first page address following the system.
199  */
200 void
201 mach_init(argc, argv, envv)
202 	int argc;
203 	char *argv[];
204 	char *envv[];	/* Not on all arches... */
205 {
206 	char *cp;
207 	int i;
208 	paddr_t kernstartpfn, kernendpfn, first, last;
209 	caddr_t kernend, v;
210 	vsize_t size;
211 
212 	/* clear the BSS segment in kernel code */
213 	kernend = (caddr_t)mips_round_page(end);
214 	bzero(edata, kernend - edata);
215 
216 	environment = &argv[1];
217 
218 	if (bios_ident()) { /* ARC BIOS present */
219 		bios_init_console();
220 		bios_save_info();
221 		physmem = bios_configure_memory(mem_reserved, mem_clusters,
222 		    &mem_cluster_cnt);
223 	}
224 
225 	/* Initialize the CPU type */
226 	ident_platform();
227 	if (platform == NULL) {
228 		/* This is probably the best we can do... */
229 		printf("kernel not configured for this system:\n");
230 		printf("ID [%s] Vendor [%8.8s] Product [%02x",
231 		    arc_id, arc_vendor_id, arc_product_id[0]);
232 		for (i = 1; i < sizeof(arc_product_id); i++)
233 			printf(":%02x", arc_product_id[i]);
234 		printf("]\n");
235 		printf("DisplayController [%s]\n", arc_displayc_id);
236 #if 1
237 		for (;;)
238 			;
239 #else
240 		cpu_reboot(RB_HALT | RB_NOSYNC, NULL);
241 #endif
242 	}
243 
244 	physmem = btoc(physmem);
245 
246 	/* compute bootdev for autoconfig setup */
247 	cp = firmware_getenv("OSLOADPARTITION");
248 	makebootdev(cp != NULL ? cp : argv[0]);
249 
250 	/*
251 	 * Look at arguments passed to us and compute boothowto.
252 	 * Default to SINGLE and ASKNAME if no args or
253 	 * SINGLE and DFLTROOT if this is a ramdisk kernel.
254 	 */
255 #ifdef MEMORY_DISK_IS_ROOT
256 	boothowto = RB_SINGLE;
257 #else
258 	boothowto = RB_SINGLE | RB_ASKNAME;
259 #endif /* MEMORY_DISK_IS_ROOT */
260 #ifdef KADB
261 	boothowto |= RB_KDB;
262 #endif
263 
264 	cp = firmware_getenv("OSLOADOPTIONS");
265 	if (cp) {
266 		while (*cp) {
267 			switch (*cp++) {
268 			case 'a': /* autoboot */
269 				boothowto &= ~RB_SINGLE;
270 				break;
271 
272 			case 'm': /* mini root present in memory */
273 				boothowto |= RB_MINIROOT;
274 				break;
275 
276 			case 'n': /* ask for names */
277 				boothowto |= RB_ASKNAME;
278 				break;
279 
280 			case 'N': /* don't ask for names */
281 				boothowto &= ~RB_ASKNAME;
282 				break;
283 
284 			case 's': /* use serial console */
285 				com_console = 1;
286 				break;
287 
288 			case 'q': /* boot quietly */
289 				boothowto |= AB_QUIET;
290 				break;
291 
292 			case 'v': /* boot verbosely */
293 				boothowto |= AB_VERBOSE;
294 				break;
295 			}
296 
297 		}
298 	}
299 
300 	/*
301 	 * Set the VM page size.
302 	 */
303 	uvm_setpagesize();
304 
305 	/* make sure that we don't call BIOS console from now on */
306 	cn_tab = NULL;
307 
308 	/*
309 	 * Copy exception-dispatch code down to exception vector.
310 	 * Initialize locore-function vector.
311 	 * Clear out the I and D caches.
312 	 *
313 	 * Now its time to abandon the BIOS and be self supplying.
314 	 * Start with cleaning out the TLB. Bye bye Microsoft....
315 	 *
316 	 * This may clobber PTEs needed by the BIOS.
317 	 */
318 	mips_vector_init();
319 
320 	/*
321 	 * Map critical I/O spaces (e.g. for console printf(9)) on KSEG2.
322 	 * We cannot call VM functions here, since uvm is not initialized,
323 	 * yet.
324 	 * Since printf(9) is called before uvm_init() in main(),
325 	 * we have to handcraft console I/O space anyway.
326 	 *
327 	 * XXX - reserve these KVA space after UVM initialization.
328 	 */
329 
330 	arc_init_wired_map();
331 
332 	(*platform->init)();
333 	cpuspeed = platform->clock;
334 	sprintf(cpu_model, "%s %s%s",
335 	    platform->vendor, platform->model, platform->variant);
336 
337 #ifdef MFS
338 	/*
339 	 * Check to see if a mini-root was loaded into memory. It resides
340 	 * at the start of the next page just after the end of BSS.
341 	 */
342 	if (boothowto & RB_MINIROOT)
343 		kernend += round_page(mfs_initminiroot(kernend));
344 #endif
345 
346 #ifdef DDB
347 #if 0 /* XXX */
348 	/* init symbols if present */
349 	if (esym)
350 		ddb_init(1000, &end, (int*)esym);
351 #endif
352 #endif
353 
354 	maxmem = physmem;
355 
356 	/* XXX: revisit here */
357 
358 	/*
359 	 * Load the rest of the pages into the VM system.
360 	 */
361 	kernstartpfn = atop(trunc_page(
362 	    MIPS_KSEG0_TO_PHYS((kernel_text) - UPAGES * PAGE_SIZE)));
363 	kernendpfn = atop(round_page(MIPS_KSEG0_TO_PHYS(kernend)));
364 #if 0
365 	/* give all free memory to VM */
366 	/* XXX - currently doesn't work, due to "panic: pmap_enter: pmap" */
367 	for (i = 0; i < mem_cluster_cnt; i++) {
368 		if (mem_reserved[i])
369 			continue;
370 		first = atop(round_page(mem_clusters[i].start));
371 		last = atop(trunc_page(mem_clusters[i].start +
372 		    mem_clusters[i].size));
373 		if (last <= kernstartpfn || kernendpfn <= first) {
374 			uvm_page_physload(first, last, first, last,
375 			    VM_FREELIST_DEFAULT);
376 		} else {
377 			if (first < kernstartpfn)
378 				uvm_page_physload(first, kernstartpfn,
379 				    first, kernstartpfn, VM_FREELIST_DEFAULT);
380 			if (kernendpfn < last)
381 				uvm_page_physload(kernendpfn, last,
382 				    kernendpfn, last, , VM_FREELIST_DEFAULT);
383 		}
384 	}
385 #elif 0 /* XXX */
386 	/* give all free memory above the kernel to VM (non-contig version) */
387 	for (i = 0; i < mem_cluster_cnt; i++) {
388 		if (mem_reserved[i])
389 			continue;
390 		first = atop(round_page(mem_clusters[i].start));
391 		last = atop(trunc_page(mem_clusters[i].start +
392 		    mem_clusters[i].size));
393 		if (kernendpfn < last) {
394 			if (first < kernendpfn)
395 				first = kernendpfn;
396 			uvm_page_physload(first, last, first, last,
397 			    VM_FREELIST_DEFAULT);
398 		}
399 	}
400 #else
401 	/* give all memory above the kernel to VM (contig version) */
402 #if 1
403 	mem_clusters[0].start = 0;
404 	mem_clusters[0].size  = ctob(physmem);
405 	mem_cluster_cnt = 1;
406 #endif
407 
408 	first = kernendpfn;
409 	last = physmem;
410 	uvm_page_physload(first, last, first, last, VM_FREELIST_DEFAULT);
411 #endif
412 
413 	/*
414 	 * Initialize error message buffer (at end of core).
415 	 */
416 	mips_init_msgbuf();
417 
418 	/*
419 	 * Compute the size of system data structures.  pmap_bootstrap()
420 	 * needs some of this information.
421 	 */
422 	size = (vsize_t)allocsys(NULL, NULL);
423 
424 	/*
425 	 * Initialize the virtual memory system.
426 	 */
427 	pmap_bootstrap();
428 
429 	/*
430 	 * Allocate space for proc0's USPACE.
431 	 */
432 	v = (caddr_t)uvm_pageboot_alloc(USPACE);
433 	proc0.p_addr = proc0paddr = (struct user *)v;
434 	proc0.p_md.md_regs = (struct frame *)(v + USPACE) - 1;
435 	curpcb = &proc0.p_addr->u_pcb;
436 	curpcb->pcb_context[11] = MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */
437 
438 	/*
439 	 * Allocate space for system data structures.  These data structures
440 	 * are allocated here instead of cpu_startup() because physical
441 	 * memory is directly addressable.  We don't have to map these into
442 	 * virtual address space.
443 	 */
444 	v = (caddr_t)uvm_pageboot_alloc(size);
445 	if ((allocsys(v, NULL) - v) != size)
446 		panic("mach_init: table size inconsistency");
447 }
448 
449 void
450 mips_machdep_cache_config(void)
451 {
452 	mips_sdcache_size = arc_cpu_l2cache_size;
453 }
454 
455 /*
456  * Return a pointer to the given environment variable.
457  */
458 char *
459 firmware_getenv(envname)
460 	char *envname;
461 {
462 	char **env;
463 	int l;
464 
465 	l = strlen(envname);
466 
467 	for (env = environment; env[0]; env++) {
468 		if (strncasecmp(envname, env[0], l) == 0 && env[0][l] == '=') {
469 			return (&env[0][l + 1]);
470 		}
471 	}
472 	return (NULL);
473 }
474 
475 /*
476  * Console initialization: called early on from main,
477  * before vm init or startup.  Do enough configuration
478  * to choose and initialize a console.
479  */
480 void
481 consinit()
482 {
483 	static int initted;
484 
485 	if (initted)
486 		return;
487 	initted = 1;
488 
489 	(*platform->cons_init)();
490 }
491 
492 /*
493  * cpu_startup: allocate memory for variable-sized tables,
494  * initialize cpu, and do autoconfiguration.
495  */
496 void
497 cpu_startup()
498 {
499 	unsigned i;
500 	int base, residual;
501 	vaddr_t minaddr, maxaddr;
502 	vsize_t size;
503 	char pbuf[9];
504 #ifdef DEBUG
505 	extern int pmapdebug;
506 	int opmapdebug = pmapdebug;
507 
508 	pmapdebug = 0;		/* Shut up pmap debug during bootstrap */
509 #endif
510 
511 	/*
512 	 * Good {morning,afternoon,evening,night}.
513 	 */
514 	printf(version);
515 	printf("%s\n", cpu_model);
516 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
517 	printf("total memory = %s\n", pbuf);
518 
519 	/*
520 	 * Allocate virtual address space for file I/O buffers.
521 	 * Note they are different than the array of headers, 'buf',
522 	 * and usually occupy more virtual memory than physical.
523 	 */
524 	size = MAXBSIZE * nbuf;
525 	if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(size),
526 		    NULL, UVM_UNKNOWN_OFFSET, 0,
527 		    UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
528 				UVM_ADV_NORMAL, 0)) != 0)
529 		panic("cpu_startup: cannot allocate VM for buffers");
530 
531 	minaddr = (vaddr_t)buffers;
532 	if ((bufpages / nbuf) >= btoc(MAXBSIZE)) {
533 		bufpages = btoc(MAXBSIZE) * nbuf; /* do not overallocate RAM */
534 	}
535 	base = bufpages / nbuf;
536 	residual = bufpages % nbuf;
537 
538 	/* now allocate RAM for buffers */
539 	for (i = 0; i < nbuf; i++) {
540 		vsize_t curbufsize;
541 		vaddr_t curbuf;
542 		struct vm_page *pg;
543 
544 		/*
545 		 * Each buffer has MAXBSIZE bytes of VM space allocated.  Of
546 		 * that MAXBSIZE space, we allocate and map (base+1) pages
547 		 * for the first "residual" buffers, and then we allocate
548 		 * "base" pages for the rest.
549 		 */
550 		curbuf = (vaddr_t)buffers + (i * MAXBSIZE);
551 		curbufsize = NBPG * ((i < residual) ? (base+1) : base);
552 
553 		while (curbufsize) {
554 			pg = uvm_pagealloc(NULL, 0, NULL, 0);
555 			if (pg == NULL)
556 				panic("cpu_startup: not enough memory for "
557 				    "buffer cache");
558 			pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
559 				       VM_PROT_READ|VM_PROT_WRITE);
560 			curbuf += PAGE_SIZE;
561 			curbufsize -= PAGE_SIZE;
562 		}
563 	}
564 	pmap_update(pmap_kernel());
565 
566 	/*
567 	 * Allocate a submap for exec arguments.  This map effectively
568 	 * limits the number of processes exec'ing at any time.
569 	 */
570 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
571 				   16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
572 
573 	/*
574 	 * Allocate a submap for physio
575 	 */
576 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
577 				   VM_PHYS_SIZE, 0, FALSE, NULL);
578 
579 	/*
580 	 * No need to allocate an mbuf cluster submap.  Mbuf clusters
581 	 * are allocated via the pool allocator, and we use KSEG to
582 	 * map those pages.
583 	 */
584 
585 #ifdef DEBUG
586 	pmapdebug = opmapdebug;
587 #endif
588 	format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
589 	printf("avail memory = %s\n", pbuf);
590 	format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG);
591 	printf("using %d buffers containing %s of memory\n", nbuf, pbuf);
592 
593 	/*
594 	 * Set up buffers, so they can be used to read disk labels.
595 	 */
596 	bufinit();
597 }
598 
599 /*
600  * machine dependent system variables.
601  */
602 int
603 cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
604 	int *name;
605 	u_int namelen;
606 	void *oldp;
607 	size_t *oldlenp;
608 	void *newp;
609 	size_t newlen;
610 	struct proc *p;
611 {
612 	dev_t consdev;
613 
614 	/* all sysctl names at this level are terminal */
615 	if (namelen != 1)
616 		return (ENOTDIR);		/* overloaded */
617 
618 	switch (name[0]) {
619 	case CPU_CONSDEV:
620 		if (cn_tab != NULL)
621 			consdev = cn_tab->cn_dev;
622 		else
623 			consdev = NODEV;
624 		return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
625 		    sizeof consdev));
626 	default:
627 		return (EOPNOTSUPP);
628 	}
629 	/* NOTREACHED */
630 }
631 
632 int	waittime = -1;
633 struct user dumppcb;	/* Actually, struct pcb would do. */
634 
635 void
636 cpu_reboot(howto, bootstr)
637 	register int howto;
638 	char *bootstr;
639 {
640 
641 	/* take a snap shot before clobbering any registers */
642 	if (curproc)
643 		savectx((struct user *)curpcb);
644 
645 #ifdef DEBUG
646 	if (panicstr)
647 		stacktrace();
648 #endif
649 
650 	boothowto = howto;
651 	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
652 		/* fill curproc with live object */
653 		if (curproc == NULL)
654 			curproc = &proc0;
655 		/*
656 		 * Synchronize the disks....
657 		 */
658 		waittime = 0;
659 		vfs_shutdown();
660 
661 		/*
662 		 * If we've been adjusting the clock, the todr
663 		 * will be out of synch; adjust it now.
664 		 */
665 		resettodr();
666 	}
667 	(void) splhigh();		/* extreme priority */
668 
669 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
670 		dumpsys();
671 
672 	doshutdownhooks();
673 
674 	if (howto & RB_HALT) {
675 		printf("\n");
676 		printf("The operating system has halted.\n");
677 		printf("Please press any key to reboot.\n\n");
678 		cnpollc(1);	/* for proper keyboard command handling */
679 		cngetc();
680 		cnpollc(0);
681 	}
682 
683 	printf("rebooting...\n");
684 	delay(1000000);
685 
686 	(*platform->reset)();
687 
688 	__asm__(" li $2, 0xbfc00000; jr $2; nop\n");
689 	for (;;)
690 		; /* Forever */
691 	/* NOTREACHED */
692 }
693 
694 /*
695  * Pass system reset command to keyboard controller (8042).
696  */
697 void
698 arc_sysreset(addr, cmd_offset)
699 	bus_addr_t addr;
700 	bus_size_t cmd_offset;
701 {
702 	volatile u_int8_t *kbdata = (u_int8_t *)addr + KBDATAP;
703 	volatile u_int8_t *kbcmd = (u_int8_t *)addr + cmd_offset;
704 
705 #define KBC_ARC_SYSRESET 0xd1
706 
707 	delay(1000);
708 	*kbcmd = KBC_ARC_SYSRESET;
709 	delay(1000);
710 	*kbdata = 0;
711 }
712 
713 /*
714  * Return the best possible estimate of the time in the timeval
715  * to which tvp points.  Unfortunately, we can't read the hardware registers.
716  * We guarantee that the time will be greater than the value obtained by a
717  * previous call.
718  */
719 void
720 microtime(tvp)
721 	register struct timeval *tvp;
722 {
723 	int s = splclock();
724 	static struct timeval lasttime;
725 
726 	*tvp = time;
727 #ifdef notdef
728 	tvp->tv_usec += clkread();
729 	while (tvp->tv_usec >= 1000000) {
730 		tvp->tv_sec++;
731 		tvp->tv_usec -= 1000000;
732 	}
733 #endif
734 	if (tvp->tv_sec == lasttime.tv_sec &&
735 	    tvp->tv_usec <= lasttime.tv_usec &&
736 	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
737 		tvp->tv_sec++;
738 		tvp->tv_usec -= 1000000;
739 	}
740 	lasttime = *tvp;
741 	splx(s);
742 }
743