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