xref: /original-bsd/sys/i386/i386/machdep.c (revision e718337e)
1 /*-
2  * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * %sccs.include.386.c%
9  *
10  *	@(#)machdep.c	5.5 (Berkeley) 11/25/90
11  */
12 
13 #include "param.h"
14 #include "systm.h"
15 #include "dir.h"
16 #include "user.h"
17 #include "kernel.h"
18 #include "malloc.h"
19 #include "map.h"
20 #include "vm.h"
21 #include "proc.h"
22 #include "buf.h"
23 #include "reboot.h"
24 #include "conf.h"
25 #include "inode.h"
26 #include "file.h"
27 #include "text.h"
28 #include "clist.h"
29 #include "callout.h"
30 #include "cmap.h"
31 #include "mbuf.h"
32 #include "msgbuf.h"
33 #include "quota.h"
34 #include "../net/netisr.h"
35 
36 #include "../i386/frame.h"
37 #include "../i386/reg.h"
38 #include "../i386/segments.h"
39 #include "../i386/pte.h"
40 #include "../i386/psl.h"
41 #include "../i386/isa/rtc.h"
42 
43 /*
44  * Declare these as initialized data so we can patch them.
45  */
46 int	nswbuf = 0;
47 #ifdef	NBUF
48 int	nbuf = NBUF;
49 #else
50 int	nbuf = 0;
51 #endif
52 #ifdef	BUFPAGES
53 int	bufpages = BUFPAGES;
54 #else
55 int	bufpages = 0;
56 #endif
57 int kernmem;
58 
59 /*
60  * Machine-dependent startup code
61  */
62 /*extern char Sysbase;
63 caddr_t sbase = { &Sysbase };*/
64 extern	char	Sysbase[];
65 /* extern struct pte	EMCmap[];
66 extern char		EMCbase[]; */
67 int boothowto = 0, Maxmem = 0;
68 extern int bootdev;
69 #ifdef SMALL
70 extern int forcemaxmem;
71 #endif
72 int biosmem;
73 
74 extern cyloffset;
75 
76 caddr_t bypasshole(b,t) caddr_t b,t; {
77 
78 	if (b <= Sysbase + 0xa0000 && t > Sysbase + 0xa0000)
79 		return(Sysbase + 0x100000);
80 	return(b);
81 }
82 
83 startup(firstaddr)
84 	int firstaddr;
85 {
86 	register int unixsize;
87 	register unsigned i;
88 	register struct pte *pte;
89 	int mapaddr, j;
90 	register caddr_t v;
91 	int maxbufs, base, residual;
92 	extern struct map *useriomap;
93 
94 	/*
95 	 * Initialize the console before we print anything out.
96 	 */
97 	/*cninit();*/
98 
99 	/*
100 	 * Bounds check memory size information against bios values
101 	 * use the lesser of the two
102 	 */
103 	biosmem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
104 printf("Maxmem %x howto %x bootdev %x cyloff %x firstaddr %x bios %d %d\n",
105 		Maxmem, boothowto, bootdev, cyloffset, firstaddr,
106 biosmem,
107 rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI)<<8)
108 );
109 	maxmem = Maxmem-1;
110 
111 	if(biosmem != 640)
112 		panic("does not have 640K of base memory");
113 
114 	biosmem = 1024;
115 	biosmem += rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI)<<8);
116 	biosmem = biosmem/4 - 1 ;
117 	if (biosmem < maxmem) maxmem=biosmem;
118 
119 #ifdef SMALL
120 if(forcemaxmem && maxmem > forcemaxmem)
121 	maxmem = forcemaxmem-1;
122 #endif
123 /*
124 maxmem = 0xA00;*/
125 
126 	/*
127 	 * Initialize error message buffer (at end of core).
128 	 */
129 /* Problem to resolve. AT's have memory that is not contigous, as
130 I/O address space for video adapters and network cards fall into
131 a range of 0xa0000 - 0x100000 . Note that the cmap really expects
132 contigous memory. For the moment, use the bottom of memory for
133 kernel and run-time configured storage (e.g. valloc), using memory
134 above 0x100000 for the cmap, and wasting the stuff left over after
135 valloc-end up to 0xa0000 (640K). Will have to fix this before beta,
136 and will have to somehow move this out into per bus adapter directory
137 (e.g. configurable). For now, punt
138 
139 How about starting cmap normally following valloc space, and then
140 write a routine than allocs only phys pages in the 0xa0000-0x100000
141 hole?
142 
143 Temporary fix for beta, if we only have 640K, then cmap follows valloc
144 up to 640K.
145 */
146 	maxmem -= btoc(sizeof (struct msgbuf));
147 	pte = msgbufmap;
148 	for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
149 		*(int *)pte++ = PG_V | PG_KW | ctob(maxmem + i);
150 
151 #ifdef notdef
152 	/* XXX EMC */
153 	pte = EMCmap;
154 	*(int *)pte = PG_V | PG_UW | 0xc0000000;
155 	printf("EMC at %x\n", EMCbase);
156 #endif
157 
158 	freemem = physmem = maxmem;
159 
160 	load_cr3(_cr3());
161 
162 #ifdef KDB
163 	kdb_init();			/* startup kernel debugger */
164 #endif
165 	/*
166 	 * Good {morning,afternoon,evening,night}.
167 	 */
168 	printf(version);
169 	printf("real mem  = %d\n", ctob(physmem));
170 
171 	/*
172 	 * Allocate space for system data structures.
173 	 * The first available real memory address is in "firstaddr".
174 	 * The first available kernel virtual address is in "v".
175 	 * As pages of kernel virtual memory are allocated, "v" is incremented.
176 	 * As pages of memory are allocated and cleared,
177 	 * "firstaddr" is incremented.
178 	 * An index into the kernel page table corresponding to the
179 	 * virtual memory address maintained in "v" is kept in "mapaddr".
180 	 */
181 	v = (caddr_t)(Sysbase + (firstaddr * NBPG));
182 	/*v = sbase + (firstaddr * NBPG);*/
183 #define	valloc(name, type, num) \
184 		v = bypasshole (v, v + (int) ((name)+(num))) ; \
185 	    (name) = (type *)v; v = (caddr_t)((name)+(num))
186 #define	valloclim(name, type, num, lim) \
187 		v = bypasshole (v, v + (int) ((name)+(num))) ; \
188 	    (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
189 	valloclim(inode, struct inode, ninode, inodeNINODE);
190 	valloclim(file, struct file, nfile, fileNFILE);
191 	valloclim(proc, struct proc, nproc, procNPROC);
192 	valloclim(text, struct text, ntext, textNTEXT);
193 	valloc(cfree, struct cblock, nclist);
194 	valloc(callout, struct callout, ncallout);
195 	valloc(swapmap, struct map, nswapmap = nproc * 2);
196 	valloc(argmap, struct map, ARGMAPSIZE);
197 	valloc(kernelmap, struct map, nproc);
198 	valloc(useriomap, struct map, nproc);
199 	valloc(mbmap, struct map, nmbclusters/4);
200 	valloc(namecache, struct namecache, nchsize);
201 
202 	valloc(kmemmap, struct map, ekmempt - kmempt);
203 	valloc(kmemusage, struct kmemusage, ekmempt - kmempt);
204 #ifdef QUOTA
205 	valloclim(quota, struct quota, nquota, quotaNQUOTA);
206 	valloclim(dquot, struct dquot, ndquot, dquotNDQUOT);
207 #endif
208 
209 	/*
210 	 * Determine how many buffers to allocate.
211 	 * Use 10% of memory for the first 2 Meg, 5% of the remaining
212 	 * memory. Insure a minimum of 16 buffers.
213 	 * We allocate 1/2 as many swap buffer headers as file i/o buffers.
214 	 */
215 	if (bufpages == 0)
216 		if (physmem < (2 * 1024 * 1024))
217 			bufpages = physmem / 10 / CLSIZE;
218 		else
219 			bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE;
220 	if (nbuf == 0) {
221 		nbuf = bufpages / 2;
222 		if (nbuf < 16)
223 			nbuf = 16;
224 	}
225 	if (nswbuf == 0) {
226 		nswbuf = (nbuf / 2) &~ 1;	/* force even */
227 		if (nswbuf > 256)
228 			nswbuf = 256;		/* sanity */
229 	}
230 	valloc(swbuf, struct buf, nswbuf);
231 
232 	/*
233 	 * Now the amount of virtual memory remaining for buffers
234 	 * can be calculated, estimating needs for the cmap.
235 	 */
236 	ncmap = (maxmem*NBPG  - ((int)(v - Sysbase))) /
237 		(CLBYTES + sizeof(struct cmap)) + 2;
238 	maxbufs = ((SYSPTSIZE * NBPG) -
239 		((int)(v - Sysbase + ncmap * sizeof(struct cmap)))) /
240 		(MAXBSIZE + sizeof(struct buf));
241 	if (maxbufs < 16)
242 		panic("sys pt too small");
243 	if (nbuf > maxbufs) {
244 		printf("SYSPTSIZE limits number of buffers to %d\n", maxbufs);
245 		nbuf = maxbufs;
246 	}
247 	if (bufpages > nbuf * (MAXBSIZE / CLBYTES))
248 		bufpages = nbuf * (MAXBSIZE / CLBYTES);
249 	valloc(buf, struct buf, nbuf);
250 
251 	/*
252 	 * Allocate space for core map.
253 	 * Allow space for all of physical memory minus the amount
254 	 * dedicated to the system. The amount of physical memory
255 	 * dedicated to the system is the total virtual memory of
256 	 * the system thus far, plus core map, buffer pages,
257 	 * and buffer headers not yet allocated.
258 	 * Add 2: 1 because the 0th entry is unused, 1 for rounding.
259 	 */
260 	/*ncmap = (maxmem*NBPG - ((int)((v - sbase) + bufpages*CLBYTES))) /*/
261 	ncmap = (maxmem*NBPG - ((int)((v - Sysbase) + bufpages*CLBYTES))) /
262 		(CLBYTES + sizeof(struct cmap)) + 2;
263 	valloclim(cmap, struct cmap, ncmap, ecmap);
264 
265 	/*
266 	 * Clear space allocated thus far, and make r/w entries
267 	 * for the space in the kernel map.
268 	 */
269 	unixsize = btoc((int)(v - Sysbase));
270 	while (firstaddr < unixsize) {
271 		*(int *)(&Sysmap[firstaddr]) = PG_V | PG_KW | ctob(firstaddr);
272 		clearseg((unsigned)firstaddr);
273 		firstaddr++;
274 	}
275 
276 	/*
277 	 * Now allocate buffers proper.  They are different than the above
278 	 * in that they usually occupy more virtual memory than physical.
279 	 */
280 	v = bypasshole (v, (caddr_t) ((int)(v + PGOFSET) &~ PGOFSET +
281 		MAXBSIZE*nbuf));
282 	v = (caddr_t) ((int)(v + PGOFSET) &~ PGOFSET);
283 	valloc(buffers, char, MAXBSIZE * nbuf);
284 	base = bufpages / nbuf;
285 	residual = bufpages % nbuf;
286 	mapaddr = firstaddr = btoc((unsigned) buffers - (unsigned)Sysbase);
287 	for (i = 0; i < residual; i++) {
288 		for (j = 0; j < (base + 1) * CLSIZE; j++) {
289 			*(int *)(&Sysmap[mapaddr+j]) = PG_V | PG_KW | ctob(firstaddr);
290 			clearseg((unsigned)firstaddr);
291 			firstaddr++;
292 		}
293 		mapaddr += MAXBSIZE / NBPG;
294 	}
295 	for (i = residual; i < nbuf; i++) {
296 		for (j = 0; j < base * CLSIZE; j++) {
297 			*(int *)(&Sysmap[mapaddr+j]) = PG_V | PG_KW | ctob(firstaddr);
298 			clearseg((unsigned)firstaddr);
299 			firstaddr++;
300 		}
301 		mapaddr += MAXBSIZE / NBPG;
302 	}
303 
304 	unixsize = btoc((int)(v - Sysbase));
305 	if (firstaddr >= physmem - 8*UPAGES)
306 		panic("no memory");
307 
308 	/*
309 	 * Initialize callouts
310 	 */
311 	callfree = callout;
312 	for (i = 1; i < ncallout; i++)
313 		callout[i-1].c_next = &callout[i];
314 
315 	/*
316 	 * Initialize memory allocator and swap
317 	 * and user page table maps.
318 	 *
319 	 * THE USER PAGE TABLE MAP IS CALLED ``kernelmap''
320 	 * WHICH IS A VERY UNDESCRIPTIVE AND INCONSISTENT NAME.
321 	 */
322 
323 	/*
324 	 *  cmap must not allocate the hole, so toss memory
325 	 */
326 	if(firstaddr < 640/4 && maxmem > 1024/4){
327 		printf("[not using %dK due to hole]\n", 4*(640/4 - firstaddr));
328 		firstaddr = 0x100;
329 	}
330 	if(maxmem < 2048/4-10)
331 	  printf("WARNING: NOT ENOUGH RAM MEMORY - RUNNING IN DEGRADED MODE\n");
332 
333 	meminit(firstaddr, maxmem);
334 	maxmem = freemem;
335 	printf("avail mem = %d\n", ctob(maxmem));
336 	printf("using %d buffers containing %d bytes of memory\n",
337 		nbuf, bufpages * CLBYTES);
338 	rminit(kernelmap, (long)USRPTSIZE, (long)1,
339 	    "usrpt", nproc);
340 /*
341  * PTEs for mapping user space into kernel for phyio operations.
342  * One page is enough to handle 4Mb of simultaneous raw IO operations.
343  */
344 	rminit(useriomap, (long)USRIOSIZE, (long)1, "usrio", nproc);
345 	rminit(mbmap, (long)(nmbclusters * CLSIZE), (long)CLSIZE,
346 	    "mbclusters", nmbclusters/4);
347 	kmeminit();	/* now safe to do malloc/free */
348 	/*intenable = 1;		/* Enable interrupts from now on */
349 
350 	/*
351 	 * Set up CPU-specific registers, cache, etc.
352 	 */
353 	initcpu();
354 
355 	/*
356 	 * Set up buffers, so they can be used to read disk labels.
357 	 */
358 	bhinit();
359 	binit();
360 
361 	/*
362 	 * Configure the system.
363 	 */
364 	configure();
365 }
366 
367 #ifdef PGINPROF
368 /*
369  * Return the difference (in microseconds)
370  * between the  current time and a previous
371  * time as represented  by the arguments.
372  * If there is a pending clock interrupt
373  * which has not been serviced due to high
374  * ipl, return error code.
375  */
376 /*ARGSUSED*/
377 vmtime(otime, olbolt, oicr)
378 	register int otime, olbolt, oicr;
379 {
380 
381 	return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
382 }
383 #endif
384 
385 struct sigframe {
386 	int	sf_signum;
387 	int	sf_code;
388 	struct	sigcontext *sf_scp;
389 	int	(*sf_handler)();
390 	int	sf_eax;
391 	int	sf_edx;
392 	int	sf_ecx;
393 	struct	save87	sf_fsave;	/* fpu coproc */
394 } ;
395 
396 /*
397  * Send an interrupt to process.
398  *
399  * Stack is set up to allow sigcode stored
400  * in u. to call routine, followed by kcall
401  * to sigreturn routine below.  After sigreturn
402  * resets the signal mask, the stack, and the
403  * frame pointer, it returns to the user
404  * specified pc, psl.
405  */
406 sendsig(p, sig, mask, frmtrp)
407 	int (*p)(), sig, mask;
408 {
409 	register struct sigcontext *scp;
410 	register int *regs;
411 	register struct sigframe *fp;
412 	int oonstack;
413 
414 #include "dbg.h"
415 dprintf(DSIGNAL,"sendsig %d code %d to pid %d frmtrp %d to locn %x\n",
416 	sig, u.u_code, u.u_procp->p_pid, frmtrp, p);
417 	regs = u.u_ar0;
418 	oonstack = u.u_onstack;
419 	/*
420 	 * Allocate and validate space for the signal handler
421 	 * context. Note that if the stack is in P0 space, the
422 	 * call to grow() is a nop, and the useracc() check
423 	 * will fail if the process has not already allocated
424 	 * the space with a `brk'.
425 	 */
426 	if (!u.u_onstack && (u.u_sigonstack & sigmask(sig))) {
427 		scp = (struct sigcontext *)u.u_sigsp - 1;
428 		u.u_onstack = 1;
429 	} else {
430 		if (frmtrp)
431 			scp = (struct sigcontext *)regs[tESP] - 1;
432 		else
433 			scp = (struct sigcontext *)regs[sESP] - 1;
434 	}
435 	fp = (struct sigframe *)scp - 1;
436 	if ((int)fp <= USRSTACK - ctob(u.u_ssize))
437 		(void) grow((unsigned)fp);
438 	if (useracc((caddr_t)fp, sizeof (*fp) + sizeof (*scp), B_WRITE) == 0) {
439 		/*
440 		 * Process has trashed its stack; give it an illegal
441 		 * instruction to halt it in its tracks.
442 		 */
443 printf("sendsig: failed to grow stack down to %x\n", fp);
444 		u.u_signal[SIGILL] = SIG_DFL;
445 		sig = sigmask(SIGILL);
446 		u.u_procp->p_sigignore &= ~sig;
447 		u.u_procp->p_sigcatch &= ~sig;
448 		u.u_procp->p_sigmask &= ~sig;
449 		psignal(u.u_procp, SIGILL);
450 		return;
451 	}
452 
453 	/*
454 	 * Build the argument list for the signal handler.
455 	 */
456 	fp->sf_signum = sig;
457 	if (sig == SIGILL || sig == SIGFPE) {
458 		fp->sf_code = u.u_code;
459 		u.u_code = 0;
460 	} else
461 		fp->sf_code = 0;
462 	/* indicate trap occured from system call */
463 	if(!frmtrp) fp->sf_code |= 0x80;
464 
465 	fp->sf_scp = scp;
466 	fp->sf_handler = p;
467 
468 	/* save scratch registers */
469 	if(frmtrp) {
470 		fp->sf_eax = regs[tEAX];
471 		fp->sf_edx = regs[tEDX];
472 		fp->sf_ecx = regs[tECX];
473 	} else {
474 		fp->sf_eax = regs[sEAX];
475 		fp->sf_edx = regs[sEDX];
476 		fp->sf_ecx = regs[sECX];
477 	}
478 #ifdef notyet
479 	/* XXX FPU state? */
480 #endif
481 	/*
482 	 * Build the signal context to be used by sigreturn.
483 	 */
484 	scp->sc_onstack = oonstack;
485 	scp->sc_mask = mask;
486 	if(frmtrp) {
487 		scp->sc_sp = regs[tESP];
488 		scp->sc_fp = regs[tEBP];
489 		scp->sc_pc = regs[tEIP];
490 		scp->sc_ps = regs[tEFLAGS];
491 		regs[tESP] = (int)fp;
492 		regs[tEIP] = (int)u.u_pcb.pcb_sigc;
493 	} else {
494 		scp->sc_sp = regs[sESP];
495 		scp->sc_fp = regs[sEBP];
496 		scp->sc_pc = regs[sEIP];
497 		scp->sc_ps = regs[sEFLAGS];
498 		regs[sESP] = (int)fp;
499 		regs[sEIP] = (int)u.u_pcb.pcb_sigc;
500 	}
501 }
502 
503 /*
504  * System call to cleanup state after a signal
505  * has been taken.  Reset signal mask and
506  * stack state from context left by sendsig (above).
507  * Return to previous pc and psl as specified by
508  * context left by sendsig. Check carefully to
509  * make sure that the user has not modified the
510  * psl to gain improper priviledges or to cause
511  * a machine fault.
512  */
513 sigreturn()
514 {
515 	register struct sigframe *fp;
516 	register struct sigcontext *scp;
517 	register int *regs = u.u_ar0;
518 
519 	fp = (struct sigframe *) regs[sESP] ;
520 	if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) {
521 		u.u_error = EINVAL;
522 		return;
523 	}
524 
525 	/* restore scratch registers */
526 	regs[sEAX] = fp->sf_eax ;
527 	regs[sEDX] = fp->sf_edx ;
528 	regs[sECX] = fp->sf_ecx ;
529 #ifdef notyet
530 	/* XXX FPU state? */
531 #endif
532 
533 	scp = fp->sf_scp;
534 	if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0) {
535 		u.u_error = EINVAL;
536 		return;
537 	}
538 #ifdef notyet
539 	if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
540 		u.u_error = EINVAL;
541 		return;
542 	}
543 #endif
544 	u.u_eosys = JUSTRETURN;
545 	u.u_onstack = scp->sc_onstack & 01;
546 	u.u_procp->p_sigmask = scp->sc_mask &~
547 	    (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
548 	regs[sEBP] = scp->sc_fp;
549 	regs[sESP] = scp->sc_sp;
550 	regs[sEIP] = scp->sc_pc;
551 	regs[sEFLAGS] = scp->sc_ps;
552 }
553 
554 int	waittime = -1;
555 
556 boot(arghowto)
557 	int arghowto;
558 {
559 	register long dummy;		/* r12 is reserved */
560 	register int howto;		/* r11 == how to boot */
561 	register int devtype;		/* r10 == major of root dev */
562 	extern char *panicstr;
563 
564 	howto = arghowto;
565 	if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
566 		register struct buf *bp;
567 		int iter, nbusy;
568 
569 		waittime = 0;
570 		(void) splnet();
571 		printf("syncing disks... ");
572 		/*
573 		 * Release inodes held by texts before update.
574 		 */
575 		if (panicstr == 0)
576 			xumount(NODEV);
577 		update();
578 
579 		for (iter = 0; iter < 20; iter++) {
580 			nbusy = 0;
581 			for (bp = &buf[nbuf]; --bp >= buf; )
582 				if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
583 					nbusy++;
584 			if (nbusy == 0)
585 				break;
586 			printf("%d ", nbusy);
587 			DELAY(40000 * iter);
588 		}
589 		if (nbusy)
590 			printf("giving up\n");
591 		else
592 			printf("done\n");
593 		DELAY(10000);			/* wait for printf to finish */
594 	}
595 	splhigh();
596 	devtype = major(rootdev);
597 	if (howto&RB_HALT) {
598 		printf("halting (in tight loop); hit reset\n\n");
599 		reset_cpu();
600 		for (;;) ;
601 	} else {
602 		if (howto & RB_DUMP) {
603 			doadump();		/* CPBOOT's itsself */
604 			/*NOTREACHED*/
605 		}
606 	}
607 #ifdef lint
608 	dummy = 0; dummy = dummy;
609 	printf("howto %d, devtype %d\n", arghowto, devtype);
610 #endif
611 	reset_cpu();
612 	for(;;) ;
613 	/*NOTREACHED*/
614 }
615 
616 int	dumpmag = 0x8fca0101;	/* magic number for savecore */
617 int	dumpsize = 0;		/* also for savecore */
618 /*
619  * Doadump comes here after turning off memory management and
620  * getting on the dump stack, either when called above, or by
621  * the auto-restart code.
622  */
623 dumpsys()
624 {
625 
626 	if (dumpdev == NODEV)
627 		return;
628 #ifdef notdef
629 	if ((minor(dumpdev)&07) != 1)
630 		return;
631 #endif
632 	dumpsize = physmem;
633 	printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
634 	printf("dump ");
635 	switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
636 
637 	case ENXIO:
638 		printf("device bad\n");
639 		break;
640 
641 	case EFAULT:
642 		printf("device not ready\n");
643 		break;
644 
645 	case EINVAL:
646 		printf("area improper\n");
647 		break;
648 
649 	case EIO:
650 		printf("i/o error\n");
651 		break;
652 
653 	default:
654 		printf("succeeded\n");
655 		break;
656 	}
657 	printf("\n\n");
658 	DELAY(1000);
659 }
660 
661 microtime(tvp)
662 	register struct timeval *tvp;
663 {
664 	int s = splhigh();
665 
666 	*tvp = time;
667 	tvp->tv_usec += tick;
668 	while (tvp->tv_usec > 1000000) {
669 		tvp->tv_sec++;
670 		tvp->tv_usec -= 1000000;
671 	}
672 	splx(s);
673 }
674 
675 physstrat(bp, strat, prio)
676 	struct buf *bp;
677 	int (*strat)(), prio;
678 {
679 	register int s;
680 	caddr_t baddr;
681 
682 	/*
683 	 * vmapbuf clobbers b_addr so we must remember it so that it
684 	 * can be restored after vunmapbuf.  This is truely rude, we
685 	 * should really be storing this in a field in the buf struct
686 	 * but none are available and I didn't want to add one at
687 	 * this time.  Note that b_addr for dirty page pushes is
688 	 * restored in vunmapbuf. (ugh!)
689 	 */
690 	baddr = bp->b_un.b_addr;
691 	vmapbuf(bp);
692 	(*strat)(bp);
693 	/* pageout daemon doesn't wait for pushed pages */
694 	if (bp->b_flags & B_DIRTY)
695 		return;
696 	s = splbio();
697 	while ((bp->b_flags & B_DONE) == 0)
698 		sleep((caddr_t)bp, prio);
699 	splx(s);
700 	vunmapbuf(bp);
701 	bp->b_un.b_addr = baddr;
702 }
703 
704 initcpu()
705 {
706 	register struct proc *p;
707 
708 	p = &proc[0];
709 }
710 
711 /*
712  * Clear registers on exec
713  */
714 setregs(entry)
715 	u_long entry;
716 {
717 
718 #ifdef notdef
719 	/* should pass args to init on the stack */
720 	for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
721 		*rp++ = 0;
722 #endif
723 	u.u_ar0[sEBP] = 0;	/* bottom of the fp chain */
724 	u.u_ar0[sEIP] = entry;
725 }
726 
727 /*
728  * Initialize 386 and configure to run kernel
729  */
730 
731 /*
732  * Initialize segments & interrupt table
733  */
734 
735 
736 #define	GNULL_SEL	0	/* Null Descriptor */
737 #define	GCODE_SEL	1	/* Kernel Code Descriptor */
738 #define	GDATA_SEL	2	/* Kernel Data Descriptor */
739 #define	GLDT_SEL	3	/* LDT - eventually one per process */
740 #define	GTGATE_SEL	4	/* Process task switch gate */
741 #define	GPANIC_SEL	5	/* Task state to consider panic from */
742 #define	GPROC0_SEL	6	/* Task state process slot zero and up */
743 
744 union descriptor gdt[GPROC0_SEL];
745 
746 /* interrupt descriptor table */
747 struct gate_descriptor idt[32+16];
748 
749 /* local descriptor table */
750 union descriptor ldt[5];
751 #define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
752 #define	LSYS5SIGR_SEL	1
753 
754 #define	L43BSDCALLS_SEL	2	/* notyet */
755 #define	LUCODE_SEL	3
756 #define	LUDATA_SEL	4
757 /* seperate stack, es,fs,gs sels ? */
758 /* #define	LPOSIXCALLS_SEL	5	/* notyet */
759 
760 struct	i386tss	tss;
761 
762 /* software prototypes -- in more palitable form */
763 struct soft_segment_descriptor gdt_segs[] = {
764 	/* Null Descriptor */
765 {	0x0,			/* segment base address  */
766 	0x0,			/* length - all address space */
767 	0,			/* segment type */
768 	0,			/* segment descriptor priority level */
769 	0,			/* segment descriptor present */
770 	0,0,
771 	0,			/* default 32 vs 16 bit size */
772 	0  			/* limit granularity (byte/page units)*/ },
773 	/* Code Descriptor for kernel */
774 {	0x0,			/* segment base address  */
775 	0xfffff,		/* length - all address space */
776 	SDT_MEMERA,		/* segment type */
777 	0,			/* segment descriptor priority level */
778 	1,			/* segment descriptor present */
779 	0,0,
780 	1,			/* default 32 vs 16 bit size */
781 	1  			/* limit granularity (byte/page units)*/ },
782 	/* Data Descriptor for kernel */
783 {	0x0,			/* segment base address  */
784 	0xfffff,		/* length - all address space */
785 	SDT_MEMRWA,		/* segment type */
786 	0,			/* segment descriptor priority level */
787 	1,			/* segment descriptor present */
788 	0,0,
789 	1,			/* default 32 vs 16 bit size */
790 	1  			/* limit granularity (byte/page units)*/ },
791 	/* LDT Descriptor */
792 {	(int) ldt,			/* segment base address  */
793 	sizeof(ldt)-1,		/* length - all address space */
794 	SDT_SYSLDT,		/* segment type */
795 	0,			/* segment descriptor priority level */
796 	1,			/* segment descriptor present */
797 	0,0,
798 	0,			/* unused - default 32 vs 16 bit size */
799 	0  			/* limit granularity (byte/page units)*/ },
800 	/* Null Descriptor - Placeholder */
801 {	0x0,			/* segment base address  */
802 	0x0,			/* length - all address space */
803 	0,			/* segment type */
804 	0,			/* segment descriptor priority level */
805 	0,			/* segment descriptor present */
806 	0,0,
807 	0,			/* default 32 vs 16 bit size */
808 	0  			/* limit granularity (byte/page units)*/ },
809 	/* Panic Tss Descriptor */
810 {	(int) &u,			/* segment base address  */
811 	sizeof(tss)-1,		/* length - all address space */
812 	SDT_SYS386TSS,		/* segment type */
813 	0,			/* segment descriptor priority level */
814 	1,			/* segment descriptor present */
815 	0,0,
816 	0,			/* unused - default 32 vs 16 bit size */
817 	0  			/* limit granularity (byte/page units)*/ }};
818 
819 struct soft_segment_descriptor ldt_segs[] = {
820 	/* Null Descriptor - overwritten by call gate */
821 {	0x0,			/* segment base address  */
822 	0x0,			/* length - all address space */
823 	0,			/* segment type */
824 	0,			/* segment descriptor priority level */
825 	0,			/* segment descriptor present */
826 	0,0,
827 	0,			/* default 32 vs 16 bit size */
828 	0  			/* limit granularity (byte/page units)*/ },
829 	/* Null Descriptor - overwritten by call gate */
830 {	0x0,			/* segment base address  */
831 	0x0,			/* length - all address space */
832 	0,			/* segment type */
833 	0,			/* segment descriptor priority level */
834 	0,			/* segment descriptor present */
835 	0,0,
836 	0,			/* default 32 vs 16 bit size */
837 	0  			/* limit granularity (byte/page units)*/ },
838 	/* Null Descriptor - overwritten by call gate */
839 {	0x0,			/* segment base address  */
840 	0x0,			/* length - all address space */
841 	0,			/* segment type */
842 	0,			/* segment descriptor priority level */
843 	0,			/* segment descriptor present */
844 	0,0,
845 	0,			/* default 32 vs 16 bit size */
846 	0  			/* limit granularity (byte/page units)*/ },
847 	/* Code Descriptor for user */
848 {	0x0,			/* segment base address  */
849 	0xfffff,		/* length - all address space */
850 	SDT_MEMERA,		/* segment type */
851 	SEL_UPL,		/* segment descriptor priority level */
852 	1,			/* segment descriptor present */
853 	0,0,
854 	1,			/* default 32 vs 16 bit size */
855 	1  			/* limit granularity (byte/page units)*/ },
856 	/* Data Descriptor for user */
857 {	0x0,			/* segment base address  */
858 	0xfffff,		/* length - all address space */
859 	SDT_MEMRWA,		/* segment type */
860 	SEL_UPL,		/* segment descriptor priority level */
861 	1,			/* segment descriptor present */
862 	0,0,
863 	1,			/* default 32 vs 16 bit size */
864 	1  			/* limit granularity (byte/page units)*/ } };
865 
866 /* table descriptors - used to load tables by microp */
867 struct region_descriptor r_gdt = {
868 	sizeof(gdt)-1,(char *)gdt
869 };
870 
871 struct region_descriptor r_idt = {
872 	sizeof(idt)-1,(char *)idt
873 };
874 
875 setidt(idx, func, typ, dpl) char *func; {
876 	struct gate_descriptor *ip = idt + idx;
877 
878 	ip->gd_looffset = (int)func;
879 	ip->gd_selector = 8;
880 	ip->gd_stkcpy = 0;
881 	ip->gd_xx = 0;
882 	ip->gd_type = typ;
883 	ip->gd_dpl = dpl;
884 	ip->gd_p = 1;
885 	ip->gd_hioffset = ((int)func)>>16 ;
886 }
887 
888 #define	IDTVEC(name)	X/**/name
889 extern	IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
890 	IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
891 	IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
892 	IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
893 	IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
894 	IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
895 	IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
896 	IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
897 
898 int lcr0(), lcr3(), rcr0(), rcr2();
899 int _udatasel, _ucodesel, _gsel_tss;
900 
901 init386(first) { extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
902 	int x, *pi;
903 	struct gate_descriptor *gdp;
904 
905 	/* make gdt memory segments */
906 	gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
907 	for (x=0; x < 6; x++) ssdtosd(gdt_segs+x, gdt+x);
908 	/* make ldt memory segments */
909 	ldt_segs[LUCODE_SEL].ssd_limit = btoc((int) Sysbase);
910 	/*ldt_segs[LUDATA_SEL].ssd_limit = btoc((int) Sysbase); */
911 	ldt_segs[LUDATA_SEL].ssd_limit = btoc(0xfffff000);
912 /* Note. eventually want private ldts per process */
913 	for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
914 
915 /* exceptions */
916 	setidt(0, &IDTVEC(div),  SDT_SYS386TGT, SEL_KPL);
917 	setidt(1, &IDTVEC(dbg),  SDT_SYS386TGT, SEL_KPL);
918 	setidt(2, &IDTVEC(nmi),  SDT_SYS386TGT, SEL_KPL);
919  	setidt(3, &IDTVEC(bpt),  SDT_SYS386TGT, SEL_UPL);
920 	setidt(4, &IDTVEC(ofl),  SDT_SYS386TGT, SEL_KPL);
921 	setidt(5, &IDTVEC(bnd),  SDT_SYS386TGT, SEL_KPL);
922 	setidt(6, &IDTVEC(ill),  SDT_SYS386TGT, SEL_KPL);
923 	setidt(7, &IDTVEC(dna),  SDT_SYS386TGT, SEL_KPL);
924 	setidt(8, &IDTVEC(dble),  SDT_SYS386TGT, SEL_KPL);
925 	setidt(9, &IDTVEC(fpusegm),  SDT_SYS386TGT, SEL_KPL);
926 	setidt(10, &IDTVEC(tss),  SDT_SYS386TGT, SEL_KPL);
927 	setidt(11, &IDTVEC(missing),  SDT_SYS386TGT, SEL_KPL);
928 	setidt(12, &IDTVEC(stk),  SDT_SYS386TGT, SEL_KPL);
929 	setidt(13, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL);
930 	setidt(14, &IDTVEC(page),  SDT_SYS386TGT, SEL_KPL);
931 	setidt(15, &IDTVEC(rsvd),  SDT_SYS386TGT, SEL_KPL);
932 	setidt(16, &IDTVEC(fpu),  SDT_SYS386TGT, SEL_KPL);
933 	setidt(17, &IDTVEC(rsvd0),  SDT_SYS386TGT, SEL_KPL);
934 	setidt(18, &IDTVEC(rsvd1),  SDT_SYS386TGT, SEL_KPL);
935 	setidt(19, &IDTVEC(rsvd2),  SDT_SYS386TGT, SEL_KPL);
936 	setidt(20, &IDTVEC(rsvd3),  SDT_SYS386TGT, SEL_KPL);
937 	setidt(21, &IDTVEC(rsvd4),  SDT_SYS386TGT, SEL_KPL);
938 	setidt(22, &IDTVEC(rsvd5),  SDT_SYS386TGT, SEL_KPL);
939 	setidt(23, &IDTVEC(rsvd6),  SDT_SYS386TGT, SEL_KPL);
940 	setidt(24, &IDTVEC(rsvd7),  SDT_SYS386TGT, SEL_KPL);
941 	setidt(25, &IDTVEC(rsvd8),  SDT_SYS386TGT, SEL_KPL);
942 	setidt(26, &IDTVEC(rsvd9),  SDT_SYS386TGT, SEL_KPL);
943 	setidt(27, &IDTVEC(rsvd10),  SDT_SYS386TGT, SEL_KPL);
944 	setidt(28, &IDTVEC(rsvd11),  SDT_SYS386TGT, SEL_KPL);
945 	setidt(29, &IDTVEC(rsvd12),  SDT_SYS386TGT, SEL_KPL);
946 	setidt(30, &IDTVEC(rsvd13),  SDT_SYS386TGT, SEL_KPL);
947 	setidt(31, &IDTVEC(rsvd14),  SDT_SYS386TGT, SEL_KPL);
948 
949 #include	"isa.h"
950 #if	NISA >0
951 	isa_defaultirq();
952 #endif
953 
954 	lgdt(gdt, sizeof(gdt)-1);
955 	lidt(idt, sizeof(idt)-1);
956 	lldt(GSEL(GLDT_SEL, SEL_KPL));
957 
958 
959 	/* make a initial tss so microp can get interrupt stack on syscall! */
960 	u.u_pcb.pcbtss.tss_esp0 = (int) &u + UPAGES*NBPG;
961 	u.u_pcb.pcbtss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
962 	_gsel_tss = GSEL(GPANIC_SEL, SEL_KPL);
963 	ltr(_gsel_tss);
964 
965 	/* make a call gate to reenter kernel with */
966 	gdp = &ldt[LSYS5CALLS_SEL].gd;
967 
968 	x = (int) &IDTVEC(syscall);
969 	gdp->gd_looffset = x++;
970 	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
971 	gdp->gd_stkcpy = 0;
972 	gdp->gd_type = SDT_SYS386CGT;
973 	gdp->gd_dpl = SEL_UPL;
974 	gdp->gd_p = 1;
975 	gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
976 
977 	/* transfer to user mode */
978 
979 	_ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
980 	_udatasel = LSEL(LUDATA_SEL, SEL_UPL);
981 }
982 
983 /*
984  * zero out physical memory
985  * specified in relocation units (NBPG bytes)
986  */
987 clearseg(n) {
988 	extern CMAP1, CADDR1;
989 
990 	CMAP1 = PG_V | PG_KW | ctob(n);
991 	load_cr3(_cr3());
992 	bzero(&CADDR1,NBPG);
993 }
994 
995 /*
996  * copy a page of physical memory
997  * specified in relocation units (NBPG bytes)
998  */
999 copyseg(frm, n) {
1000 	extern CMAP2, CADDR2;
1001 
1002 	CMAP2 = PG_V | PG_KW | ctob(n);
1003 	load_cr3(_cr3());
1004 	bcopy(frm, &CADDR2,NBPG);
1005 }
1006 
1007 aston() {
1008 	schednetisr(NETISR_AST);
1009 }
1010 
1011 /*
1012  * insert an element into a queue
1013  */
1014 #undef insque
1015 _insque(element, head)
1016 	register struct prochd *element, *head;
1017 {
1018 	element->ph_link = head->ph_link;
1019 	head->ph_link = (struct proc *)element;
1020 	element->ph_rlink = (struct proc *)head;
1021 	((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
1022 }
1023 
1024 /*
1025  * remove an element from a queue
1026  */
1027 #undef remque
1028 _remque(element)
1029 	register struct prochd *element;
1030 {
1031 	((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
1032 	((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
1033 	element->ph_rlink = (struct proc *)0;
1034 }
1035 
1036 vmunaccess() {}
1037 
1038 /*
1039  * Below written in C to allow access to debugging code
1040  */
1041 copyinstr(fromaddr, toaddr, maxlength, lencopied) int *lencopied;
1042 	char *toaddr; {
1043 	int c,tally;
1044 
1045 	tally = 0;
1046 	while (maxlength--) {
1047 		c = fubyte(fromaddr++);
1048 		if (c == -1) {
1049 			if(lencopied) *lencopied = tally;
1050 			return(EFAULT);
1051 		}
1052 		tally++;
1053 		*toaddr++ = (char) c;
1054 		if (c == 0){
1055 			if(lencopied) *lencopied = tally;
1056 			return(0);
1057 		}
1058 	}
1059 	if(lencopied) *lencopied = tally;
1060 	return(ENOENT);
1061 }
1062 
1063 copyoutstr(fromaddr, toaddr, maxlength, lencopied) int *lencopied;
1064 	u_char *fromaddr; {
1065 	int c;
1066 	int tally;
1067 
1068 	tally = 0;
1069 	while (maxlength--) {
1070 		c = subyte(toaddr++,*fromaddr);
1071 		if (c == -1) return(EFAULT);
1072 		tally++;
1073 		if (*fromaddr++ == 0){
1074 			if(lencopied) *lencopied = tally;
1075 			return(0);
1076 		}
1077 	}
1078 	if(lencopied) *lencopied = tally;
1079 	return(ENOENT);
1080 }
1081 
1082 copystr(fromaddr, toaddr, maxlength, lencopied) int *lencopied;
1083 	u_char *fromaddr, *toaddr; {
1084 	int tally;
1085 
1086 	tally = 0;
1087 	while (maxlength--) {
1088 		*toaddr = *fromaddr++;
1089 		tally++;
1090 		if (*toaddr++ == 0) {
1091 			if(lencopied) *lencopied = tally;
1092 			return(0);
1093 		}
1094 	}
1095 	if(lencopied) *lencopied = tally;
1096 	return(ENOENT);
1097 }
1098 
1099 /*
1100  * ovbcopy - like bcopy, but recognizes overlapping ranges and handles
1101  *           them correctly.
1102  */
1103 ovbcopy(from, to, bytes)
1104 	char *from, *to;
1105 	int bytes;			/* num bytes to copy */
1106 {
1107 	/* Assume that bcopy copies left-to-right (low addr first). */
1108 	if (from + bytes <= to || to + bytes <= from || to == from)
1109 		bcopy(from, to, bytes);	/* non-overlapping or no-op*/
1110 	else if (from > to)
1111 		bcopy(from, to, bytes);	/* overlapping but OK */
1112 	else {
1113 		/* to > from: overlapping, and must copy right-to-left. */
1114 		from += bytes - 1;
1115 		to += bytes - 1;
1116 		while (bytes-- > 0)
1117 			*to-- = *from--;
1118 	}
1119 }
1120