xref: /original-bsd/sys/i386/i386/machdep.c (revision 68d9582f)
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.13 (Berkeley) 05/11/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(p, (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 #include "npx.h"
611 #if NNPX > 0
612 	npxinit(0x262);
613 #endif
614 }
615 
616 /*
617  * Initialize 386 and configure to run kernel
618  */
619 
620 /*
621  * Initialize segments & interrupt table
622  */
623 
624 
625 #define	GNULL_SEL	0	/* Null Descriptor */
626 #define	GCODE_SEL	1	/* Kernel Code Descriptor */
627 #define	GDATA_SEL	2	/* Kernel Data Descriptor */
628 #define	GLDT_SEL	3	/* LDT - eventually one per process */
629 #define	GTGATE_SEL	4	/* Process task switch gate */
630 #define	GPANIC_SEL	5	/* Task state to consider panic from */
631 #define	GPROC0_SEL	6	/* Task state process slot zero and up */
632 #define NGDT 	GPROC0_SEL+1
633 
634 union descriptor gdt[GPROC0_SEL+1];
635 
636 /* interrupt descriptor table */
637 struct gate_descriptor idt[32+16];
638 
639 /* local descriptor table */
640 union descriptor ldt[5];
641 #define	LSYS5CALLS_SEL	0	/* forced by intel BCS */
642 #define	LSYS5SIGR_SEL	1
643 
644 #define	L43BSDCALLS_SEL	2	/* notyet */
645 #define	LUCODE_SEL	3
646 #define	LUDATA_SEL	4
647 /* seperate stack, es,fs,gs sels ? */
648 /* #define	LPOSIXCALLS_SEL	5	/* notyet */
649 
650 struct	i386tss	tss, panic_tss;
651 
652 extern  struct user *proc0paddr;
653 
654 /* software prototypes -- in more palitable form */
655 struct soft_segment_descriptor gdt_segs[] = {
656 	/* Null Descriptor */
657 {	0x0,			/* segment base address  */
658 	0x0,			/* length - all address space */
659 	0,			/* segment type */
660 	0,			/* segment descriptor priority level */
661 	0,			/* segment descriptor present */
662 	0,0,
663 	0,			/* default 32 vs 16 bit size */
664 	0  			/* limit granularity (byte/page units)*/ },
665 	/* Code Descriptor for kernel */
666 {	0x0,			/* segment base address  */
667 	0xfffff,		/* length - all address space */
668 	SDT_MEMERA,		/* segment type */
669 	0,			/* segment descriptor priority level */
670 	1,			/* segment descriptor present */
671 	0,0,
672 	1,			/* default 32 vs 16 bit size */
673 	1  			/* limit granularity (byte/page units)*/ },
674 	/* Data Descriptor for kernel */
675 {	0x0,			/* segment base address  */
676 	0xfffff,		/* length - all address space */
677 	SDT_MEMRWA,		/* segment type */
678 	0,			/* segment descriptor priority level */
679 	1,			/* segment descriptor present */
680 	0,0,
681 	1,			/* default 32 vs 16 bit size */
682 	1  			/* limit granularity (byte/page units)*/ },
683 	/* LDT Descriptor */
684 {	(int) ldt,			/* segment base address  */
685 	sizeof(ldt)-1,		/* length - all address space */
686 	SDT_SYSLDT,		/* segment type */
687 	0,			/* segment descriptor priority level */
688 	1,			/* segment descriptor present */
689 	0,0,
690 	0,			/* unused - default 32 vs 16 bit size */
691 	0  			/* limit granularity (byte/page units)*/ },
692 	/* Null Descriptor - Placeholder */
693 {	0x0,			/* segment base address  */
694 	0x0,			/* length - all address space */
695 	0,			/* segment type */
696 	0,			/* segment descriptor priority level */
697 	0,			/* segment descriptor present */
698 	0,0,
699 	0,			/* default 32 vs 16 bit size */
700 	0  			/* limit granularity (byte/page units)*/ },
701 	/* Panic Tss Descriptor */
702 {	(int) &panic_tss,		/* segment base address  */
703 	sizeof(tss)-1,		/* length - all address space */
704 	SDT_SYS386TSS,		/* segment type */
705 	0,			/* segment descriptor priority level */
706 	1,			/* segment descriptor present */
707 	0,0,
708 	0,			/* unused - default 32 vs 16 bit size */
709 	0  			/* limit granularity (byte/page units)*/ },
710 	/* Proc 0 Tss Descriptor */
711 {	(int) kstack,			/* segment base address  */
712 	sizeof(tss)-1,		/* length - all address space */
713 	SDT_SYS386TSS,		/* segment type */
714 	0,			/* segment descriptor priority level */
715 	1,			/* segment descriptor present */
716 	0,0,
717 	0,			/* unused - default 32 vs 16 bit size */
718 	0  			/* limit granularity (byte/page units)*/ }};
719 
720 struct soft_segment_descriptor ldt_segs[] = {
721 	/* Null Descriptor - overwritten by call gate */
722 {	0x0,			/* segment base address  */
723 	0x0,			/* length - all address space */
724 	0,			/* segment type */
725 	0,			/* segment descriptor priority level */
726 	0,			/* segment descriptor present */
727 	0,0,
728 	0,			/* default 32 vs 16 bit size */
729 	0  			/* limit granularity (byte/page units)*/ },
730 	/* Null Descriptor - overwritten by call gate */
731 {	0x0,			/* segment base address  */
732 	0x0,			/* length - all address space */
733 	0,			/* segment type */
734 	0,			/* segment descriptor priority level */
735 	0,			/* segment descriptor present */
736 	0,0,
737 	0,			/* default 32 vs 16 bit size */
738 	0  			/* limit granularity (byte/page units)*/ },
739 	/* Null Descriptor - overwritten by call gate */
740 {	0x0,			/* segment base address  */
741 	0x0,			/* length - all address space */
742 	0,			/* segment type */
743 	0,			/* segment descriptor priority level */
744 	0,			/* segment descriptor present */
745 	0,0,
746 	0,			/* default 32 vs 16 bit size */
747 	0  			/* limit granularity (byte/page units)*/ },
748 	/* Code Descriptor for user */
749 {	0x0,			/* segment base address  */
750 	0xfffff,		/* length - all address space */
751 	SDT_MEMERA,		/* segment type */
752 	SEL_UPL,		/* segment descriptor priority level */
753 	1,			/* segment descriptor present */
754 	0,0,
755 	1,			/* default 32 vs 16 bit size */
756 	1  			/* limit granularity (byte/page units)*/ },
757 	/* Data Descriptor for user */
758 {	0x0,			/* segment base address  */
759 	0xfffff,		/* length - all address space */
760 	SDT_MEMRWA,		/* segment type */
761 	SEL_UPL,		/* segment descriptor priority level */
762 	1,			/* segment descriptor present */
763 	0,0,
764 	1,			/* default 32 vs 16 bit size */
765 	1  			/* limit granularity (byte/page units)*/ } };
766 
767 /* table descriptors - used to load tables by microp */
768 struct region_descriptor r_gdt = {
769 	sizeof(gdt)-1,(char *)gdt
770 };
771 
772 struct region_descriptor r_idt = {
773 	sizeof(idt)-1,(char *)idt
774 };
775 
776 setidt(idx, func, typ, dpl) char *func; {
777 	struct gate_descriptor *ip = idt + idx;
778 
779 	ip->gd_looffset = (int)func;
780 	ip->gd_selector = 8;
781 	ip->gd_stkcpy = 0;
782 	ip->gd_xx = 0;
783 	ip->gd_type = typ;
784 	ip->gd_dpl = dpl;
785 	ip->gd_p = 1;
786 	ip->gd_hioffset = ((int)func)>>16 ;
787 }
788 
789 #define	IDTVEC(name)	__CONCAT(X, name)
790 extern	IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
791 	IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
792 	IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
793 	IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
794 	IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
795 	IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
796 	IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
797 	IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
798 
799 int lcr0(), lcr3(), rcr0(), rcr2();
800 int _udatasel, _ucodesel, _gsel_tss;
801 
802 init386(first) { extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
803 	int x, *pi;
804 	unsigned biosbasemem, biosextmem;
805 	struct gate_descriptor *gdp;
806 	extern int sigcode,szsigcode;
807 
808 	proc0.p_addr = proc0paddr;
809 
810 	/*
811 	 * Initialize the console before we print anything out.
812 	 */
813 
814 	cninit (KERNBASE+0xa0000);
815 
816 	/* make gdt memory segments */
817 	gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
818 	for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
819 	/* make ldt memory segments */
820 	ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
821 	ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
822 	/* Note. eventually want private ldts per process */
823 	for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
824 
825 	/* exceptions */
826 	setidt(0, &IDTVEC(div),  SDT_SYS386TGT, SEL_KPL);
827 	setidt(1, &IDTVEC(dbg),  SDT_SYS386TGT, SEL_KPL);
828 	setidt(2, &IDTVEC(nmi),  SDT_SYS386TGT, SEL_KPL);
829  	setidt(3, &IDTVEC(bpt),  SDT_SYS386TGT, SEL_UPL);
830 	setidt(4, &IDTVEC(ofl),  SDT_SYS386TGT, SEL_KPL);
831 	setidt(5, &IDTVEC(bnd),  SDT_SYS386TGT, SEL_KPL);
832 	setidt(6, &IDTVEC(ill),  SDT_SYS386TGT, SEL_KPL);
833 	setidt(7, &IDTVEC(dna),  SDT_SYS386TGT, SEL_KPL);
834 	setidt(8, &IDTVEC(dble),  SDT_SYS386TGT, SEL_KPL);
835 	setidt(9, &IDTVEC(fpusegm),  SDT_SYS386TGT, SEL_KPL);
836 	setidt(10, &IDTVEC(tss),  SDT_SYS386TGT, SEL_KPL);
837 	setidt(11, &IDTVEC(missing),  SDT_SYS386TGT, SEL_KPL);
838 	setidt(12, &IDTVEC(stk),  SDT_SYS386TGT, SEL_KPL);
839 	setidt(13, &IDTVEC(prot),  SDT_SYS386TGT, SEL_KPL);
840 	setidt(14, &IDTVEC(page),  SDT_SYS386TGT, SEL_KPL);
841 	setidt(15, &IDTVEC(rsvd),  SDT_SYS386TGT, SEL_KPL);
842 	setidt(16, &IDTVEC(fpu),  SDT_SYS386TGT, SEL_KPL);
843 	setidt(17, &IDTVEC(rsvd0),  SDT_SYS386TGT, SEL_KPL);
844 	setidt(18, &IDTVEC(rsvd1),  SDT_SYS386TGT, SEL_KPL);
845 	setidt(19, &IDTVEC(rsvd2),  SDT_SYS386TGT, SEL_KPL);
846 	setidt(20, &IDTVEC(rsvd3),  SDT_SYS386TGT, SEL_KPL);
847 	setidt(21, &IDTVEC(rsvd4),  SDT_SYS386TGT, SEL_KPL);
848 	setidt(22, &IDTVEC(rsvd5),  SDT_SYS386TGT, SEL_KPL);
849 	setidt(23, &IDTVEC(rsvd6),  SDT_SYS386TGT, SEL_KPL);
850 	setidt(24, &IDTVEC(rsvd7),  SDT_SYS386TGT, SEL_KPL);
851 	setidt(25, &IDTVEC(rsvd8),  SDT_SYS386TGT, SEL_KPL);
852 	setidt(26, &IDTVEC(rsvd9),  SDT_SYS386TGT, SEL_KPL);
853 	setidt(27, &IDTVEC(rsvd10),  SDT_SYS386TGT, SEL_KPL);
854 	setidt(28, &IDTVEC(rsvd11),  SDT_SYS386TGT, SEL_KPL);
855 	setidt(29, &IDTVEC(rsvd12),  SDT_SYS386TGT, SEL_KPL);
856 	setidt(30, &IDTVEC(rsvd13),  SDT_SYS386TGT, SEL_KPL);
857 	setidt(31, &IDTVEC(rsvd14),  SDT_SYS386TGT, SEL_KPL);
858 
859 #include	"isa.h"
860 #if	NISA >0
861 	isa_defaultirq();
862 #endif
863 
864 	lgdt(gdt, sizeof(gdt)-1);
865 	lidt(idt, sizeof(idt)-1);
866 	lldt(GSEL(GLDT_SEL, SEL_KPL));
867 
868 	/*
869 	 * This memory size stuff is a real mess.  Here is a simple
870 	 * setup that just believes the BIOS.  After the rest of
871 	 * the system is a little more stable, we'll come back to
872 	 * this and deal with issues if incorrect BIOS information,
873 	 * and when physical memory is > 16 megabytes.
874 	 */
875 	biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
876 	biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
877 	Maxmem = btoc ((biosextmem + 1024) * 1024);
878 	maxmem = Maxmem - 1;
879 	physmem = btoc (biosbasemem * 1024 + (biosextmem - 1) * 1024);
880 	printf ("bios %dK+%dK. maxmem %x, physmem %x\n",
881 		biosbasemem, biosextmem, ctob (maxmem), ctob (physmem));
882 
883 	vm_set_page_size();
884 	/* call pmap initialization to make new kernel address space */
885 	pmap_bootstrap (first, 0);
886 	/* now running on new page tables, configured,and u/iom is accessible */
887 
888 	/* make a initial tss so microp can get interrupt stack on syscall! */
889 	proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
890 	proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
891 	_gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
892 	ltr(_gsel_tss);
893 
894 	/* make a call gate to reenter kernel with */
895 	gdp = &ldt[LSYS5CALLS_SEL].gd;
896 
897 	x = (int) &IDTVEC(syscall);
898 	gdp->gd_looffset = x++;
899 	gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
900 	gdp->gd_stkcpy = 0;
901 	gdp->gd_type = SDT_SYS386CGT;
902 	gdp->gd_dpl = SEL_UPL;
903 	gdp->gd_p = 1;
904 	gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
905 
906 	/* transfer to user mode */
907 
908 	_ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
909 	_udatasel = LSEL(LUDATA_SEL, SEL_UPL);
910 
911 	/* setup proc 0's pcb */
912 	bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
913 	proc0.p_addr->u_pcb.pcb_flags = 0;
914 	proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
915 }
916 
917 extern struct pte	*CMAP1, *CMAP2;
918 extern caddr_t		CADDR1, CADDR2;
919 /*
920  * zero out physical memory
921  * specified in relocation units (NBPG bytes)
922  */
923 clearseg(n) {
924 
925 	*(int *)CMAP2 = PG_V | PG_KW | ctob(n);
926 	load_cr3(rcr3());
927 	bzero(CADDR2,NBPG);
928 	*(int *) CADDR2 = 0;
929 }
930 
931 /*
932  * copy a page of physical memory
933  * specified in relocation units (NBPG bytes)
934  */
935 copyseg(frm, n) {
936 
937 	*(int *)CMAP2 = PG_V | PG_KW | ctob(n);
938 	load_cr3(rcr3());
939 	bcopy((void *)frm, (void *)CADDR2, NBPG);
940 }
941 
942 /*
943  * copy a page of physical memory
944  * specified in relocation units (NBPG bytes)
945  */
946 physcopyseg(frm, to) {
947 
948 	*(int *)CMAP1 = PG_V | PG_KW | ctob(frm);
949 	*(int *)CMAP2 = PG_V | PG_KW | ctob(to);
950 	load_cr3(rcr3());
951 	bcopy(CADDR1, CADDR2, NBPG);
952 }
953 
954 /*aston() {
955 	schednetisr(NETISR_AST);
956 }*/
957 
958 setsoftclock() {
959 	schednetisr(NETISR_SCLK);
960 }
961 
962 /*
963  * insert an element into a queue
964  */
965 #undef insque
966 _insque(element, head)
967 	register struct prochd *element, *head;
968 {
969 	element->ph_link = head->ph_link;
970 	head->ph_link = (struct proc *)element;
971 	element->ph_rlink = (struct proc *)head;
972 	((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
973 }
974 
975 /*
976  * remove an element from a queue
977  */
978 #undef remque
979 _remque(element)
980 	register struct prochd *element;
981 {
982 	((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
983 	((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
984 	element->ph_rlink = (struct proc *)0;
985 }
986 
987 vmunaccess() {}
988 
989 /*
990  * Below written in C to allow access to debugging code
991  */
992 copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
993 	void *toaddr, *fromaddr; {
994 	int c,tally;
995 
996 	tally = 0;
997 	while (maxlength--) {
998 		c = fubyte(fromaddr++);
999 		if (c == -1) {
1000 			if(lencopied) *lencopied = tally;
1001 			return(EFAULT);
1002 		}
1003 		tally++;
1004 		*(char *)toaddr++ = (char) c;
1005 		if (c == 0){
1006 			if(lencopied) *lencopied = tally;
1007 			return(0);
1008 		}
1009 	}
1010 	if(lencopied) *lencopied = tally;
1011 	return(ENAMETOOLONG);
1012 }
1013 
1014 copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
1015 	void *fromaddr, *toaddr; {
1016 	int c;
1017 	int tally;
1018 
1019 	tally = 0;
1020 	while (maxlength--) {
1021 		c = subyte(toaddr++, *(char *)fromaddr);
1022 		if (c == -1) return(EFAULT);
1023 		tally++;
1024 		if (*(char *)fromaddr++ == 0){
1025 			if(lencopied) *lencopied = tally;
1026 			return(0);
1027 		}
1028 	}
1029 	if(lencopied) *lencopied = tally;
1030 	return(ENAMETOOLONG);
1031 }
1032 
1033 copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
1034 	void *fromaddr, *toaddr; {
1035 	u_int tally;
1036 
1037 	tally = 0;
1038 	while (maxlength--) {
1039 		*(u_char *)toaddr = *(u_char *)fromaddr++;
1040 		tally++;
1041 		if (*(u_char *)toaddr++ == 0) {
1042 			if(lencopied) *lencopied = tally;
1043 			return(0);
1044 		}
1045 	}
1046 	if(lencopied) *lencopied = tally;
1047 	return(ENAMETOOLONG);
1048 }
1049