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