xref: /original-bsd/sys/i386/i386/machdep.c (revision 93152bbe)
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.redist.c%
9  *
10  *	@(#)machdep.c	7.5 (Berkeley) 07/25/91
11  */
12 
13 
14 #include "param.h"
15 #include "systm.h"
16 #include "signalvar.h"
17 #include "kernel.h"
18 #include "map.h"
19 #include "proc.h"
20 #include "user.h"
21 #include "buf.h"
22 #include "reboot.h"
23 #include "conf.h"
24 #include "file.h"
25 #include "clist.h"
26 #include "callout.h"
27 #include "malloc.h"
28 #include "mbuf.h"
29 #include "msgbuf.h"
30 #include "net/netisr.h"
31 
32 #include "vm/vm.h"
33 #include "vm/vm_kern.h"
34 #include "vm/vm_page.h"
35 
36 vm_map_t buffer_map;
37 extern vm_offset_t avail_end;
38 
39 #include "machine/cpu.h"
40 #include "machine/reg.h"
41 #include "machine/psl.h"
42 #include "machine/specialreg.h"
43 #include "i386/isa/rtc.h"
44 
45 /*
46  * Declare these as initialized data so we can patch them.
47  */
48 int	nswbuf = 0;
49 #ifdef	NBUF
50 int	nbuf = NBUF;
51 #else
52 int	nbuf = 0;
53 #endif
54 #ifdef	BUFPAGES
55 int	bufpages = BUFPAGES;
56 #else
57 int	bufpages = 0;
58 #endif
59 int	msgbufmapped;		/* set when safe to use msgbuf */
60 
61 /*
62  * Machine-dependent startup code
63  */
64 int boothowto = 0, Maxmem = 0;
65 long dumplo;
66 int physmem, maxmem;
67 extern int bootdev;
68 #ifdef SMALL
69 extern int forcemaxmem;
70 #endif
71 int biosmem;
72 
73 extern cyloffset;
74 
75 cpu_startup(firstaddr)
76 	int firstaddr;
77 {
78 	register int unixsize;
79 	register unsigned i;
80 	register struct pte *pte;
81 	int mapaddr, j;
82 	register caddr_t v;
83 	int maxbufs, base, residual;
84 	extern long Usrptsize;
85 	vm_offset_t minaddr, maxaddr;
86 	vm_size_t size;
87 
88 	/*
89 	 * Initialize error message buffer (at end of core).
90 	 */
91 
92 	/* avail_end was pre-decremented in pmap_bootstrap to compensate */
93 	for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
94 		pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG,
95 			   VM_PROT_ALL, TRUE);
96 	msgbufmapped = 1;
97 
98 #ifdef KDB
99 	kdb_init();			/* startup kernel debugger */
100 #endif
101 	/*
102 	 * Good {morning,afternoon,evening,night}.
103 	 */
104 	printf(version);
105 	printf("real mem  = %d\n", ctob(physmem));
106 
107 	/*
108 	 * Allocate space for system data structures.
109 	 * The first available real memory address is in "firstaddr".
110 	 * The first available kernel virtual address is in "v".
111 	 * As pages of kernel virtual memory are allocated, "v" is incremented.
112 	 * As pages of memory are allocated and cleared,
113 	 * "firstaddr" is incremented.
114 	 * An index into the kernel page table corresponding to the
115 	 * virtual memory address maintained in "v" is kept in "mapaddr".
116 	 */
117 
118 	/*
119 	 * Make two passes.  The first pass calculates how much memory is
120 	 * needed and allocates it.  The second pass assigns virtual
121 	 * addresses to the various data structures.
122 	 */
123 	firstaddr = 0;
124 again:
125 	v = (caddr_t)firstaddr;
126 
127 #define	valloc(name, type, num) \
128 	    (name) = (type *)v; v = (caddr_t)((name)+(num))
129 #define	valloclim(name, type, num, lim) \
130 	    (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
131 	valloc(cfree, struct cblock, nclist);
132 	valloc(callout, struct callout, ncallout);
133 	valloc(swapmap, struct map, nswapmap = maxproc * 2);
134 #ifdef SYSVSHM
135 	valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
136 #endif
137 	/*
138 	 * Determine how many buffers to allocate.
139 	 * Use 10% of memory for the first 2 Meg, 5% of the remaining
140 	 * memory. Insure a minimum of 16 buffers.
141 	 * We allocate 1/2 as many swap buffer headers as file i/o buffers.
142 	 */
143 	if (bufpages == 0)
144 		if (physmem < (2 * 1024 * 1024))
145 			bufpages = physmem / 10 / CLSIZE;
146 		else
147 			bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE;
148 	if (nbuf == 0) {
149 		nbuf = bufpages / 2;
150 		if (nbuf < 16)
151 			nbuf = 16;
152 	}
153 	if (nswbuf == 0) {
154 		nswbuf = (nbuf / 2) &~ 1;	/* force even */
155 		if (nswbuf > 256)
156 			nswbuf = 256;		/* sanity */
157 	}
158 	valloc(swbuf, struct buf, nswbuf);
159 	valloc(buf, struct buf, nbuf);
160 
161 	/*
162 	 * End of first pass, size has been calculated so allocate memory
163 	 */
164 	if (firstaddr == 0) {
165 		size = (vm_size_t)(v - firstaddr);
166 		firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
167 		if (firstaddr == 0)
168 			panic("startup: no room for tables");
169 		goto again;
170 	}
171 	/*
172 	 * End of second pass, addresses have been assigned
173 	 */
174 	if ((vm_size_t)(v - firstaddr) != size)
175 		panic("startup: table size inconsistency");
176 	/*
177 	 * Now allocate buffers proper.  They are different than the above
178 	 * in that they usually occupy more virtual memory than physical.
179 	 */
180 	size = MAXBSIZE * nbuf;
181 	buffer_map = kmem_suballoc(kernel_map, (vm_offset_t)&buffers,
182 				   &maxaddr, size, FALSE);
183 	minaddr = (vm_offset_t)buffers;
184 	if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0,
185 			&minaddr, size, FALSE) != KERN_SUCCESS)
186 		panic("startup: cannot allocate buffers");
187 	base = bufpages / nbuf;
188 	residual = bufpages % nbuf;
189 	for (i = 0; i < nbuf; i++) {
190 		vm_size_t curbufsize;
191 		vm_offset_t curbuf;
192 
193 		/*
194 		 * First <residual> buffers get (base+1) physical pages
195 		 * allocated for them.  The rest get (base) physical pages.
196 		 *
197 		 * The rest of each buffer occupies virtual space,
198 		 * but has no physical memory allocated for it.
199 		 */
200 		curbuf = (vm_offset_t)buffers + i * MAXBSIZE;
201 		curbufsize = CLBYTES * (i < residual ? base+1 : base);
202 		vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE);
203 		vm_map_simplify(buffer_map, curbuf);
204 	}
205 	/*
206 	 * Allocate a submap for exec arguments.  This map effectively
207 	 * limits the number of processes exec'ing at any time.
208 	 */
209 	exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
210 				 16*NCARGS, TRUE);
211 	/*
212 	 * Allocate a submap for physio
213 	 */
214 	phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
215 				 VM_PHYS_SIZE, TRUE);
216 
217 	/*
218 	 * Finally, allocate mbuf pool.  Since mclrefcnt is an off-size
219 	 * we use the more space efficient malloc in place of kmem_alloc.
220 	 */
221 	mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
222 				   M_MBUF, M_NOWAIT);
223 	bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
224 	mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
225 			       VM_MBUF_SIZE, FALSE);
226 	/*
227 	 * Initialize callouts
228 	 */
229 	callfree = callout;
230 	for (i = 1; i < ncallout; i++)
231 		callout[i-1].c_next = &callout[i];
232 
233 	printf("avail mem = %d\n", ptoa(vm_stat.free_count));
234 	printf("using %d buffers containing %d bytes of memory\n",
235 		nbuf, bufpages * CLBYTES);
236 
237 	/*
238 	 * Set up CPU-specific registers, cache, etc.
239 	 */
240 	initcpu();
241 
242 	/*
243 	 * Set up buffers, so they can be used to read disk labels.
244 	 */
245 	bufinit();
246 
247 	/*
248 	 * Configure the system.
249 	 */
250 	configure();
251 }
252 
253 #ifdef PGINPROF
254 /*
255  * Return the difference (in microseconds)
256  * between the  current time and a previous
257  * time as represented  by the arguments.
258  * If there is a pending clock interrupt
259  * which has not been serviced due to high
260  * ipl, return error code.
261  */
262 /*ARGSUSED*/
263 vmtime(otime, olbolt, oicr)
264 	register int otime, olbolt, oicr;
265 {
266 
267 	return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
268 }
269 #endif
270 
271 struct sigframe {
272 	int	sf_signum;
273 	int	sf_code;
274 	struct	sigcontext *sf_scp;
275 	sig_t	sf_handler;
276 	int	sf_eax;
277 	int	sf_edx;
278 	int	sf_ecx;
279 	struct	sigcontext sf_sc;
280 } ;
281 
282 extern int kstack[];
283 
284 /*
285  * Send an interrupt to process.
286  *
287  * Stack is set up to allow sigcode stored
288  * in u. to call routine, followed by kcall
289  * to sigreturn routine below.  After sigreturn
290  * resets the signal mask, the stack, and the
291  * frame pointer, it returns to the user
292  * specified pc, psl.
293  */
294 void
295 sendsig(catcher, sig, mask, code)
296 	sig_t catcher;
297 	int sig, mask;
298 	unsigned code;
299 {
300 	register struct proc *p = curproc;
301 	register int *regs;
302 	register struct sigframe *fp;
303 	struct sigacts *ps = p->p_sigacts;
304 	int oonstack, frmtrap;
305 
306 	regs = p->p_regs;
307         oonstack = ps->ps_onstack;
308 	frmtrap = curpcb->pcb_flags & FM_TRAP;
309 	/*
310 	 * Allocate and validate space for the signal handler
311 	 * context. Note that if the stack is in P0 space, the
312 	 * call to grow() is a nop, and the useracc() check
313 	 * will fail if the process has not already allocated
314 	 * the space with a `brk'.
315 	 */
316         if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
317 		fp = (struct sigframe *)(ps->ps_sigsp
318 				- sizeof(struct sigframe));
319                 ps->ps_onstack = 1;
320 	} else {
321 		if (frmtrap)
322 			fp = (struct sigframe *)(regs[tESP]
323 				- sizeof(struct sigframe));
324 		else
325 			fp = (struct sigframe *)(regs[sESP]
326 				- sizeof(struct sigframe));
327 	}
328 
329 	if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize))
330 		(void)grow((unsigned)fp);
331 
332 	if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) {
333 		/*
334 		 * Process has trashed its stack; give it an illegal
335 		 * instruction to halt it in its tracks.
336 		 */
337 		SIGACTION(p, SIGILL) = SIG_DFL;
338 		sig = sigmask(SIGILL);
339 		p->p_sigignore &= ~sig;
340 		p->p_sigcatch &= ~sig;
341 		p->p_sigmask &= ~sig;
342 		psignal(p, SIGILL);
343 		return;
344 	}
345 
346 	/*
347 	 * Build the argument list for the signal handler.
348 	 */
349 	fp->sf_signum = sig;
350 	fp->sf_code = code;
351 	fp->sf_scp = &fp->sf_sc;
352 	fp->sf_handler = catcher;
353 
354 	/* save scratch registers */
355 	if(frmtrap) {
356 		fp->sf_eax = regs[tEAX];
357 		fp->sf_edx = regs[tEDX];
358 		fp->sf_ecx = regs[tECX];
359 	} else {
360 		fp->sf_eax = regs[sEAX];
361 		fp->sf_edx = regs[sEDX];
362 		fp->sf_ecx = regs[sECX];
363 	}
364 	/*
365 	 * Build the signal context to be used by sigreturn.
366 	 */
367 	fp->sf_sc.sc_onstack = oonstack;
368 	fp->sf_sc.sc_mask = mask;
369 	if(frmtrap) {
370 		fp->sf_sc.sc_sp = regs[tESP];
371 		fp->sf_sc.sc_fp = regs[tEBP];
372 		fp->sf_sc.sc_pc = regs[tEIP];
373 		fp->sf_sc.sc_ps = regs[tEFLAGS];
374 		regs[tESP] = (int)fp;
375 		regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
376 	} else {
377 		fp->sf_sc.sc_sp = regs[sESP];
378 		fp->sf_sc.sc_fp = regs[sEBP];
379 		fp->sf_sc.sc_pc = regs[sEIP];
380 		fp->sf_sc.sc_ps = regs[sEFLAGS];
381 		regs[sESP] = (int)fp;
382 		regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
383 	}
384 }
385 
386 /*
387  * System call to cleanup state after a signal
388  * has been taken.  Reset signal mask and
389  * stack state from context left by sendsig (above).
390  * Return to previous pc and psl as specified by
391  * context left by sendsig. Check carefully to
392  * make sure that the user has not modified the
393  * psl to gain improper priviledges or to cause
394  * a machine fault.
395  */
396 sigreturn(p, uap, retval)
397 	struct proc *p;
398 	struct args {
399 		struct sigcontext *sigcntxp;
400 	} *uap;
401 	int *retval;
402 {
403 	register struct sigcontext *scp;
404 	register struct sigframe *fp;
405 	register int *regs = p->p_regs;
406 
407 
408 	fp = (struct sigframe *) regs[sESP] ;
409 
410 	if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0)
411 		return(EINVAL);
412 
413 	/* restore scratch registers */
414 	regs[sEAX] = fp->sf_eax ;
415 	regs[sEDX] = fp->sf_edx ;
416 	regs[sECX] = fp->sf_ecx ;
417 
418 	scp = fp->sf_scp;
419 	if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
420 		return(EINVAL);
421 #ifdef notyet
422 	if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
423 		return(EINVAL);
424 	}
425 #endif
426         p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
427 	p->p_sigmask = scp->sc_mask &~
428 	    (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
429 	regs[sEBP] = scp->sc_fp;
430 	regs[sESP] = scp->sc_sp;
431 	regs[sEIP] = scp->sc_pc;
432 	regs[sEFLAGS] = scp->sc_ps;
433 	return(EJUSTRETURN);
434 }
435 
436 int	waittime = -1;
437 
438 boot(arghowto)
439 	int arghowto;
440 {
441 	register long dummy;		/* r12 is reserved */
442 	register int howto;		/* r11 == how to boot */
443 	register int devtype;		/* r10 == major of root dev */
444 	extern char *panicstr;
445 
446 	howto = arghowto;
447 	if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
448 		register struct buf *bp;
449 		int iter, nbusy;
450 
451 		waittime = 0;
452 		(void) splnet();
453 		printf("syncing disks... ");
454 		/*
455 		 * Release inodes held by texts before update.
456 		 */
457 		if (panicstr == 0)
458 			vnode_pager_umount(NULL);
459 		sync((struct sigcontext *)0);
460 
461 		for (iter = 0; iter < 20; iter++) {
462 			nbusy = 0;
463 			for (bp = &buf[nbuf]; --bp >= buf; )
464 				if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
465 					nbusy++;
466 			if (nbusy == 0)
467 				break;
468 			printf("%d ", nbusy);
469 			DELAY(40000 * iter);
470 		}
471 		if (nbusy)
472 			printf("giving up\n");
473 		else
474 			printf("done\n");
475 		DELAY(10000);			/* wait for printf to finish */
476 	}
477 	splhigh();
478 	devtype = major(rootdev);
479 	if (howto&RB_HALT) {
480 		printf("halting (in tight loop); hit reset\n\n");
481 		splx(0xfffd);	/* all but keyboard XXX */
482 		for (;;) ;
483 	} else {
484 		if (howto & RB_DUMP) {
485 			dumpsys();
486 			/*NOTREACHED*/
487 		}
488 	}
489 #ifdef lint
490 	dummy = 0; dummy = dummy;
491 	printf("howto %d, devtype %d\n", arghowto, devtype);
492 #endif
493 	reset_cpu();
494 	for(;;) ;
495 	/*NOTREACHED*/
496 }
497 
498 int	dumpmag = 0x8fca0101;	/* magic number for savecore */
499 int	dumpsize = 0;		/* also for savecore */
500 /*
501  * Doadump comes here after turning off memory management and
502  * getting on the dump stack, either when called above, or by
503  * the auto-restart code.
504  */
505 dumpsys()
506 {
507 
508 	if (dumpdev == NODEV)
509 		return;
510 	if ((minor(dumpdev)&07) != 1)
511 		return;
512 	dumpsize = physmem;
513 	printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
514 	printf("dump ");
515 	switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
516 
517 	case ENXIO:
518 		printf("device bad\n");
519 		break;
520 
521 	case EFAULT:
522 		printf("device not ready\n");
523 		break;
524 
525 	case EINVAL:
526 		printf("area improper\n");
527 		break;
528 
529 	case EIO:
530 		printf("i/o error\n");
531 		break;
532 
533 	default:
534 		printf("succeeded\n");
535 		break;
536 	}
537 	printf("\n\n");
538 	DELAY(1000);
539 }
540 
541 microtime(tvp)
542 	register struct timeval *tvp;
543 {
544 	int s = splhigh();
545 
546 	*tvp = time;
547 	tvp->tv_usec += tick;
548 	while (tvp->tv_usec > 1000000) {
549 		tvp->tv_sec++;
550 		tvp->tv_usec -= 1000000;
551 	}
552 	splx(s);
553 }
554 
555 physstrat(bp, strat, prio)
556 	struct buf *bp;
557 	int (*strat)(), prio;
558 {
559 	register int s;
560 	caddr_t baddr;
561 
562 	/*
563 	 * vmapbuf clobbers b_addr so we must remember it so that it
564 	 * can be restored after vunmapbuf.  This is truely rude, we
565 	 * should really be storing this in a field in the buf struct
566 	 * but none are available and I didn't want to add one at
567 	 * this time.  Note that b_addr for dirty page pushes is
568 	 * restored in vunmapbuf. (ugh!)
569 	 */
570 	baddr = bp->b_un.b_addr;
571 	vmapbuf(bp);
572 	(*strat)(bp);
573 	/* pageout daemon doesn't wait for pushed pages */
574 	if (bp->b_flags & B_DIRTY)
575 		return;
576 	s = splbio();
577 	while ((bp->b_flags & B_DONE) == 0)
578 		sleep((caddr_t)bp, prio);
579 	splx(s);
580 	vunmapbuf(bp);
581 	bp->b_un.b_addr = baddr;
582 }
583 
584 initcpu()
585 {
586 }
587 
588 /*
589  * Clear registers on exec
590  */
591 setregs(p, entry)
592 	struct proc *p;
593 	u_long entry;
594 {
595 
596 	p->p_regs[sEBP] = 0;	/* bottom of the fp chain */
597 	p->p_regs[sEIP] = entry;
598 
599 	p->p_addr->u_pcb.pcb_flags = 0;	/* no fp at all */
600 	load_cr0(rcr0() | CR0_EM);	/* start emulating */
601 #ifdef	NPX
602 	npxinit(0x262);
603 #endif
604 }
605 
606 /*
607  * Initialize 386 and configure to run kernel
608  */
609 
610 /*
611  * Initialize segments & interrupt table
612  */
613 
614 
615 #define	GNULL_SEL	0	/* Null Descriptor */
616 #define	GCODE_SEL	1	/* Kernel Code Descriptor */
617 #define	GDATA_SEL	2	/* Kernel Data Descriptor */
618 #define	GLDT_SEL	3	/* LDT - eventually one per process */
619 #define	GTGATE_SEL	4	/* Process task switch gate */
620 #define	GPANIC_SEL	5	/* Task state to consider panic from */
621 #define	GPROC0_SEL	6	/* Task state process slot zero and up */
622 #define NGDT 	GPROC0_SEL+1
623 
624 union descriptor gdt[GPROC0_SEL+1];
625 
626 /* interrupt descriptor table */
627 struct gate_descriptor idt[32+16];
628 
629 /* local descriptor table */
630 union descriptor ldt[5];
631 #define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
632 #define	LSYS5SIGR_SEL	1
633 
634 #define	L43BSDCALLS_SEL	2	/* notyet */
635 #define	LUCODE_SEL	3
636 #define	LUDATA_SEL	4
637 /* seperate stack, es,fs,gs sels ? */
638 /* #define	LPOSIXCALLS_SEL	5	/* notyet */
639 
640 struct	i386tss	tss, panic_tss;
641 
642 extern  struct user *proc0paddr;
643 
644 /* software prototypes -- in more palitable form */
645 struct soft_segment_descriptor gdt_segs[] = {
646 	/* Null Descriptor */
647 {	0x0,			/* segment base address  */
648 	0x0,			/* length - all address space */
649 	0,			/* segment type */
650 	0,			/* segment descriptor priority level */
651 	0,			/* segment descriptor present */
652 	0,0,
653 	0,			/* default 32 vs 16 bit size */
654 	0  			/* limit granularity (byte/page units)*/ },
655 	/* Code Descriptor for kernel */
656 {	0x0,			/* segment base address  */
657 	0xfffff,		/* length - all address space */
658 	SDT_MEMERA,		/* segment type */
659 	0,			/* segment descriptor priority level */
660 	1,			/* segment descriptor present */
661 	0,0,
662 	1,			/* default 32 vs 16 bit size */
663 	1  			/* limit granularity (byte/page units)*/ },
664 	/* Data Descriptor for kernel */
665 {	0x0,			/* segment base address  */
666 	0xfffff,		/* length - all address space */
667 	SDT_MEMRWA,		/* segment type */
668 	0,			/* segment descriptor priority level */
669 	1,			/* segment descriptor present */
670 	0,0,
671 	1,			/* default 32 vs 16 bit size */
672 	1  			/* limit granularity (byte/page units)*/ },
673 	/* LDT Descriptor */
674 {	(int) ldt,			/* segment base address  */
675 	sizeof(ldt)-1,		/* length - all address space */
676 	SDT_SYSLDT,		/* segment type */
677 	0,			/* segment descriptor priority level */
678 	1,			/* segment descriptor present */
679 	0,0,
680 	0,			/* unused - default 32 vs 16 bit size */
681 	0  			/* limit granularity (byte/page units)*/ },
682 	/* Null Descriptor - Placeholder */
683 {	0x0,			/* segment base address  */
684 	0x0,			/* length - all address space */
685 	0,			/* segment type */
686 	0,			/* segment descriptor priority level */
687 	0,			/* segment descriptor present */
688 	0,0,
689 	0,			/* default 32 vs 16 bit size */
690 	0  			/* limit granularity (byte/page units)*/ },
691 	/* Panic Tss Descriptor */
692 {	(int) &panic_tss,		/* segment base address  */
693 	sizeof(tss)-1,		/* length - all address space */
694 	SDT_SYS386TSS,		/* segment type */
695 	0,			/* segment descriptor priority level */
696 	1,			/* segment descriptor present */
697 	0,0,
698 	0,			/* unused - default 32 vs 16 bit size */
699 	0  			/* limit granularity (byte/page units)*/ },
700 	/* Proc 0 Tss Descriptor */
701 {	(int) kstack,			/* segment base address  */
702 	sizeof(tss)-1,		/* length - all address space */
703 	SDT_SYS386TSS,		/* segment type */
704 	0,			/* segment descriptor priority level */
705 	1,			/* segment descriptor present */
706 	0,0,
707 	0,			/* unused - default 32 vs 16 bit size */
708 	0  			/* limit granularity (byte/page units)*/ }};
709 
710 struct soft_segment_descriptor ldt_segs[] = {
711 	/* Null Descriptor - overwritten by call gate */
712 {	0x0,			/* segment base address  */
713 	0x0,			/* length - all address space */
714 	0,			/* segment type */
715 	0,			/* segment descriptor priority level */
716 	0,			/* segment descriptor present */
717 	0,0,
718 	0,			/* default 32 vs 16 bit size */
719 	0  			/* limit granularity (byte/page units)*/ },
720 	/* Null Descriptor - overwritten by call gate */
721 {	0x0,			/* segment base address  */
722 	0x0,			/* length - all address space */
723 	0,			/* segment type */
724 	0,			/* segment descriptor priority level */
725 	0,			/* segment descriptor present */
726 	0,0,
727 	0,			/* default 32 vs 16 bit size */
728 	0  			/* limit granularity (byte/page units)*/ },
729 	/* Null Descriptor - overwritten by call gate */
730 {	0x0,			/* segment base address  */
731 	0x0,			/* length - all address space */
732 	0,			/* segment type */
733 	0,			/* segment descriptor priority level */
734 	0,			/* segment descriptor present */
735 	0,0,
736 	0,			/* default 32 vs 16 bit size */
737 	0  			/* limit granularity (byte/page units)*/ },
738 	/* Code Descriptor for user */
739 {	0x0,			/* segment base address  */
740 	0xfffff,		/* length - all address space */
741 	SDT_MEMERA,		/* segment type */
742 	SEL_UPL,		/* segment descriptor priority level */
743 	1,			/* segment descriptor present */
744 	0,0,
745 	1,			/* default 32 vs 16 bit size */
746 	1  			/* limit granularity (byte/page units)*/ },
747 	/* Data Descriptor for user */
748 {	0x0,			/* segment base address  */
749 	0xfffff,		/* length - all address space */
750 	SDT_MEMRWA,		/* segment type */
751 	SEL_UPL,		/* segment descriptor priority level */
752 	1,			/* segment descriptor present */
753 	0,0,
754 	1,			/* default 32 vs 16 bit size */
755 	1  			/* limit granularity (byte/page units)*/ } };
756 
757 /* table descriptors - used to load tables by microp */
758 struct region_descriptor r_gdt = {
759 	sizeof(gdt)-1,(char *)gdt
760 };
761 
762 struct region_descriptor r_idt = {
763 	sizeof(idt)-1,(char *)idt
764 };
765 
766 setidt(idx, func, typ, dpl) char *func; {
767 	struct gate_descriptor *ip = idt + idx;
768 
769 	ip->gd_looffset = (int)func;
770 	ip->gd_selector = 8;
771 	ip->gd_stkcpy = 0;
772 	ip->gd_xx = 0;
773 	ip->gd_type = typ;
774 	ip->gd_dpl = dpl;
775 	ip->gd_p = 1;
776 	ip->gd_hioffset = ((int)func)>>16 ;
777 }
778 
779 #define	IDTVEC(name)	__CONCAT(X, name)
780 extern	IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
781 	IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
782 	IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
783 	IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
784 	IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
785 	IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
786 	IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
787 	IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
788 
789 int lcr0(), lcr3(), rcr0(), rcr2();
790 int _udatasel, _ucodesel, _gsel_tss;
791 
792 init386(first) { extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
793 	int x, *pi;
794 	unsigned biosbasemem, biosextmem;
795 	struct gate_descriptor *gdp;
796 	extern int sigcode,szsigcode;
797 
798 	proc0.p_addr = proc0paddr;
799 
800 	/*
801 	 * Initialize the console before we print anything out.
802 	 */
803 
804 	cninit (KERNBASE+0xa0000);
805 
806 	/* make gdt memory segments */
807 	gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
808 	for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
809 	/* make ldt memory segments */
810 	ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
811 	ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
812 	/* Note. eventually want private ldts per process */
813 	for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
814 
815 	/* exceptions */
816 	setidt(0, &IDTVEC(div),  SDT_SYS386TGT, SEL_KPL);
817 	setidt(1, &IDTVEC(dbg),  SDT_SYS386TGT, SEL_KPL);
818 	setidt(2, &IDTVEC(nmi),  SDT_SYS386TGT, SEL_KPL);
819  	setidt(3, &IDTVEC(bpt),  SDT_SYS386TGT, SEL_UPL);
820 	setidt(4, &IDTVEC(ofl),  SDT_SYS386TGT, SEL_KPL);
821 	setidt(5, &IDTVEC(bnd),  SDT_SYS386TGT, SEL_KPL);
822 	setidt(6, &IDTVEC(ill),  SDT_SYS386TGT, SEL_KPL);
823 	setidt(7, &IDTVEC(dna),  SDT_SYS386TGT, SEL_KPL);
824 	setidt(8, &IDTVEC(dble),  SDT_SYS386TGT, SEL_KPL);
825 	setidt(9, &IDTVEC(fpusegm),  SDT_SYS386TGT, SEL_KPL);
826 	setidt(10, &IDTVEC(tss),  SDT_SYS386TGT, SEL_KPL);
827 	setidt(11, &IDTVEC(missing),  SDT_SYS386TGT, SEL_KPL);
828 	setidt(12, &IDTVEC(stk),  SDT_SYS386TGT, SEL_KPL);
829 	setidt(13, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL);
830 	setidt(14, &IDTVEC(page),  SDT_SYS386TGT, SEL_KPL);
831 	setidt(15, &IDTVEC(rsvd),  SDT_SYS386TGT, SEL_KPL);
832 	setidt(16, &IDTVEC(fpu),  SDT_SYS386TGT, SEL_KPL);
833 	setidt(17, &IDTVEC(rsvd0),  SDT_SYS386TGT, SEL_KPL);
834 	setidt(18, &IDTVEC(rsvd1),  SDT_SYS386TGT, SEL_KPL);
835 	setidt(19, &IDTVEC(rsvd2),  SDT_SYS386TGT, SEL_KPL);
836 	setidt(20, &IDTVEC(rsvd3),  SDT_SYS386TGT, SEL_KPL);
837 	setidt(21, &IDTVEC(rsvd4),  SDT_SYS386TGT, SEL_KPL);
838 	setidt(22, &IDTVEC(rsvd5),  SDT_SYS386TGT, SEL_KPL);
839 	setidt(23, &IDTVEC(rsvd6),  SDT_SYS386TGT, SEL_KPL);
840 	setidt(24, &IDTVEC(rsvd7),  SDT_SYS386TGT, SEL_KPL);
841 	setidt(25, &IDTVEC(rsvd8),  SDT_SYS386TGT, SEL_KPL);
842 	setidt(26, &IDTVEC(rsvd9),  SDT_SYS386TGT, SEL_KPL);
843 	setidt(27, &IDTVEC(rsvd10),  SDT_SYS386TGT, SEL_KPL);
844 	setidt(28, &IDTVEC(rsvd11),  SDT_SYS386TGT, SEL_KPL);
845 	setidt(29, &IDTVEC(rsvd12),  SDT_SYS386TGT, SEL_KPL);
846 	setidt(30, &IDTVEC(rsvd13),  SDT_SYS386TGT, SEL_KPL);
847 	setidt(31, &IDTVEC(rsvd14),  SDT_SYS386TGT, SEL_KPL);
848 
849 #include	"isa.h"
850 #if	NISA >0
851 	isa_defaultirq();
852 #endif
853 
854 	lgdt(gdt, sizeof(gdt)-1);
855 	lidt(idt, sizeof(idt)-1);
856 	lldt(GSEL(GLDT_SEL, SEL_KPL));
857 
858 #ifdef notyet
859 	/* determine amount of memory present so we can scale kernel PT */
860 	for (i= RAM_BEGIN; i < IOM_BEGIN; i += NBPG)
861 		if (probemem(i) == 0) break;
862 	if (i == IOM_BEGIN) {
863 		if (maxphysmem == 0) maxphysmem = RAM_END;
864 		for (i= IOM_END; i < maxphysmem; i += NBPG)
865 			if (probemem(i) == 0) break;
866 	}
867 	maxmem = i / NBPG;
868 #else
869 Maxmem = 8192 *1024 /NBPG;
870 	maxmem = Maxmem;
871 #endif
872 
873 	/* reconcile against BIOS's recorded values in RTC
874 	 * we trust neither of them, as both can lie!
875 	 */
876 	biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
877 	biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
878 	if (biosbasemem == 0xffff || biosextmem == 0xffff) {
879 		if (maxmem > 0xffc)
880 			maxmem = 640/4;
881 	} else if (biosextmem > 0 && biosbasemem == 640) {
882 		int totbios = (biosbasemem + 0x60000 + biosextmem)/4;
883 		if (totbios < maxmem) maxmem = totbios;
884 	} else	maxmem = 640/4;
885 	maxmem = maxmem-1;
886 	physmem = maxmem - (0x100 -0xa0);
887 
888 	/* call pmap initialization to make new kernel address space */
889 	pmap_bootstrap (first, 0);
890 	/* now running on new page tables, configured,and u/iom is accessible */
891 
892 	/* make a initial tss so microp can get interrupt stack on syscall! */
893 	proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
894 	proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
895 	_gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
896 	ltr(_gsel_tss);
897 
898 	/* make a call gate to reenter kernel with */
899 	gdp = &ldt[LSYS5CALLS_SEL].gd;
900 
901 	x = (int) &IDTVEC(syscall);
902 	gdp->gd_looffset = x++;
903 	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
904 	gdp->gd_stkcpy = 0;
905 	gdp->gd_type = SDT_SYS386CGT;
906 	gdp->gd_dpl = SEL_UPL;
907 	gdp->gd_p = 1;
908 	gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
909 
910 	/* transfer to user mode */
911 
912 	_ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
913 	_udatasel = LSEL(LUDATA_SEL, SEL_UPL);
914 
915 	/* setup proc 0's pcb */
916 	bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
917 	proc0.p_addr->u_pcb.pcb_flags = 0;
918 	proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
919 }
920 
921 extern struct pte	*CMAP1, *CMAP2;
922 extern caddr_t		CADDR1, CADDR2;
923 /*
924  * zero out physical memory
925  * specified in relocation units (NBPG bytes)
926  */
927 clearseg(n) {
928 
929 	*(int *)CMAP2 = PG_V | PG_KW | ctob(n);
930 	load_cr3(rcr3());
931 	bzero(CADDR2,NBPG);
932 	*(int *) CADDR2 = 0;
933 }
934 
935 /*
936  * copy a page of physical memory
937  * specified in relocation units (NBPG bytes)
938  */
939 copyseg(frm, n) {
940 
941 	*(int *)CMAP2 = PG_V | PG_KW | ctob(n);
942 	load_cr3(rcr3());
943 	bcopy((void *)frm, (void *)CADDR2, NBPG);
944 }
945 
946 /*
947  * copy a page of physical memory
948  * specified in relocation units (NBPG bytes)
949  */
950 physcopyseg(frm, to) {
951 
952 	*(int *)CMAP1 = PG_V | PG_KW | ctob(frm);
953 	*(int *)CMAP2 = PG_V | PG_KW | ctob(to);
954 	load_cr3(rcr3());
955 	bcopy(CADDR1, CADDR2, NBPG);
956 }
957 
958 /*aston() {
959 	schednetisr(NETISR_AST);
960 }*/
961 
962 setsoftclock() {
963 	schednetisr(NETISR_SCLK);
964 }
965 
966 /*
967  * insert an element into a queue
968  */
969 #undef insque
970 _insque(element, head)
971 	register struct prochd *element, *head;
972 {
973 	element->ph_link = head->ph_link;
974 	head->ph_link = (struct proc *)element;
975 	element->ph_rlink = (struct proc *)head;
976 	((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
977 }
978 
979 /*
980  * remove an element from a queue
981  */
982 #undef remque
983 _remque(element)
984 	register struct prochd *element;
985 {
986 	((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
987 	((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
988 	element->ph_rlink = (struct proc *)0;
989 }
990 
991 vmunaccess() {}
992 
993 /*
994  * Below written in C to allow access to debugging code
995  */
996 copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
997 	void *toaddr, *fromaddr; {
998 	u_int c,tally;
999 
1000 	tally = 0;
1001 	while (maxlength--) {
1002 		c = fubyte(fromaddr++);
1003 		if (c == -1) {
1004 			if(lencopied) *lencopied = tally;
1005 			return(EFAULT);
1006 		}
1007 		tally++;
1008 		*(char *)toaddr++ = (char) c;
1009 		if (c == 0){
1010 			if(lencopied) *lencopied = tally;
1011 			return(0);
1012 		}
1013 	}
1014 	if(lencopied) *lencopied = tally;
1015 	return(ENAMETOOLONG);
1016 }
1017 
1018 copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
1019 	void *fromaddr, *toaddr; {
1020 	int c;
1021 	int tally;
1022 
1023 	tally = 0;
1024 	while (maxlength--) {
1025 		c = subyte(toaddr++, *(char *)fromaddr);
1026 		if (c == -1) return(EFAULT);
1027 		tally++;
1028 		if (*(char *)fromaddr++ == 0){
1029 			if(lencopied) *lencopied = tally;
1030 			return(0);
1031 		}
1032 	}
1033 	if(lencopied) *lencopied = tally;
1034 	return(ENAMETOOLONG);
1035 }
1036 
1037 copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
1038 	void *fromaddr, *toaddr; {
1039 	u_int tally;
1040 
1041 	tally = 0;
1042 	while (maxlength--) {
1043 		*(u_char *)toaddr = *(u_char *)fromaddr++;
1044 		tally++;
1045 		if (*(u_char *)toaddr++ == 0) {
1046 			if(lencopied) *lencopied = tally;
1047 			return(0);
1048 		}
1049 	}
1050 	if(lencopied) *lencopied = tally;
1051 	return(ENAMETOOLONG);
1052 }
1053