xref: /original-bsd/sys/i386/i386/machdep.c (revision b806d041)
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.15 (Berkeley) 10/11/92
11  */
12 
13 #include <sys/param.h>
14 #include <sys/systm.h>
15 #include <sys/signalvar.h>
16 #include <sys/kernel.h>
17 #include <sys/map.h>
18 #include <sys/proc.h>
19 #include <sys/user.h>
20 #include <sys/buf.h>
21 #include <sys/reboot.h>
22 #include <sys/conf.h>
23 #include <sys/file.h>
24 #include <sys/clist.h>
25 #include <sys/callout.h>
26 #include <sys/malloc.h>
27 #include <sys/mbuf.h>
28 #include <sys/msgbuf.h>
29 
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(kernel_pmap, 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 	callout[i-1].c_next = NULL;
233 
234 	/*printf("avail mem = %d\n", ptoa(vm_page_free_count));*/
235 	printf("using %d buffers containing %d bytes of memory\n",
236 		nbuf, bufpages * CLBYTES);
237 
238 	/*
239 	 * Set up CPU-specific registers, cache, etc.
240 	 */
241 	initcpu();
242 
243 	/*
244 	 * Set up buffers, so they can be used to read disk labels.
245 	 */
246 	bufinit();
247 
248 	/*
249 	 * Configure the system.
250 	 */
251 	configure();
252 }
253 
254 #ifdef PGINPROF
255 /*
256  * Return the difference (in microseconds)
257  * between the  current time and a previous
258  * time as represented  by the arguments.
259  * If there is a pending clock interrupt
260  * which has not been serviced due to high
261  * ipl, return error code.
262  */
263 /*ARGSUSED*/
264 vmtime(otime, olbolt, oicr)
265 	register int otime, olbolt, oicr;
266 {
267 
268 	return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
269 }
270 #endif
271 
272 struct sigframe {
273 	int	sf_signum;
274 	int	sf_code;
275 	struct	sigcontext *sf_scp;
276 	sig_t	sf_handler;
277 	int	sf_eax;
278 	int	sf_edx;
279 	int	sf_ecx;
280 	struct	sigcontext sf_sc;
281 } ;
282 
283 extern int kstack[];
284 
285 /*
286  * Send an interrupt to process.
287  *
288  * Stack is set up to allow sigcode stored
289  * in u. to call routine, followed by kcall
290  * to sigreturn routine below.  After sigreturn
291  * resets the signal mask, the stack, and the
292  * frame pointer, it returns to the user
293  * specified pc, psl.
294  */
295 void
296 sendsig(catcher, sig, mask, code)
297 	sig_t catcher;
298 	int sig, mask;
299 	unsigned code;
300 {
301 	register struct proc *p = curproc;
302 	register int *regs;
303 	register struct sigframe *fp;
304 	struct sigacts *psp = p->p_sigacts;
305 	int oonstack, frmtrap;
306 
307 	regs = p->p_md.md_regs;
308         oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK;
309 	frmtrap = curpcb->pcb_flags & FM_TRAP;
310 	/*
311 	 * Allocate and validate space for the signal handler
312 	 * context. Note that if the stack is in P0 space, the
313 	 * call to grow() is a nop, and the useracc() check
314 	 * will fail if the process has not already allocated
315 	 * the space with a `brk'.
316 	 */
317 	if ((psp->ps_flags & SAS_ALTSTACK) &&
318 	    (psp->ps_sigstk.ss_flags & SA_ONSTACK) == 0 &&
319 	    (psp->ps_sigonstack & sigmask(sig))) {
320 		fp = (struct sigframe *)(psp->ps_sigstk.ss_base +
321 		    psp->ps_sigstk.ss_size - sizeof(struct sigframe));
322 		psp->ps_sigstk.ss_flags |= SA_ONSTACK;
323 	} else {
324 		if (frmtrap)
325 			fp = (struct sigframe *)(regs[tESP]
326 				- sizeof(struct sigframe));
327 		else
328 			fp = (struct sigframe *)(regs[sESP]
329 				- sizeof(struct sigframe));
330 	}
331 
332 	if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize))
333 		(void)grow(p, (unsigned)fp);
334 
335 	if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) {
336 		/*
337 		 * Process has trashed its stack; give it an illegal
338 		 * instruction to halt it in its tracks.
339 		 */
340 		SIGACTION(p, SIGILL) = SIG_DFL;
341 		sig = sigmask(SIGILL);
342 		p->p_sigignore &= ~sig;
343 		p->p_sigcatch &= ~sig;
344 		p->p_sigmask &= ~sig;
345 		psignal(p, SIGILL);
346 		return;
347 	}
348 
349 	/*
350 	 * Build the argument list for the signal handler.
351 	 */
352 	fp->sf_signum = sig;
353 	fp->sf_code = code;
354 	fp->sf_scp = &fp->sf_sc;
355 	fp->sf_handler = catcher;
356 
357 	/* save scratch registers */
358 	if(frmtrap) {
359 		fp->sf_eax = regs[tEAX];
360 		fp->sf_edx = regs[tEDX];
361 		fp->sf_ecx = regs[tECX];
362 	} else {
363 		fp->sf_eax = regs[sEAX];
364 		fp->sf_edx = regs[sEDX];
365 		fp->sf_ecx = regs[sECX];
366 	}
367 	/*
368 	 * Build the signal context to be used by sigreturn.
369 	 */
370 	fp->sf_sc.sc_onstack = oonstack;
371 	fp->sf_sc.sc_mask = mask;
372 	if(frmtrap) {
373 		fp->sf_sc.sc_sp = regs[tESP];
374 		fp->sf_sc.sc_fp = regs[tEBP];
375 		fp->sf_sc.sc_pc = regs[tEIP];
376 		fp->sf_sc.sc_ps = regs[tEFLAGS];
377 		regs[tESP] = (int)fp;
378 		regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
379 	} else {
380 		fp->sf_sc.sc_sp = regs[sESP];
381 		fp->sf_sc.sc_fp = regs[sEBP];
382 		fp->sf_sc.sc_pc = regs[sEIP];
383 		fp->sf_sc.sc_ps = regs[sEFLAGS];
384 		regs[sESP] = (int)fp;
385 		regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
386 	}
387 }
388 
389 /*
390  * System call to cleanup state after a signal
391  * has been taken.  Reset signal mask and
392  * stack state from context left by sendsig (above).
393  * Return to previous pc and psl as specified by
394  * context left by sendsig. Check carefully to
395  * make sure that the user has not modified the
396  * psl to gain improper priviledges or to cause
397  * a machine fault.
398  */
399 struct sigreturn_args {
400 	struct sigcontext *sigcntxp;
401 };
402 sigreturn(p, uap, retval)
403 	struct proc *p;
404 	struct sigreturn_args *uap;
405 	int *retval;
406 {
407 	register struct sigcontext *scp;
408 	register struct sigframe *fp;
409 	register int *regs = p->p_md.md_regs;
410 
411 
412 	fp = (struct sigframe *) regs[sESP] ;
413 
414 	if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0)
415 		return(EINVAL);
416 
417 	/* restore scratch registers */
418 	regs[sEAX] = fp->sf_eax ;
419 	regs[sEDX] = fp->sf_edx ;
420 	regs[sECX] = fp->sf_ecx ;
421 
422 	scp = fp->sf_scp;
423 	if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
424 		return(EINVAL);
425 #ifdef notyet
426 	if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
427 		return(EINVAL);
428 	}
429 #endif
430 	if (scp->sc_onstack & 01)
431 		p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
432 	else
433 		p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
434 	p->p_sigmask = scp->sc_mask &~
435 	    (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
436 	regs[sEBP] = scp->sc_fp;
437 	regs[sESP] = scp->sc_sp;
438 	regs[sEIP] = scp->sc_pc;
439 	regs[sEFLAGS] = scp->sc_ps;
440 	return(EJUSTRETURN);
441 }
442 
443 int	waittime = -1;
444 
445 boot(arghowto)
446 	int arghowto;
447 {
448 	register long dummy;		/* r12 is reserved */
449 	register int howto;		/* r11 == how to boot */
450 	register int devtype;		/* r10 == major of root dev */
451 	extern char *panicstr;
452 extern int cold;
453 
454 	howto = arghowto;
455 	if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
456 		register struct buf *bp;
457 		int iter, nbusy;
458 
459 		waittime = 0;
460 		(void) splnet();
461 		printf("syncing disks... ");
462 		/*
463 		 * Release inodes held by texts before update.
464 		 */
465 		if (panicstr == 0)
466 			vnode_pager_umount(NULL);
467 		sync((struct sigcontext *)0);
468 
469 		for (iter = 0; iter < 20; iter++) {
470 			nbusy = 0;
471 			for (bp = &buf[nbuf]; --bp >= buf; )
472 				if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
473 					nbusy++;
474 			if (nbusy == 0)
475 				break;
476 			printf("%d ", nbusy);
477 			DELAY(40000 * iter);
478 		}
479 		if (nbusy)
480 			printf("giving up\n");
481 		else
482 			printf("done\n");
483 		DELAY(10000);			/* wait for printf to finish */
484 	}
485 	splhigh();
486 	devtype = major(rootdev);
487 	if (howto&RB_HALT) {
488 		printf("halting (in tight loop); hit reset\n\n");
489 		splx(0xfffd);	/* all but keyboard XXX */
490 		for (;;) ;
491 	} else {
492 		if (howto & RB_DUMP) {
493 			dumpsys();
494 			/*NOTREACHED*/
495 		}
496 	}
497 #ifdef lint
498 	dummy = 0; dummy = dummy;
499 	printf("howto %d, devtype %d\n", arghowto, devtype);
500 #endif
501 #ifdef	notdef
502 	pg("pausing (hit any key to reset)");
503 #endif
504 	reset_cpu();
505 	for(;;) ;
506 	/*NOTREACHED*/
507 }
508 
509 int	dumpmag = 0x8fca0101;	/* magic number for savecore */
510 int	dumpsize = 0;		/* also for savecore */
511 /*
512  * Doadump comes here after turning off memory management and
513  * getting on the dump stack, either when called above, or by
514  * the auto-restart code.
515  */
516 dumpsys()
517 {
518 
519 	if (dumpdev == NODEV)
520 		return;
521 	if ((minor(dumpdev)&07) != 1)
522 		return;
523 	dumpsize = physmem;
524 	printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
525 	printf("dump ");
526 	switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
527 
528 	case ENXIO:
529 		printf("device bad\n");
530 		break;
531 
532 	case EFAULT:
533 		printf("device not ready\n");
534 		break;
535 
536 	case EINVAL:
537 		printf("area improper\n");
538 		break;
539 
540 	case EIO:
541 		printf("i/o error\n");
542 		break;
543 
544 	default:
545 		printf("succeeded\n");
546 		break;
547 	}
548 	printf("\n\n");
549 	DELAY(1000);
550 }
551 
552 microtime(tvp)
553 	register struct timeval *tvp;
554 {
555 	int s = splhigh();
556 
557 	*tvp = time;
558 	tvp->tv_usec += tick;
559 	while (tvp->tv_usec > 1000000) {
560 		tvp->tv_sec++;
561 		tvp->tv_usec -= 1000000;
562 	}
563 	splx(s);
564 }
565 
566 physstrat(bp, strat, prio)
567 	struct buf *bp;
568 	int (*strat)(), prio;
569 {
570 	register int s;
571 	caddr_t baddr;
572 
573 	/*
574 	 * vmapbuf clobbers b_addr so we must remember it so that it
575 	 * can be restored after vunmapbuf.  This is truely rude, we
576 	 * should really be storing this in a field in the buf struct
577 	 * but none are available and I didn't want to add one at
578 	 * this time.  Note that b_addr for dirty page pushes is
579 	 * restored in vunmapbuf. (ugh!)
580 	 */
581 	baddr = bp->b_un.b_addr;
582 	vmapbuf(bp);
583 	(*strat)(bp);
584 	/* pageout daemon doesn't wait for pushed pages */
585 	if (bp->b_flags & B_DIRTY)
586 		return;
587 	s = splbio();
588 	while ((bp->b_flags & B_DONE) == 0)
589 		sleep((caddr_t)bp, prio);
590 	splx(s);
591 	vunmapbuf(bp);
592 	bp->b_un.b_addr = baddr;
593 }
594 
595 initcpu()
596 {
597 }
598 
599 /*
600  * Clear registers on exec
601  */
602 setregs(p, entry, retval)
603 	register struct proc *p;
604 	u_long entry;
605 	int retval[2];
606 {
607 	p->p_md.md_regs[sEBP] = 0;	/* bottom of the fp chain */
608 	p->p_md.md_regs[sEIP] = entry;
609 
610 	p->p_addr->u_pcb.pcb_flags = 0;	/* no fp at all */
611 	load_cr0(rcr0() | CR0_EM);	/* start emulating */
612 #include "npx.h"
613 #if NNPX > 0
614 	npxinit(0x262);
615 #endif
616 }
617 
618 /*
619  * Initialize 386 and configure to run kernel
620  */
621 
622 /*
623  * Initialize segments & interrupt table
624  */
625 
626 
627 #define	GNULL_SEL	0	/* Null Descriptor */
628 #define	GCODE_SEL	1	/* Kernel Code Descriptor */
629 #define	GDATA_SEL	2	/* Kernel Data Descriptor */
630 #define	GLDT_SEL	3	/* LDT - eventually one per process */
631 #define	GTGATE_SEL	4	/* Process task switch gate */
632 #define	GPANIC_SEL	5	/* Task state to consider panic from */
633 #define	GPROC0_SEL	6	/* Task state process slot zero and up */
634 #define NGDT 	GPROC0_SEL+1
635 
636 union descriptor gdt[GPROC0_SEL+1];
637 
638 /* interrupt descriptor table */
639 struct gate_descriptor idt[32+16];
640 
641 /* local descriptor table */
642 union descriptor ldt[5];
643 #define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
644 #define	LSYS5SIGR_SEL	1
645 
646 #define	L43BSDCALLS_SEL	2	/* notyet */
647 #define	LUCODE_SEL	3
648 #define	LUDATA_SEL	4
649 /* seperate stack, es,fs,gs sels ? */
650 /* #define	LPOSIXCALLS_SEL	5	/* notyet */
651 
652 struct	i386tss	tss, panic_tss;
653 
654 extern  struct user *proc0paddr;
655 
656 /* software prototypes -- in more palitable form */
657 struct soft_segment_descriptor gdt_segs[] = {
658 	/* Null Descriptor */
659 {	0x0,			/* segment base address  */
660 	0x0,			/* length - all address space */
661 	0,			/* segment type */
662 	0,			/* segment descriptor priority level */
663 	0,			/* segment descriptor present */
664 	0,0,
665 	0,			/* default 32 vs 16 bit size */
666 	0  			/* limit granularity (byte/page units)*/ },
667 	/* Code Descriptor for kernel */
668 {	0x0,			/* segment base address  */
669 	0xfffff,		/* length - all address space */
670 	SDT_MEMERA,		/* segment type */
671 	0,			/* segment descriptor priority level */
672 	1,			/* segment descriptor present */
673 	0,0,
674 	1,			/* default 32 vs 16 bit size */
675 	1  			/* limit granularity (byte/page units)*/ },
676 	/* Data Descriptor for kernel */
677 {	0x0,			/* segment base address  */
678 	0xfffff,		/* length - all address space */
679 	SDT_MEMRWA,		/* segment type */
680 	0,			/* segment descriptor priority level */
681 	1,			/* segment descriptor present */
682 	0,0,
683 	1,			/* default 32 vs 16 bit size */
684 	1  			/* limit granularity (byte/page units)*/ },
685 	/* LDT Descriptor */
686 {	(int) ldt,			/* segment base address  */
687 	sizeof(ldt)-1,		/* length - all address space */
688 	SDT_SYSLDT,		/* segment type */
689 	0,			/* segment descriptor priority level */
690 	1,			/* segment descriptor present */
691 	0,0,
692 	0,			/* unused - default 32 vs 16 bit size */
693 	0  			/* limit granularity (byte/page units)*/ },
694 	/* Null Descriptor - Placeholder */
695 {	0x0,			/* segment base address  */
696 	0x0,			/* length - all address space */
697 	0,			/* segment type */
698 	0,			/* segment descriptor priority level */
699 	0,			/* segment descriptor present */
700 	0,0,
701 	0,			/* default 32 vs 16 bit size */
702 	0  			/* limit granularity (byte/page units)*/ },
703 	/* Panic Tss Descriptor */
704 {	(int) &panic_tss,		/* segment base address  */
705 	sizeof(tss)-1,		/* length - all address space */
706 	SDT_SYS386TSS,		/* segment type */
707 	0,			/* segment descriptor priority level */
708 	1,			/* segment descriptor present */
709 	0,0,
710 	0,			/* unused - default 32 vs 16 bit size */
711 	0  			/* limit granularity (byte/page units)*/ },
712 	/* Proc 0 Tss Descriptor */
713 {	(int) kstack,			/* segment base address  */
714 	sizeof(tss)-1,		/* length - all address space */
715 	SDT_SYS386TSS,		/* segment type */
716 	0,			/* segment descriptor priority level */
717 	1,			/* segment descriptor present */
718 	0,0,
719 	0,			/* unused - default 32 vs 16 bit size */
720 	0  			/* limit granularity (byte/page units)*/ }};
721 
722 struct soft_segment_descriptor ldt_segs[] = {
723 	/* Null Descriptor - overwritten by call gate */
724 {	0x0,			/* segment base address  */
725 	0x0,			/* length - all address space */
726 	0,			/* segment type */
727 	0,			/* segment descriptor priority level */
728 	0,			/* segment descriptor present */
729 	0,0,
730 	0,			/* default 32 vs 16 bit size */
731 	0  			/* limit granularity (byte/page units)*/ },
732 	/* Null Descriptor - overwritten by call gate */
733 {	0x0,			/* segment base address  */
734 	0x0,			/* length - all address space */
735 	0,			/* segment type */
736 	0,			/* segment descriptor priority level */
737 	0,			/* segment descriptor present */
738 	0,0,
739 	0,			/* default 32 vs 16 bit size */
740 	0  			/* limit granularity (byte/page units)*/ },
741 	/* Null Descriptor - overwritten by call gate */
742 {	0x0,			/* segment base address  */
743 	0x0,			/* length - all address space */
744 	0,			/* segment type */
745 	0,			/* segment descriptor priority level */
746 	0,			/* segment descriptor present */
747 	0,0,
748 	0,			/* default 32 vs 16 bit size */
749 	0  			/* limit granularity (byte/page units)*/ },
750 	/* Code Descriptor for user */
751 {	0x0,			/* segment base address  */
752 	0xfffff,		/* length - all address space */
753 	SDT_MEMERA,		/* segment type */
754 	SEL_UPL,		/* segment descriptor priority level */
755 	1,			/* segment descriptor present */
756 	0,0,
757 	1,			/* default 32 vs 16 bit size */
758 	1  			/* limit granularity (byte/page units)*/ },
759 	/* Data Descriptor for user */
760 {	0x0,			/* segment base address  */
761 	0xfffff,		/* length - all address space */
762 	SDT_MEMRWA,		/* segment type */
763 	SEL_UPL,		/* segment descriptor priority level */
764 	1,			/* segment descriptor present */
765 	0,0,
766 	1,			/* default 32 vs 16 bit size */
767 	1  			/* limit granularity (byte/page units)*/ } };
768 
769 /* table descriptors - used to load tables by microp */
770 struct region_descriptor r_gdt = {
771 	sizeof(gdt)-1,(char *)gdt
772 };
773 
774 struct region_descriptor r_idt = {
775 	sizeof(idt)-1,(char *)idt
776 };
777 
778 setidt(idx, func, typ, dpl) char *func; {
779 	struct gate_descriptor *ip = idt + idx;
780 
781 	ip->gd_looffset = (int)func;
782 	ip->gd_selector = 8;
783 	ip->gd_stkcpy = 0;
784 	ip->gd_xx = 0;
785 	ip->gd_type = typ;
786 	ip->gd_dpl = dpl;
787 	ip->gd_p = 1;
788 	ip->gd_hioffset = ((int)func)>>16 ;
789 }
790 
791 #define	IDTVEC(name)	__CONCAT(X, name)
792 extern	IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
793 	IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
794 	IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
795 	IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
796 	IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
797 	IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
798 	IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
799 	IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
800 
801 int lcr0(), lcr3(), rcr0(), rcr2();
802 int _udatasel, _ucodesel, _gsel_tss;
803 
804 init386(first) { extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
805 	int x, *pi;
806 	unsigned biosbasemem, biosextmem;
807 	struct gate_descriptor *gdp;
808 	extern int sigcode,szsigcode;
809 
810 	proc0.p_addr = proc0paddr;
811 
812 	/*
813 	 * Initialize the console before we print anything out.
814 	 */
815 
816 	cninit (KERNBASE+0xa0000);
817 
818 	/* make gdt memory segments */
819 	gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
820 	for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
821 	/* make ldt memory segments */
822 	ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
823 	ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
824 	/* Note. eventually want private ldts per process */
825 	for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
826 
827 	/* exceptions */
828 	setidt(0, &IDTVEC(div),  SDT_SYS386TGT, SEL_KPL);
829 	setidt(1, &IDTVEC(dbg),  SDT_SYS386TGT, SEL_KPL);
830 	setidt(2, &IDTVEC(nmi),  SDT_SYS386TGT, SEL_KPL);
831  	setidt(3, &IDTVEC(bpt),  SDT_SYS386TGT, SEL_UPL);
832 	setidt(4, &IDTVEC(ofl),  SDT_SYS386TGT, SEL_KPL);
833 	setidt(5, &IDTVEC(bnd),  SDT_SYS386TGT, SEL_KPL);
834 	setidt(6, &IDTVEC(ill),  SDT_SYS386TGT, SEL_KPL);
835 	setidt(7, &IDTVEC(dna),  SDT_SYS386TGT, SEL_KPL);
836 	setidt(8, &IDTVEC(dble),  SDT_SYS386TGT, SEL_KPL);
837 	setidt(9, &IDTVEC(fpusegm),  SDT_SYS386TGT, SEL_KPL);
838 	setidt(10, &IDTVEC(tss),  SDT_SYS386TGT, SEL_KPL);
839 	setidt(11, &IDTVEC(missing),  SDT_SYS386TGT, SEL_KPL);
840 	setidt(12, &IDTVEC(stk),  SDT_SYS386TGT, SEL_KPL);
841 	setidt(13, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL);
842 	setidt(14, &IDTVEC(page),  SDT_SYS386TGT, SEL_KPL);
843 	setidt(15, &IDTVEC(rsvd),  SDT_SYS386TGT, SEL_KPL);
844 	setidt(16, &IDTVEC(fpu),  SDT_SYS386TGT, SEL_KPL);
845 	setidt(17, &IDTVEC(rsvd0),  SDT_SYS386TGT, SEL_KPL);
846 	setidt(18, &IDTVEC(rsvd1),  SDT_SYS386TGT, SEL_KPL);
847 	setidt(19, &IDTVEC(rsvd2),  SDT_SYS386TGT, SEL_KPL);
848 	setidt(20, &IDTVEC(rsvd3),  SDT_SYS386TGT, SEL_KPL);
849 	setidt(21, &IDTVEC(rsvd4),  SDT_SYS386TGT, SEL_KPL);
850 	setidt(22, &IDTVEC(rsvd5),  SDT_SYS386TGT, SEL_KPL);
851 	setidt(23, &IDTVEC(rsvd6),  SDT_SYS386TGT, SEL_KPL);
852 	setidt(24, &IDTVEC(rsvd7),  SDT_SYS386TGT, SEL_KPL);
853 	setidt(25, &IDTVEC(rsvd8),  SDT_SYS386TGT, SEL_KPL);
854 	setidt(26, &IDTVEC(rsvd9),  SDT_SYS386TGT, SEL_KPL);
855 	setidt(27, &IDTVEC(rsvd10),  SDT_SYS386TGT, SEL_KPL);
856 	setidt(28, &IDTVEC(rsvd11),  SDT_SYS386TGT, SEL_KPL);
857 	setidt(29, &IDTVEC(rsvd12),  SDT_SYS386TGT, SEL_KPL);
858 	setidt(30, &IDTVEC(rsvd13),  SDT_SYS386TGT, SEL_KPL);
859 	setidt(31, &IDTVEC(rsvd14),  SDT_SYS386TGT, SEL_KPL);
860 
861 #include "isa.h"
862 #if	NISA >0
863 	isa_defaultirq();
864 #endif
865 
866 	lgdt(gdt, sizeof(gdt)-1);
867 	lidt(idt, sizeof(idt)-1);
868 	lldt(GSEL(GLDT_SEL, SEL_KPL));
869 
870 	/*
871 	 * This memory size stuff is a real mess.  Here is a simple
872 	 * setup that just believes the BIOS.  After the rest of
873 	 * the system is a little more stable, we'll come back to
874 	 * this and deal with issues if incorrect BIOS information,
875 	 * and when physical memory is > 16 megabytes.
876 	 */
877 	biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
878 	biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
879 	Maxmem = btoc ((biosextmem + 1024) * 1024);
880 	maxmem = Maxmem - 1;
881 	physmem = btoc (biosbasemem * 1024 + (biosextmem - 1) * 1024);
882 	printf ("bios %dK+%dK. maxmem %x, physmem %x\n",
883 		biosbasemem, biosextmem, ctob (maxmem), ctob (physmem));
884 
885 	vm_set_page_size();
886 	/* call pmap initialization to make new kernel address space */
887 	pmap_bootstrap (first, 0);
888 	/* now running on new page tables, configured,and u/iom is accessible */
889 
890 	/* make a initial tss so microp can get interrupt stack on syscall! */
891 	proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
892 	proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
893 	_gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
894 	ltr(_gsel_tss);
895 
896 	/* make a call gate to reenter kernel with */
897 	gdp = &ldt[LSYS5CALLS_SEL].gd;
898 
899 	x = (int) &IDTVEC(syscall);
900 	gdp->gd_looffset = x++;
901 	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
902 	gdp->gd_stkcpy = 0;
903 	gdp->gd_type = SDT_SYS386CGT;
904 	gdp->gd_dpl = SEL_UPL;
905 	gdp->gd_p = 1;
906 	gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
907 
908 	/* transfer to user mode */
909 
910 	_ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
911 	_udatasel = LSEL(LUDATA_SEL, SEL_UPL);
912 
913 	/* setup proc 0's pcb */
914 	bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
915 	proc0.p_addr->u_pcb.pcb_flags = 0;
916 	proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
917 }
918 
919 extern struct pte	*CMAP1, *CMAP2;
920 extern caddr_t		CADDR1, CADDR2;
921 /*
922  * zero out physical memory
923  * specified in relocation units (NBPG bytes)
924  */
925 clearseg(n) {
926 
927 	*(int *)CMAP2 = PG_V | PG_KW | ctob(n);
928 	load_cr3(rcr3());
929 	bzero(CADDR2,NBPG);
930 	*(int *) CADDR2 = 0;
931 }
932 
933 /*
934  * copy a page of physical memory
935  * specified in relocation units (NBPG bytes)
936  */
937 copyseg(frm, n) {
938 
939 	*(int *)CMAP2 = PG_V | PG_KW | ctob(n);
940 	load_cr3(rcr3());
941 	bcopy((void *)frm, (void *)CADDR2, NBPG);
942 }
943 
944 /*
945  * copy a page of physical memory
946  * specified in relocation units (NBPG bytes)
947  */
948 physcopyseg(frm, to) {
949 
950 	*(int *)CMAP1 = PG_V | PG_KW | ctob(frm);
951 	*(int *)CMAP2 = PG_V | PG_KW | ctob(to);
952 	load_cr3(rcr3());
953 	bcopy(CADDR1, CADDR2, NBPG);
954 }
955 
956 /*aston() {
957 	schednetisr(NETISR_AST);
958 }*/
959 
960 setsoftclock() {
961 	schednetisr(NETISR_SCLK);
962 }
963 
964 /*
965  * insert an element into a queue
966  */
967 #undef insque
968 _insque(element, head)
969 	register struct prochd *element, *head;
970 {
971 	element->ph_link = head->ph_link;
972 	head->ph_link = (struct proc *)element;
973 	element->ph_rlink = (struct proc *)head;
974 	((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
975 }
976 
977 /*
978  * remove an element from a queue
979  */
980 #undef remque
981 _remque(element)
982 	register struct prochd *element;
983 {
984 	((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
985 	((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
986 	element->ph_rlink = (struct proc *)0;
987 }
988 
989 vmunaccess() {}
990 
991 /*
992  * Below written in C to allow access to debugging code
993  */
994 copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
995 	void *toaddr, *fromaddr; {
996 	int c,tally;
997 
998 	tally = 0;
999 	while (maxlength--) {
1000 		c = fubyte(fromaddr++);
1001 		if (c == -1) {
1002 			if(lencopied) *lencopied = tally;
1003 			return(EFAULT);
1004 		}
1005 		tally++;
1006 		*(char *)toaddr++ = (char) c;
1007 		if (c == 0){
1008 			if(lencopied) *lencopied = tally;
1009 			return(0);
1010 		}
1011 	}
1012 	if(lencopied) *lencopied = tally;
1013 	return(ENAMETOOLONG);
1014 }
1015 
1016 copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
1017 	void *fromaddr, *toaddr; {
1018 	int c;
1019 	int tally;
1020 
1021 	tally = 0;
1022 	while (maxlength--) {
1023 		c = subyte(toaddr++, *(char *)fromaddr);
1024 		if (c == -1) return(EFAULT);
1025 		tally++;
1026 		if (*(char *)fromaddr++ == 0){
1027 			if(lencopied) *lencopied = tally;
1028 			return(0);
1029 		}
1030 	}
1031 	if(lencopied) *lencopied = tally;
1032 	return(ENAMETOOLONG);
1033 }
1034 
1035 copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
1036 	void *fromaddr, *toaddr; {
1037 	u_int tally;
1038 
1039 	tally = 0;
1040 	while (maxlength--) {
1041 		*(u_char *)toaddr = *(u_char *)fromaddr++;
1042 		tally++;
1043 		if (*(u_char *)toaddr++ == 0) {
1044 			if(lencopied) *lencopied = tally;
1045 			return(0);
1046 		}
1047 	}
1048 	if(lencopied) *lencopied = tally;
1049 	return(ENAMETOOLONG);
1050 }
1051