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