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