|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: model_dep.c ! 28: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 29: * ! 30: * Copyright (C) 1986, Avadis Tevanian, Jr., Michael Wayne Young ! 31: * ! 32: * Basic initialization for I386 - ISA bus machines. ! 33: */ ! 34: ! 35: #include <platforms.h> ! 36: #include <mach_kdb.h> ! 37: ! 38: #include <mach/vm_param.h> ! 39: #include <mach/vm_prot.h> ! 40: #include <mach/machine.h> ! 41: #include <mach/machine/multiboot.h> ! 42: ! 43: #include "vm_param.h" ! 44: #include <kern/time_out.h> ! 45: #include <sys/time.h> ! 46: #include <vm/vm_page.h> ! 47: #include <i386/machspl.h> ! 48: #include <i386/pmap.h> ! 49: #include "proc_reg.h" ! 50: ! 51: /* Location of the kernel's symbol table. ! 52: Both of these are 0 if none is available. */ ! 53: #if MACH_KDB ! 54: static vm_offset_t kern_sym_start, kern_sym_end; ! 55: #else ! 56: #define kern_sym_start 0 ! 57: #define kern_sym_end 0 ! 58: #endif ! 59: ! 60: /* These indicate the total extent of physical memory addresses we're using. ! 61: They are page-aligned. */ ! 62: vm_offset_t phys_first_addr = 0; ! 63: vm_offset_t phys_last_addr; ! 64: ! 65: /* Virtual address of physical memory, for the kvtophys/phystokv macros. */ ! 66: vm_offset_t phys_mem_va; ! 67: ! 68: struct multiboot_info *boot_info; ! 69: ! 70: /* Command line supplied to kernel. */ ! 71: char *kernel_cmdline = ""; ! 72: ! 73: /* This is used for memory initialization: ! 74: it gets bumped up through physical memory ! 75: that exists and is not occupied by boot gunk. ! 76: It is not necessarily page-aligned. */ ! 77: static vm_offset_t avail_next = 0x1000; /* XX end of BIOS data area */ ! 78: ! 79: /* Possibly overestimated amount of available memory ! 80: still remaining to be handed to the VM system. */ ! 81: static vm_size_t avail_remaining; ! 82: ! 83: /* Configuration parameter: ! 84: if zero, only use physical memory in the low 16MB of addresses. ! 85: Only SCSI still has DMA problems. */ ! 86: #ifdef LINUX_DEV ! 87: int use_all_mem = 1; ! 88: #else ! 89: #include "nscsi.h" ! 90: #if NSCSI > 0 ! 91: int use_all_mem = 0; ! 92: #else ! 93: int use_all_mem = 1; ! 94: #endif ! 95: #endif ! 96: ! 97: extern char version[]; ! 98: ! 99: extern void setup_main(); ! 100: ! 101: void inittodr(); /* forward */ ! 102: ! 103: int rebootflag = 0; /* exported to kdintr */ ! 104: ! 105: /* XX interrupt stack pointer and highwater mark, for locore.S. */ ! 106: vm_offset_t int_stack_top, int_stack_high; ! 107: ! 108: #ifdef LINUX_DEV ! 109: extern void linux_init(void); ! 110: #endif ! 111: ! 112: /* ! 113: * Find devices. The system is alive. ! 114: */ ! 115: void machine_init() ! 116: { ! 117: /* ! 118: * Initialize the console. ! 119: */ ! 120: cninit(); ! 121: ! 122: /* ! 123: * Set up to use floating point. ! 124: */ ! 125: init_fpu(); ! 126: ! 127: #ifdef LINUX_DEV ! 128: /* ! 129: * Initialize Linux drivers. ! 130: */ ! 131: linux_init(); ! 132: #endif ! 133: ! 134: /* ! 135: * Find the devices ! 136: */ ! 137: probeio(); ! 138: ! 139: /* ! 140: * Get the time ! 141: */ ! 142: inittodr(); ! 143: ! 144: /* ! 145: * Tell the BIOS not to clear and test memory. ! 146: */ ! 147: *(unsigned short *)phystokv(0x472) = 0x1234; ! 148: ! 149: /* ! 150: * Unmap page 0 to trap NULL references. ! 151: */ ! 152: pmap_unmap_page_zero(); ! 153: } ! 154: ! 155: /* ! 156: * Halt a cpu. ! 157: */ ! 158: halt_cpu() ! 159: { ! 160: asm volatile("cli"); ! 161: while(1); ! 162: } ! 163: ! 164: /* ! 165: * Halt the system or reboot. ! 166: */ ! 167: halt_all_cpus(reboot) ! 168: boolean_t reboot; ! 169: { ! 170: if (reboot) { ! 171: kdreboot(); ! 172: } ! 173: else { ! 174: rebootflag = 1; ! 175: printf("In tight loop: hit ctl-alt-del to reboot\n"); ! 176: (void) spl0(); ! 177: } ! 178: for (;;) ! 179: continue; ! 180: } ! 181: ! 182: void exit(int rc) ! 183: { ! 184: halt_all_cpus(0); ! 185: } ! 186: ! 187: void db_reset_cpu() ! 188: { ! 189: halt_all_cpus(1); ! 190: } ! 191: ! 192: ! 193: /* ! 194: * Compute physical memory size and other parameters. ! 195: */ ! 196: void ! 197: mem_size_init() ! 198: { ! 199: /* Physical memory on all PCs starts at physical address 0. ! 200: XX make it a constant. */ ! 201: phys_first_addr = 0; ! 202: ! 203: phys_last_addr = 0x100000 + (boot_info->mem_upper * 0x400); ! 204: avail_remaining ! 205: = phys_last_addr - (0x100000 - (boot_info->mem_lower * 0x400) ! 206: - 0x1000); ! 207: ! 208: printf("AT386 boot: physical memory from 0x%x to 0x%x\n", ! 209: phys_first_addr, phys_last_addr); ! 210: ! 211: if ((!use_all_mem) && phys_last_addr > 16 * 1024*1024) { ! 212: printf("** Limiting useable memory to 16 Meg to avoid DMA problems.\n"); ! 213: /* This is actually enforced below, in init_alloc_aligned. */ ! 214: } ! 215: ! 216: phys_first_addr = round_page(phys_first_addr); ! 217: phys_last_addr = trunc_page(phys_last_addr); ! 218: } ! 219: ! 220: /* ! 221: * Basic PC VM initialization. ! 222: * Turns on paging and changes the kernel segments to use high linear addresses. ! 223: */ ! 224: i386at_init() ! 225: { ! 226: /* XXX move to intel/pmap.h */ ! 227: extern pt_entry_t *kernel_page_dir; ! 228: ! 229: /* ! 230: * Initialize the PIC prior to any possible call to an spl. ! 231: */ ! 232: picinit(); ! 233: ! 234: /* ! 235: * Find memory size parameters. ! 236: */ ! 237: mem_size_init(); ! 238: ! 239: /* ! 240: * Initialize kernel physical map, mapping the ! 241: * region from loadpt to avail_start. ! 242: * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS. ! 243: * XXX make the BIOS page (page 0) read-only. ! 244: */ ! 245: pmap_bootstrap(); ! 246: ! 247: /* ! 248: * Turn paging on. ! 249: * We'll have to temporarily install a direct mapping ! 250: * between physical memory and low linear memory, ! 251: * until we start using our new kernel segment descriptors. ! 252: * One page table (4MB) should do the trick. ! 253: * Also, set the WP bit so that on 486 or better processors ! 254: * page-level write protection works in kernel mode. ! 255: */ ! 256: kernel_page_dir[lin2pdenum(0)] = ! 257: kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)]; ! 258: set_cr3((unsigned)kernel_page_dir); ! 259: set_cr0(get_cr0() | CR0_PG | CR0_WP); ! 260: flush_instr_queue(); ! 261: ! 262: /* ! 263: * Initialize and activate the real i386 protected-mode structures. ! 264: */ ! 265: gdt_init(); ! 266: idt_init(); ! 267: int_init(); ! 268: ldt_init(); ! 269: ktss_init(); ! 270: ! 271: /* Get rid of the temporary direct mapping and flush it out of the TLB. */ ! 272: kernel_page_dir[lin2pdenum(0)] = 0; ! 273: set_cr3((unsigned)kernel_page_dir); ! 274: ! 275: ! 276: ! 277: /* XXX We'll just use the initialization stack we're already running on ! 278: as the interrupt stack for now. Later this will have to change, ! 279: because the init stack will get freed after bootup. */ ! 280: asm("movl %%esp,%0" : "=m" (int_stack_top)); ! 281: ! 282: /* Interrupt stacks are allocated in physical memory, ! 283: while kernel stacks are allocated in kernel virtual memory, ! 284: so phys_last_addr serves as a convenient dividing point. */ ! 285: int_stack_high = phys_last_addr; ! 286: } ! 287: ! 288: /* ! 289: * C boot entrypoint - called by boot_entry in boothdr.S. ! 290: * Running in 32-bit flat mode, but without paging yet. ! 291: */ ! 292: void c_boot_entry(vm_offset_t bi) ! 293: { ! 294: /* Stash the boot_image_info pointer. */ ! 295: boot_info = (struct multiboot_info*)phystokv(bi); ! 296: ! 297: /* XXX we currently assume phys_mem_va is always 0 here - ! 298: if it isn't, we must tweak the pointers in the boot_info. */ ! 299: ! 300: /* Before we do _anything_ else, print the hello message. ! 301: If there are no initialized console devices yet, ! 302: it will be stored and printed at the first opportunity. */ ! 303: printf(version); ! 304: printf("\n"); ! 305: ! 306: /* Find the kernel command line, if there is one. */ ! 307: if (boot_info->flags & MULTIBOOT_CMDLINE) ! 308: kernel_cmdline = (char*)phystokv(boot_info->cmdline); ! 309: ! 310: #if MACH_KDB ! 311: /* ! 312: * Locate the kernel's symbol table, if the boot loader provided it. ! 313: * We need to do this before i386at_init() ! 314: * so that the symbol table's memory won't be stomped on. ! 315: */ ! 316: if ((boot_info->flags & MULTIBOOT_AOUT_SYMS) ! 317: && boot_info->syms.a.addr) ! 318: { ! 319: vm_size_t symtab_size, strtab_size; ! 320: ! 321: kern_sym_start = (vm_offset_t)phystokv(boot_info->syms.a.addr); ! 322: symtab_size = (vm_offset_t)phystokv(boot_info->syms.a.tabsize); ! 323: strtab_size = (vm_offset_t)phystokv(boot_info->syms.a.strsize); ! 324: kern_sym_end = kern_sym_start + 4 + symtab_size + strtab_size; ! 325: ! 326: printf("kernel symbol table at %08x-%08x (%d,%d)\n", ! 327: kern_sym_start, kern_sym_end, ! 328: symtab_size, strtab_size); ! 329: } ! 330: #endif MACH_KDB ! 331: ! 332: /* ! 333: * Do basic VM initialization ! 334: */ ! 335: i386at_init(); ! 336: ! 337: #if MACH_KDB ! 338: /* ! 339: * Initialize the kernel debugger's kernel symbol table. ! 340: */ ! 341: if (kern_sym_start) ! 342: { ! 343: aout_db_sym_init(kern_sym_start, kern_sym_end, "mach", 0); ! 344: } ! 345: ! 346: /* ! 347: * Cause a breakpoint trap to the debugger before proceeding ! 348: * any further if the proper option flag was specified ! 349: * on the kernel's command line. ! 350: * XXX check for surrounding spaces. ! 351: */ ! 352: if (strstr(kernel_cmdline, "-d ")) { ! 353: cninit(); /* need console for debugger */ ! 354: Debugger(); ! 355: } ! 356: #endif MACH_KDB ! 357: ! 358: machine_slot[0].is_cpu = TRUE; ! 359: machine_slot[0].running = TRUE; ! 360: machine_slot[0].cpu_type = CPU_TYPE_I386; ! 361: machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386; ! 362: ! 363: /* ! 364: * Start the system. ! 365: */ ! 366: setup_main(); ! 367: ! 368: } ! 369: ! 370: #include <mach/vm_prot.h> ! 371: #include <vm/pmap.h> ! 372: #include <mach/time_value.h> ! 373: ! 374: timemmap(dev,off,prot) ! 375: vm_prot_t prot; ! 376: { ! 377: extern time_value_t *mtime; ! 378: ! 379: #ifdef lint ! 380: dev++; off++; ! 381: #endif lint ! 382: ! 383: if (prot & VM_PROT_WRITE) return (-1); ! 384: ! 385: return (i386_btop(pmap_extract(pmap_kernel(), (vm_offset_t) mtime))); ! 386: } ! 387: ! 388: startrtclock() ! 389: { ! 390: clkstart(); ! 391: } ! 392: ! 393: void ! 394: inittodr() ! 395: { ! 396: time_value_t new_time; ! 397: ! 398: new_time.seconds = 0; ! 399: new_time.microseconds = 0; ! 400: ! 401: (void) readtodc(&new_time.seconds); ! 402: ! 403: { ! 404: spl_t s = splhigh(); ! 405: time = new_time; ! 406: splx(s); ! 407: } ! 408: } ! 409: ! 410: void ! 411: resettodr() ! 412: { ! 413: writetodc(); ! 414: } ! 415: ! 416: unsigned int pmap_free_pages() ! 417: { ! 418: return atop(avail_remaining); ! 419: } ! 420: ! 421: /* Always returns page-aligned regions. */ ! 422: boolean_t ! 423: init_alloc_aligned(vm_size_t size, vm_offset_t *addrp) ! 424: { ! 425: vm_offset_t addr; ! 426: extern char start[], end[]; ! 427: int i; ! 428: ! 429: /* Memory regions to skip. */ ! 430: vm_offset_t boot_info_start_pa = kvtophys(boot_info); ! 431: vm_offset_t boot_info_end_pa = boot_info_start_pa + sizeof(*boot_info); ! 432: vm_offset_t cmdline_start_pa = boot_info->flags & MULTIBOOT_CMDLINE ! 433: ? boot_info->cmdline : 0; ! 434: vm_offset_t cmdline_end_pa = cmdline_start_pa ! 435: ? cmdline_start_pa+strlen((char*)phystokv(cmdline_start_pa))+1 ! 436: : 0; ! 437: vm_offset_t mods_start_pa = boot_info->flags & MULTIBOOT_MODS ! 438: ? boot_info->mods_addr : 0; ! 439: vm_offset_t mods_end_pa = mods_start_pa ! 440: ? mods_start_pa ! 441: + boot_info->mods_count * sizeof(struct multiboot_module) ! 442: : 0; ! 443: ! 444: retry: ! 445: ! 446: /* Page-align the start address. */ ! 447: avail_next = round_page(avail_next); ! 448: ! 449: /* Check if we have reached the end of memory. */ ! 450: if (avail_next == phys_last_addr) ! 451: return FALSE; ! 452: ! 453: /* Tentatively assign the current location to the caller. */ ! 454: addr = avail_next; ! 455: ! 456: /* Bump the pointer past the newly allocated region ! 457: and see where that puts us. */ ! 458: avail_next += size; ! 459: ! 460: /* Skip past the I/O and ROM area. */ ! 461: if ((avail_next > (boot_info->mem_lower * 0x400)) && (addr < 0x100000)) ! 462: { ! 463: avail_next = 0x100000; ! 464: goto retry; ! 465: } ! 466: ! 467: /* If we're only supposed to use the low 16 megs, enforce that. */ ! 468: if ((!use_all_mem) && (addr >= 16 * 1024*1024)) { ! 469: return FALSE; ! 470: } ! 471: ! 472: /* Skip our own kernel code, data, and bss. */ ! 473: if ((avail_next >= (vm_offset_t)start) && (addr < (vm_offset_t)end)) ! 474: { ! 475: avail_next = (vm_offset_t)end; ! 476: goto retry; ! 477: } ! 478: ! 479: /* Skip any areas occupied by valuable boot_info data. */ ! 480: if ((avail_next > boot_info_start_pa) && (addr < boot_info_end_pa)) ! 481: { ! 482: avail_next = boot_info_end_pa; ! 483: goto retry; ! 484: } ! 485: if ((avail_next > cmdline_start_pa) && (addr < cmdline_end_pa)) ! 486: { ! 487: avail_next = cmdline_end_pa; ! 488: goto retry; ! 489: } ! 490: if ((avail_next > mods_start_pa) && (addr < mods_end_pa)) ! 491: { ! 492: avail_next = mods_end_pa; ! 493: goto retry; ! 494: } ! 495: if ((avail_next > kern_sym_start) && (addr < kern_sym_end)) ! 496: { ! 497: avail_next = kern_sym_end; ! 498: goto retry; ! 499: } ! 500: if (boot_info->flags & MULTIBOOT_MODS) ! 501: { ! 502: struct multiboot_module *m = (struct multiboot_module *) ! 503: phystokv(boot_info->mods_addr); ! 504: for (i = 0; i < boot_info->mods_count; i++) ! 505: { ! 506: if ((avail_next > m[i].mod_start) ! 507: && (addr < m[i].mod_end)) ! 508: { ! 509: avail_next = m[i].mod_end; ! 510: goto retry; ! 511: } ! 512: /* XXX string */ ! 513: } ! 514: } ! 515: ! 516: avail_remaining -= size; ! 517: ! 518: *addrp = addr; ! 519: return TRUE; ! 520: } ! 521: ! 522: boolean_t pmap_next_page(addrp) ! 523: vm_offset_t *addrp; ! 524: { ! 525: return init_alloc_aligned(PAGE_SIZE, addrp); ! 526: } ! 527: ! 528: /* Grab a physical page: ! 529: the standard memory allocation mechanism ! 530: during system initialization. */ ! 531: vm_offset_t ! 532: pmap_grab_page() ! 533: { ! 534: vm_offset_t addr; ! 535: if (!pmap_next_page(&addr)) ! 536: panic("Not enough memory to initialize Mach"); ! 537: return addr; ! 538: } ! 539: ! 540: boolean_t pmap_valid_page(x) ! 541: vm_offset_t x; ! 542: { ! 543: /* XXX is this OK? What does it matter for? */ ! 544: return (((phys_first_addr <= x) && (x < phys_last_addr)) && ! 545: !(((boot_info->mem_lower * 1024) <= x) && (x < 1024*1024))); ! 546: } ! 547: ! 548: #ifndef NBBY ! 549: #define NBBY 8 ! 550: #endif ! 551: #ifndef NBPW ! 552: #define NBPW (NBBY * sizeof(int)) ! 553: #endif ! 554: #define DMA_MAX (16*1024*1024) ! 555: ! 556: /* ! 557: * Allocate contiguous pages below 16 MB ! 558: * starting at specified boundary for DMA. ! 559: */ ! 560: vm_offset_t ! 561: alloc_dma_mem(size, align) ! 562: vm_size_t size; ! 563: vm_offset_t align; ! 564: { ! 565: int *bits, i, j, k, n; ! 566: int npages, count, bit, mask; ! 567: int first_page, last_page; ! 568: vm_offset_t addr; ! 569: vm_page_t p, prevp; ! 570: ! 571: npages = round_page(size) / PAGE_SIZE; ! 572: mask = align ? (align - 1) / PAGE_SIZE : 0; ! 573: ! 574: /* ! 575: * Allocate bit array. ! 576: */ ! 577: n = ((DMA_MAX / PAGE_SIZE) + NBPW - 1) / NBPW; ! 578: i = n * NBPW; ! 579: bits = (unsigned *)kalloc(i); ! 580: if (bits == 0) { ! 581: printf("alloc_dma_mem: unable alloc bit array\n"); ! 582: return (0); ! 583: } ! 584: bzero((char *)bits, i); ! 585: ! 586: /* ! 587: * Walk the page free list and set a bit for ! 588: * every usable page in bit array. ! 589: */ ! 590: simple_lock(&vm_page_queue_free_lock); ! 591: for (p = vm_page_queue_free; p; p = (vm_page_t)p->pageq.next) { ! 592: if (p->phys_addr < DMA_MAX) { ! 593: i = p->phys_addr / PAGE_SIZE; ! 594: bits[i / NBPW] |= 1 << (i % NBPW); ! 595: } ! 596: } ! 597: ! 598: /* ! 599: * Search for contiguous pages by scanning bit array. ! 600: */ ! 601: for (i = 0, first_page = -1; i < n; i++) { ! 602: for (bit = 1, j = 0; j < NBPW; j++, bit <<= 1) { ! 603: if (bits[i] & bit) { ! 604: if (first_page < 0) { ! 605: k = i * NBPW + j; ! 606: if (!mask ! 607: || (((k & mask) + npages) ! 608: <= mask + 1)) { ! 609: first_page = k; ! 610: if (npages == 1) ! 611: goto found; ! 612: count = 1; ! 613: } ! 614: } else if (++count == npages) ! 615: goto found; ! 616: } else ! 617: first_page = -1; ! 618: } ! 619: } ! 620: addr = 0; ! 621: goto out; ! 622: ! 623: found: ! 624: /* ! 625: * Remove pages from the free list. ! 626: */ ! 627: addr = first_page * PAGE_SIZE; ! 628: last_page = first_page + npages; ! 629: vm_page_free_count -= npages; ! 630: p = vm_page_queue_free; ! 631: prevp = 0; ! 632: while (1) { ! 633: i = p->phys_addr / PAGE_SIZE; ! 634: if (i >= first_page && i < last_page) { ! 635: if (prevp) ! 636: prevp->pageq.next = p->pageq.next; ! 637: else ! 638: vm_page_queue_free = (vm_page_t)p->pageq.next; ! 639: p->free = FALSE; ! 640: if (--npages == 0) ! 641: break; ! 642: } else ! 643: prevp = p; ! 644: p = (vm_page_t)p->pageq.next; ! 645: } ! 646: ! 647: out: ! 648: simple_unlock(&vm_page_queue_free_lock); ! 649: kfree((vm_offset_t)bits, n * NBPW); ! 650: return (addr); ! 651: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.