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