1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department, The Mach Operating System project at
9  * Carnegie-Mellon University, Ralph Campbell, Sony Corp. and Kazumasa
10  * Utashiro of Software Research Associates, Inc.
11  *
12  * %sccs.include.redist.c%
13  *
14  *	@(#)machdep.c	7.1 (Berkeley) 06/04/92
15  */
16 
17 /* from: Utah $Hdr: machdep.c 1.63 91/04/24$ */
18 
19 #include "param.h"
20 #include "systm.h"
21 #include "signalvar.h"
22 #include "kernel.h"
23 #include "map.h"
24 #include "proc.h"
25 #include "buf.h"
26 #include "reboot.h"
27 #include "conf.h"
28 #include "file.h"
29 #include "clist.h"
30 #include "callout.h"
31 #include "malloc.h"
32 #include "mbuf.h"
33 #include "msgbuf.h"
34 #include "user.h"
35 #ifdef SYSVSHM
36 #include "shm.h"
37 #endif
38 
39 #include "vm/vm.h"
40 #include "vm/vm_kern.h"
41 #include "vm/vm_page.h"
42 
43 #include "../include/cpu.h"
44 #include "../include/reg.h"
45 #include "../include/psl.h"
46 #include "../include/pte.h"
47 
48 #include "../include/adrsmap.h"
49 
50 vm_map_t buffer_map;
51 
52 /*
53  * Declare these as initialized data so we can patch them.
54  */
55 int	nswbuf = 0;
56 #ifdef	NBUF
57 int	nbuf = NBUF;
58 #else
59 int	nbuf = 0;
60 #endif
61 #ifdef	BUFPAGES
62 int	bufpages = BUFPAGES;
63 #else
64 int	bufpages = 0;
65 #endif
66 int	msgbufmapped;		/* set when safe to use msgbuf */
67 int	maxmem;			/* max memory per process */
68 int	physmem;		/* max supported memory, changes to actual */
69 /*
70  * safepri is a safe priority for sleep to set for a spin-wait
71  * during autoconfiguration or after a panic.
72  */
73 int	safepri = PSL_LOWIPL;
74 
75 struct	user *proc0paddr;
76 struct	proc nullproc;		/* for use by swtch_exit() */
77 
78 /*
79  * Do all the stuff that locore normally does before calling main().
80  * Process arguments passed to us by the prom monitor.
81  * Return the first page address following the system.
82  */
83 mach_init(x_boothowto, x_unkown, x_bootdev, x_maxmem)
84 	int x_boothowto;
85 	int x_unkown;
86 	int x_bootdev;
87 	int x_maxmem;
88 {
89 	register char *cp;
90 	register int i;
91 	register unsigned firstaddr;
92 	register caddr_t v;
93 	caddr_t start;
94 	extern u_long bootdev;
95 	extern char edata[], end[];
96 	extern char MachUTLBMiss[], MachUTLBMissEnd[];
97 	extern char MachException[], MachExceptionEnd[];
98 #ifdef ATTR
99 	extern char *pmap_attributes;
100 #endif
101 
102 	/* clear the BSS segment */
103 	v = (caddr_t)pmax_round_page(end);
104 	bzero(edata, v - edata);
105 
106 	boothowto = x_boothowto;
107 	bootdev = x_bootdev;
108 	maxmem = physmem = pmax_btop(x_maxmem);
109 
110 	/*
111 	 * Look at arguments passed to us and compute boothowto.
112 	 */
113 #ifdef GENERIC
114 	boothowto |= RB_SINGLE | RB_ASKNAME;
115 #endif
116 #ifdef KADB
117 	boothowto |= RB_KDB;
118 #endif
119 
120 #ifdef MFS
121 	/*
122 	 * Check to see if a mini-root was loaded into memory. It resides
123 	 * at the start of the next page just after the end of BSS.
124 	 */
125 	if (boothowto & RB_MINIROOT)
126 		v += mfs_initminiroot(v);
127 #endif
128 
129 	/*
130 	 * Init mapping for u page(s) for proc[0], pm_tlbpid 1.
131 	 */
132 	start = v;
133 	curproc->p_addr = proc0paddr = (struct user *)v;
134 	curproc->p_md.md_regs = proc0paddr->u_pcb.pcb_regs;
135 	firstaddr = MACH_CACHED_TO_PHYS(v);
136 	for (i = 0; i < UPAGES; i++) {
137 		MachTLBWriteIndexed(i,
138 			(UADDR + (i << PGSHIFT)) | (1 << VMMACH_TLB_PID_SHIFT),
139 			curproc->p_md.md_upte[i] = firstaddr | PG_V | PG_M);
140 		firstaddr += NBPG;
141 	}
142 	v += UPAGES * NBPG;
143 	MachSetPID(1);
144 
145 	/*
146 	 * init nullproc for swtch_exit().
147 	 * init mapping for u page(s), pm_tlbpid 0
148 	 * This could be used for an idle process.
149 	 */
150 	nullproc.p_addr = (struct user *)v;
151 	nullproc.p_md.md_regs = ((struct user *)v)->u_pcb.pcb_regs;
152 	for (i = 0; i < UPAGES; i++) {
153 		nullproc.p_md.md_upte[i] = firstaddr | PG_V | PG_M;
154 		firstaddr += NBPG;
155 	}
156 	v += UPAGES * NBPG;
157 
158 	/* clear pages for u areas */
159 	bzero(start, v - start);
160 
161 	/*
162 	 * Copy down exception vector code.
163 	 */
164 	if (MachUTLBMissEnd - MachUTLBMiss > 0x80)
165 		panic("startup: UTLB code too large");
166 	bcopy(MachUTLBMiss, (char *)MACH_UTLB_MISS_EXC_VEC,
167 		MachUTLBMissEnd - MachUTLBMiss);
168 	bcopy(MachException, (char *)MACH_GEN_EXC_VEC,
169 		MachExceptionEnd - MachException);
170 
171 	/*
172 	 * Clear out the I and D caches.
173 	 */
174 	MachConfigCache();
175 	MachFlushCache();
176 
177 	/*
178 	 * Initialize error message buffer (at end of core).
179 	 */
180 	maxmem -= btoc(sizeof (struct msgbuf));
181 	msgbufp = (struct msgbuf *)(MACH_PHYS_TO_CACHED(maxmem << PGSHIFT));
182 	msgbufmapped = 1;
183 
184 	/*
185 	 * Allocate space for system data structures.
186 	 * The first available kernel virtual address is in "v".
187 	 * As pages of kernel virtual memory are allocated, "v" is incremented.
188 	 *
189 	 * These data structures are allocated here instead of cpu_startup()
190 	 * because physical memory is directly addressable. We don't have
191 	 * to map these into virtual address space.
192 	 */
193 	start = v;
194 
195 #define	valloc(name, type, num) \
196 	    (name) = (type *)v; v = (caddr_t)((name)+(num))
197 #define	valloclim(name, type, num, lim) \
198 	    (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
199 	valloc(cfree, struct cblock, nclist);
200 	valloc(callout, struct callout, ncallout);
201 	valloc(swapmap, struct map, nswapmap = maxproc * 2);
202 #ifdef SYSVSHM
203 	valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
204 #endif
205 #ifdef ATTR
206 	/* this is allocated here just to save a few bytes */
207 	valloc(pmap_attributes, char, physmem);
208 #endif
209 
210 	/*
211 	 * Determine how many buffers to allocate.
212 	 * We allocate more buffer space than the BSD standard of
213 	 * using 10% of memory for the first 2 Meg, 5% of remaining.
214 	 * We just allocate a flat 10%.  Insure a minimum of 16 buffers.
215 	 * We allocate 1/2 as many swap buffer headers as file i/o buffers.
216 	 */
217 	if (bufpages == 0)
218 		bufpages = physmem / 10 / CLSIZE;
219 	if (nbuf == 0) {
220 		nbuf = bufpages;
221 		if (nbuf < 16)
222 			nbuf = 16;
223 	}
224 	if (nswbuf == 0) {
225 		nswbuf = (nbuf / 2) &~ 1;	/* force even */
226 		if (nswbuf > 256)
227 			nswbuf = 256;		/* sanity */
228 	}
229 	valloc(swbuf, struct buf, nswbuf);
230 	valloc(buf, struct buf, nbuf);
231 
232 	/*
233 	 * Clear allocated memory.
234 	 */
235 	v = (caddr_t)pmax_round_page(v);
236 	bzero(start, v - start);
237 
238 	/*
239 	 * Initialize the virtual memory system.
240 	 */
241 	pmap_bootstrap((vm_offset_t)MACH_CACHED_TO_PHYS(v));
242 }
243 
244 /*
245  * Console initialization: called early on from main,
246  * before vm init or startup.  Do enough configuration
247  * to choose and initialize a console.
248  * XXX need something better here.
249  */
250 #define	SCC_CONSOLE	0
251 #define	SW_CONSOLE	0x07
252 #define	SW_NWB512	0x04
253 #define	SW_NWB225	0x01
254 #define	SW_FBPOP	0x02
255 #define	SW_FBPOP1	0x06
256 #define	SW_FBPOP2	0x03
257 #define	SW_AUTOSEL	0x07
258 consinit()
259 {
260 	extern dev_t consdev;
261 	extern struct tty *constty, *cn_tty, *rs_tty;
262 	int dipsw = (int)*(volatile u_char *)DIP_SWITCH;
263 
264 #include "bm.h"
265 #if NBM > 0
266 #ifdef news3200
267 	fbbm_probe(dipsw|2);
268 #else
269 	fbbm_probe(dipsw);
270 #endif
271 	vt100_open();
272 	setup_fnt();
273 	setup_fnt24();
274 #endif
275 
276 	switch (dipsw & SW_CONSOLE) {
277 	    case 0:
278 		scc_open(SCC_CONSOLE);
279 		consdev = makedev(1, 0);
280 		constty = rs_tty;
281 		break;
282 
283 	    default:
284 		consdev = makedev(22, 0);
285 		constty = cn_tty;
286 		break;
287 	}
288 	return(0);
289 }
290 
291 /*
292  * cpu_startup: allocate memory for variable-sized tables,
293  * initialize cpu, and do autoconfiguration.
294  */
295 cpu_startup()
296 {
297 	register unsigned i;
298 	register caddr_t v;
299 	int base, residual;
300 	extern long Usrptsize;
301 	extern struct map *useriomap;
302 #ifdef DEBUG
303 	extern int pmapdebug;
304 	int opmapdebug = pmapdebug;
305 #endif
306 	vm_offset_t minaddr, maxaddr;
307 	vm_size_t size;
308 
309 #ifdef DEBUG
310 	pmapdebug = 0;
311 #endif
312 
313 	/*
314 	 * Good {morning,afternoon,evening,night}.
315 	 */
316 	printf(version);
317 	printf("real mem = %d\n", ctob(physmem));
318 
319 	/*
320 	 * Allocate virtual address space for file I/O buffers.
321 	 * Note they are different than the array of headers, 'buf',
322 	 * and usually occupy more virtual memory than physical.
323 	 */
324 	size = MAXBSIZE * nbuf;
325 	buffer_map = kmem_suballoc(kernel_map, (vm_offset_t)&buffers,
326 				   &maxaddr, size, FALSE);
327 	minaddr = (vm_offset_t)buffers;
328 	if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0,
329 			&minaddr, size, FALSE) != KERN_SUCCESS)
330 		panic("startup: cannot allocate buffers");
331 	base = bufpages / nbuf;
332 	residual = bufpages % nbuf;
333 	for (i = 0; i < nbuf; i++) {
334 		vm_size_t curbufsize;
335 		vm_offset_t curbuf;
336 
337 		/*
338 		 * First <residual> buffers get (base+1) physical pages
339 		 * allocated for them.  The rest get (base) physical pages.
340 		 *
341 		 * The rest of each buffer occupies virtual space,
342 		 * but has no physical memory allocated for it.
343 		 */
344 		curbuf = (vm_offset_t)buffers + i * MAXBSIZE;
345 		curbufsize = CLBYTES * (i < residual ? base+1 : base);
346 		vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE);
347 		vm_map_simplify(buffer_map, curbuf);
348 	}
349 	/*
350 	 * Allocate a submap for exec arguments.  This map effectively
351 	 * limits the number of processes exec'ing at any time.
352 	 */
353 	exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
354 				 16*NCARGS, TRUE);
355 	/*
356 	 * Allocate a submap for physio
357 	 */
358 	phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
359 				 VM_PHYS_SIZE, TRUE);
360 
361 	/*
362 	 * Finally, allocate mbuf pool.  Since mclrefcnt is an off-size
363 	 * we use the more space efficient malloc in place of kmem_alloc.
364 	 */
365 	mclrefcnt = malloc(NMBCLUSTERS + CLBYTES/MCLBYTES, M_MBUF, M_NOWAIT);
366 	bzero(mclrefcnt, NMBCLUSTERS + CLBYTES/MCLBYTES);
367 	mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
368 			       VM_MBUF_SIZE, FALSE);
369 	/*
370 	 * Initialize callouts
371 	 */
372 	callfree = callout;
373 	for (i = 1; i < ncallout; i++)
374 		callout[i-1].c_next = &callout[i];
375 
376 #ifdef DEBUG
377 	pmapdebug = opmapdebug;
378 #endif
379 	printf("avail mem = %d\n", ptoa(cnt.v_free_count));
380 	printf("using %d buffers containing %d bytes of memory\n",
381 		nbuf, bufpages * CLBYTES);
382 	/*
383 	 * Set up CPU-specific registers, cache, etc.
384 	 */
385 	initcpu();
386 
387 	/*
388 	 * Set up buffers, so they can be used to read disk labels.
389 	 */
390 	bufinit();
391 
392 	/*
393 	 * Configure the system.
394 	 */
395 	configure();
396 }
397 
398 /*
399  * Set registers on exec.
400  * Clear all registers except sp, pc.
401  */
402 setregs(p, entry, retval)
403 	register struct proc *p;
404 	u_long entry;
405 	int retval[2];
406 {
407 	int sp = p->p_md.md_regs[SP];
408 	extern struct proc *machFPCurProcPtr;
409 
410 	bzero((caddr_t)p->p_md.md_regs, (FSR + 1) * sizeof(int));
411 	p->p_md.md_regs[SP] = sp;
412 	p->p_md.md_regs[PC] = entry;
413 	p->p_md.md_regs[PS] = PSL_USERSET;
414 	p->p_md.md_flags & ~MDP_FPUSED;
415 	if (machFPCurProcPtr == p)
416 		machFPCurProcPtr = (struct proc *)0;
417 }
418 
419 /*
420  * WARNING: code in locore.s assumes the layout shown for sf_signum
421  * thru sf_handler so... don't screw with them!
422  */
423 struct sigframe {
424 	int	sf_signum;		/* signo for handler */
425 	int	sf_code;		/* additional info for handler */
426 	struct	sigcontext *sf_scp;	/* context ptr for handler */
427 	sig_t	sf_handler;		/* handler addr for u_sigc */
428 };
429 
430 #ifdef DEBUG
431 int sigdebug = 0;
432 int sigpid = 0;
433 #define SDB_FOLLOW	0x01
434 #define SDB_KSTACK	0x02
435 #define SDB_FPSTATE	0x04
436 #endif
437 
438 /*
439  * Send an interrupt to process.
440  */
441 void
442 sendsig(catcher, sig, mask, code)
443 	sig_t catcher;
444 	int sig, mask;
445 	unsigned code;
446 {
447 	register struct proc *p = curproc;
448 	register struct sigframe *fp;
449 	register struct sigacts *ps = p->p_sigacts;
450 	register struct sigcontext *scp;
451 	register int *regs;
452 	int oonstack, fsize;
453 	struct sigcontext ksc;
454 
455 	regs = p->p_md.md_regs;
456 	oonstack = ps->ps_onstack;
457 	/*
458 	 * Allocate and validate space for the signal handler
459 	 * context. Note that if the stack is in data space, the
460 	 * call to grow() is a nop, and the copyout()
461 	 * will fail if the process has not already allocated
462 	 * the space with a `brk'.
463 	 */
464 	if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
465 		scp = (struct sigcontext *)ps->ps_sigsp - 1;
466 		ps->ps_onstack = 1;
467 	} else
468 		scp = (struct sigcontext *)regs[SP] - 1;
469 	fp = (struct sigframe *)scp - 1;
470 	if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize))
471 		(void)grow(p, (unsigned)fp);
472 	/*
473 	 * Build the signal context to be used by sigreturn.
474 	 */
475 	ksc.sc_onstack = oonstack;
476 	ksc.sc_mask = mask;
477 	ksc.sc_pc = regs[PC];
478 	ksc.sc_regs[ZERO] = 0xACEDBADE;		/* magic number */
479 	bcopy((caddr_t)&regs[1], (caddr_t)&ksc.sc_regs[1],
480 		sizeof(ksc.sc_regs) - sizeof(int));
481 	ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED;
482 	if (ksc.sc_fpused) {
483 		extern struct proc *machFPCurProcPtr;
484 
485 		/* if FPU has current state, save it first */
486 		if (p == machFPCurProcPtr)
487 			MachSaveCurFPState(p);
488 		bcopy((caddr_t)&p->p_md.md_regs[F0], (caddr_t)ksc.sc_fpregs,
489 			sizeof(ksc.sc_fpregs));
490 	}
491 	if (copyout((caddr_t)&ksc, (caddr_t)scp, sizeof(ksc))) {
492 		/*
493 		 * Process has trashed its stack; give it an illegal
494 		 * instruction to halt it in its tracks.
495 		 */
496 		SIGACTION(p, SIGILL) = SIG_DFL;
497 		sig = sigmask(SIGILL);
498 		p->p_sigignore &= ~sig;
499 		p->p_sigcatch &= ~sig;
500 		p->p_sigmask &= ~sig;
501 		psignal(p, SIGILL);
502 		return;
503 	}
504 	/*
505 	 * Build the argument list for the signal handler.
506 	 */
507 	regs[A0] = sig;
508 	regs[A1] = code;
509 	regs[A2] = (int)scp;
510 	regs[A3] = (int)catcher;
511 
512 	regs[PC] = (int)catcher;
513 	regs[SP] = (int)fp;
514 	regs[RA] = KERNBASE;	/* this causes a trap which we interpret as
515 				 * meaning "do a sigreturn". */
516 #ifdef DEBUG
517 	if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
518 		printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n",
519 		       p->p_pid, sig, &oonstack, fp, fp->sf_scp);
520 #endif
521 }
522 
523 /*
524  * System call to cleanup state after a signal
525  * has been taken.  Reset signal mask and
526  * stack state from context left by sendsig (above).
527  * Return to previous pc and psl as specified by
528  * context left by sendsig. Check carefully to
529  * make sure that the user has not modified the
530  * psl to gain improper priviledges or to cause
531  * a machine fault.
532  */
533 /* ARGSUSED */
534 sigreturn(p, uap, retval)
535 	struct proc *p;
536 	struct args {
537 		struct sigcontext *sigcntxp;
538 	} *uap;
539 	int *retval;
540 {
541 	register struct sigcontext *scp;
542 	register int *regs;
543 	struct sigcontext ksc;
544 	int error;
545 
546 	register struct frame *frame;
547 	register int rf;
548 	struct sigcontext tsigc;
549 	int flags;
550 
551 	scp = uap->sigcntxp;
552 #ifdef DEBUG
553 	if (sigdebug & SDB_FOLLOW)
554 		printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
555 #endif
556 	regs = p->p_md.md_regs;
557 	/*
558 	 * Test and fetch the context structure.
559 	 * We grab it all at once for speed.
560 	 */
561 	error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(ksc));
562 	if (error != 0 || ksc.sc_regs[ZERO] != 0xACEDBADE ||
563 	    (unsigned)ksc.sc_regs[SP] < (unsigned)regs[SP]) {
564 #ifdef DEBUG
565 		if (!(sigdebug & SDB_FOLLOW))
566 			printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
567 		printf("  old sp %x ra %x pc %x\n",
568 			regs[SP], regs[RA], regs[PC]);
569 		printf("  new sp %x ra %x pc %x err %d z %x\n",
570 			ksc.sc_regs[SP], ksc.sc_regs[RA], ksc.sc_regs[PC],
571 			error, ksc.sc_regs[ZERO]);
572 #endif
573 		if (regs[PC] == KERNBASE) {
574 			int sig;
575 
576 			/*
577 			 * Process has trashed its stack; give it an illegal
578 			 * instruction to halt it in its tracks.
579 			 */
580 			SIGACTION(p, SIGILL) = SIG_DFL;
581 			sig = sigmask(SIGILL);
582 			p->p_sigignore &= ~sig;
583 			p->p_sigcatch &= ~sig;
584 			p->p_sigmask &= ~sig;
585 			psignal(p, SIGILL);
586 		}
587 		return (EINVAL);
588 	}
589 	/*
590 	 * Restore the user supplied information
591 	 */
592 	p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
593 	p->p_sigmask = scp->sc_mask &~ sigcantmask;
594 	regs[PC] = ksc.sc_pc;
595 	bcopy((caddr_t)&ksc.sc_regs[1], (caddr_t)&regs[1],
596 		sizeof(ksc.sc_regs) - sizeof(int));
597 	ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED;
598 	if (ksc.sc_fpused)
599 		bcopy((caddr_t)ksc.sc_fpregs, (caddr_t)&p->p_md.md_regs[F0],
600 			sizeof(ksc.sc_fpregs));
601 	return (EJUSTRETURN);
602 }
603 
604 int	waittime = -1;
605 
606 boot(howto)
607 	register int howto;
608 {
609 
610 	/* take a snap shot before clobbering any registers */
611 	if (curproc)
612 		savectx(curproc->p_addr, 0);
613 
614 	howto |= RB_HALT; /* XXX */
615 	boothowto = howto;
616 	if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
617 		register struct buf *bp;
618 		int iter, nbusy;
619 
620 		waittime = 0;
621 		(void) spl0();
622 		printf("syncing disks... ");
623 		/*
624 		 * Release vnodes held by texts before sync.
625 		 */
626 		if (panicstr == 0)
627 			vnode_pager_umount(NULL);
628 #ifdef notyet
629 #include "fd.h"
630 #if NFD > 0
631 		fdshutdown();
632 #endif
633 #endif
634 		sync(&proc0, (void *)NULL, (int *)NULL);
635 
636 		for (iter = 0; iter < 20; iter++) {
637 			nbusy = 0;
638 			for (bp = &buf[nbuf]; --bp >= buf; )
639 				if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
640 					nbusy++;
641 			if (nbusy == 0)
642 				break;
643 			printf("%d ", nbusy);
644 			DELAY(40000 * iter);
645 		}
646 		if (nbusy)
647 			printf("giving up\n");
648 		else
649 			printf("done\n");
650 		/*
651 		 * If we've been adjusting the clock, the todr
652 		 * will be out of synch; adjust it now.
653 		 */
654 		resettodr();
655 	}
656 	(void) splhigh();		/* extreme priority */
657 	if (howto & RB_HALT) {
658 		halt(howto);
659 		/*NOTREACHED*/
660 	} else {
661 		if (howto & RB_DUMP)
662 			dumpsys();
663 		halt(howto);
664 		/*NOTREACHED*/
665 	}
666 	/*NOTREACHED*/
667 }
668 
669 halt(howto)
670 	int howto;
671 {
672 	if (*(volatile u_char *)DIP_SWITCH & 0x20)
673 		howto |= RB_HALT;
674 	to_monitor(howto);
675 	/*NOTREACHED*/
676 }
677 
678 int	dumpmag = 0x8fca0101;	/* magic number for savecore */
679 int	dumpsize = 0;		/* also for savecore */
680 long	dumplo = 0;
681 
682 dumpconf()
683 {
684 	int nblks;
685 
686 	dumpsize = physmem;
687 	if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) {
688 		nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev);
689 		if (dumpsize > btoc(dbtob(nblks - dumplo)))
690 			dumpsize = btoc(dbtob(nblks - dumplo));
691 		else if (dumplo == 0)
692 			dumplo = nblks - btodb(ctob(physmem));
693 	}
694 	/*
695 	 * Don't dump on the first CLBYTES (why CLBYTES?)
696 	 * in case the dump device includes a disk label.
697 	 */
698 	if (dumplo < btodb(CLBYTES))
699 		dumplo = btodb(CLBYTES);
700 }
701 
702 /*
703  * Doadump comes here after turning off memory management and
704  * getting on the dump stack, either when called above, or by
705  * the auto-restart code.
706  */
707 dumpsys()
708 {
709 	int error;
710 
711 	msgbufmapped = 0;
712 	if (dumpdev == NODEV)
713 		return;
714 	/*
715 	 * For dumps during autoconfiguration,
716 	 * if dump device has already configured...
717 	 */
718 	if (dumpsize == 0)
719 		dumpconf();
720 	if (dumplo < 0)
721 		return;
722 	printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
723 	printf("dump ");
724 	switch (error = (*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
725 
726 	case ENXIO:
727 		printf("device bad\n");
728 		break;
729 
730 	case EFAULT:
731 		printf("device not ready\n");
732 		break;
733 
734 	case EINVAL:
735 		printf("area improper\n");
736 		break;
737 
738 	case EIO:
739 		printf("i/o error\n");
740 		break;
741 
742 	default:
743 		printf("error %d\n", error);
744 		break;
745 
746 	case 0:
747 		printf("succeeded\n");
748 	}
749 }
750 
751 /*
752  * Return the best possible estimate of the time in the timeval
753  * to which tvp points.  Unfortunately, we can't read the hardware registers.
754  * We guarantee that the time will be greater than the value obtained by a
755  * previous call.
756  */
757 microtime(tvp)
758 	register struct timeval *tvp;
759 {
760 	int s = splclock();
761 	static struct timeval lasttime;
762 
763 	*tvp = time;
764 #ifdef notdef
765 	tvp->tv_usec += clkread();
766 	while (tvp->tv_usec > 1000000) {
767 		tvp->tv_sec++;
768 		tvp->tv_usec -= 1000000;
769 	}
770 #endif
771 	if (tvp->tv_sec == lasttime.tv_sec &&
772 	    tvp->tv_usec <= lasttime.tv_usec &&
773 	    (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
774 		tvp->tv_sec++;
775 		tvp->tv_usec -= 1000000;
776 	}
777 	lasttime = *tvp;
778 	splx(s);
779 }
780 
781 initcpu()
782 {
783 
784 	/*
785 	 * clear LEDs
786 	 */
787 	*(char*)DEBUG_PORT = (char)DP_WRITE|DP_LED0|DP_LED1|DP_LED2|DP_LED3;
788 
789 	/*
790 	 * clear all interrupts
791 	 */
792 	*(char*)INTCLR0 = 0;
793 	*(char*)INTCLR1 = 0;
794 
795 	/*
796 	 * It's not a time to enable timer yet.
797 	 *
798 	 *	INTEN0:  PERR ABORT BERR TIMER KBD  MS    CFLT CBSY
799 	 *		  o     o    o     x    o    o     x    x
800 	 *	INTEN1:  BEEP SCC  LANCE DMA  SLOT1 SLOT3 EXT1 EXT3
801 	 *		  x     o    o     o    o    o     x    x
802 	 */
803 
804 	*(char*)INTEN0 = (char) INTEN0_PERR|INTEN0_ABORT|INTEN0_BERR|
805 				INTEN0_KBDINT|INTEN0_MSINT;
806 
807 	*(char*)INTEN1 = (char) INTEN1_SCC|INTEN1_LANCE|INTEN1_DMA|
808 				INTEN1_SLOT1|INTEN1_SLOT3;
809 
810 	spl0();		/* safe to turn interrupts on now */
811 }
812 
813 /*
814  * Convert an ASCII string into an integer.
815  */
816 int
817 atoi(s)
818 	char *s;
819 {
820 	int c;
821 	unsigned base = 10, d;
822 	int neg = 0, val = 0;
823 
824 	if (s == 0 || (c = *s++) == 0)
825 		goto out;
826 
827 	/* skip spaces if any */
828 	while (c == ' ' || c == '\t')
829 		c = *s++;
830 
831 	/* parse sign, allow more than one (compat) */
832 	while (c == '-') {
833 		neg = !neg;
834 		c = *s++;
835 	}
836 
837 	/* parse base specification, if any */
838 	if (c == '0') {
839 		c = *s++;
840 		switch (c) {
841 		case 'X':
842 		case 'x':
843 			base = 16;
844 			break;
845 		case 'B':
846 		case 'b':
847 			base = 2;
848 			break;
849 		default:
850 			base = 8;
851 			break;
852 		}
853 	}
854 
855 	/* parse number proper */
856 	for (;;) {
857 		if (c >= '0' && c <= '9')
858 			d = c - '0';
859 		else if (c >= 'a' && c <= 'z')
860 			d = c - 'a' + 10;
861 		else if (c >= 'A' && c <= 'Z')
862 			d = c - 'A' + 10;
863 		else
864 			break;
865 		val *= base;
866 		val += d;
867 		c = *s++;
868 	}
869 	if (neg)
870 		val = -val;
871 out:
872 	return val;
873 }
874 
875 #ifdef CPU_SINGLE
876 /*
877  * small ring buffers for keyboard/mouse
878  */
879 struct ring_buf {
880 	u_char head;
881 	u_char tail;
882 	u_char count;
883 	u_char buf[13];
884 } ring_buf[2];
885 
886 xputc(c, chan)
887 	u_char c;
888 	int chan;
889 {
890 	register struct ring_buf *p = &ring_buf[chan];
891 	int s = splhigh();
892 
893 	if (p->count >= sizeof (p->buf)) {
894 		(void) splx(s);
895 		return (-1);
896 	}
897 	p->buf[p->head] = c;
898 	if (++p->head >= sizeof (p->buf))
899 		p->head = 0;
900 	p->count++;
901 	(void) splx(s);
902 	return (c);
903 }
904 
905 xgetc(chan)
906 	int chan;
907 {
908 	register struct ring_buf *p = &ring_buf[chan];
909 	int c;
910 	int s = splhigh();
911 
912 	if (p->count == 0) {
913 		(void) splx(s);
914 		return (-1);
915 	}
916 	c = p->buf[p->tail];
917 	if (++p->tail >= sizeof (p->buf))
918 		p->tail = 0;
919 	p->count--;
920 	(void) splx(s);
921 	return (c);
922 }
923 #endif /* CPU_SINGLE */
924 
925 _delay(time)
926 	register int time;
927 {
928 	extern int cpuspeed;
929 
930 	time *= cpuspeed;
931 	while(time--)
932 		;
933 }
934