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