|
|
1.1 ! root 1: /* main entrypoint (from oskit multiboot_main) for Mach. ! 2: It turns out this file is almost entirely machine-dependent. ! 3: ! 4: This file defines `main', which is the entrypoint from the oskit. ! 5: It calls `setup_main' (kern/startup.c) after setting up the machine, ! 6: interrupts, paging, and `machine_slot[0]'; setup_main never returns. ! 7: This file defines `machine_init', which is called after VM is set up. ! 8: */ ! 9: ! 10: #include <oskit/clientos.h> ! 11: #include <oskit/machine/base_multiboot.h> ! 12: #include <oskit/machine/base_stack.h> ! 13: #include <oskit/machine/physmem.h> ! 14: #include <oskit/x86/base_cpu.h> ! 15: #include <oskit/x86/debug_reg.h> ! 16: #include <oskit/lmm.h> ! 17: #include <oskit/machine/phys_lmm.h> ! 18: #include <oskit/machine/base_stack.h> ! 19: ! 20: #include <mach/vm_param.h> ! 21: #include <mach/vm_prot.h> ! 22: #include <mach/machine.h> ! 23: ! 24: #include <oskit/x86/proc_reg.h> ! 25: #include <oskit/x86/paging.h> ! 26: #include <oskit/x86/base_vm.h> ! 27: #include <oskit/c/unistd.h> ! 28: #include <oskit/dev/dev.h> ! 29: #include <oskit/smp.h> ! 30: #include "gdt.h" ! 31: ! 32: #include <string.h> ! 33: ! 34: #include "vm_param.h" ! 35: #include <kern/time_out.h> ! 36: #include <sys/time.h> ! 37: #include <vm/vm_page.h> ! 38: #include <vm/vm_map.h> ! 39: #include <kern/zalloc.h> ! 40: #include <i386/machspl.h> ! 41: #include <i386/pmap.h> ! 42: #include <i386/mp_desc.h> ! 43: ! 44: #include <kern/cpu_number.h> ! 45: ! 46: /* As of 2000-12-21 the oskit has an incorrect value for this constant ! 47: in <oskit/x86/proc_reg.h>, so we redefine it with the correct one. */ ! 48: #undef CR4_PGE ! 49: #define CR4_PGE 0x80 ! 50: ! 51: static void my_exit (int), (*his_exit) (int); ! 52: ! 53: /* XXX move to intel/pmap.h */ ! 54: extern pt_entry_t *kernel_page_dir; ! 55: ! 56: ! 57: #include "assert.h" ! 58: ! 59: extern char version[]; ! 60: ! 61: char **kernel_argv; ! 62: char *kernel_cmdline; /* XXX */ ! 63: ! 64: void ! 65: setup_machine_slot (int mycpu) ! 66: { ! 67: struct cpu_info info; ! 68: cpuid (&info); ! 69: ! 70: /* Examine the CPU model information provided by the oskit, ! 71: and set machine_slot[0] to describe the CPU to users who ask. */ ! 72: switch (info.family) ! 73: { ! 74: default: ! 75: case CPU_FAMILY_386: ! 76: machine_slot[mycpu].cpu_type = CPU_TYPE_I386; ! 77: break; ! 78: case CPU_FAMILY_486: ! 79: machine_slot[mycpu].cpu_type = CPU_TYPE_I486; ! 80: break; ! 81: case CPU_FAMILY_PENTIUM: ! 82: machine_slot[mycpu].cpu_type = CPU_TYPE_PENTIUM; ! 83: break; ! 84: case CPU_FAMILY_PENTIUM_PRO: ! 85: machine_slot[mycpu].cpu_type = CPU_TYPE_PENTIUMPRO; ! 86: break; ! 87: } ! 88: machine_slot[mycpu].cpu_subtype = CPU_SUBTYPE_AT386; ! 89: machine_slot[mycpu].is_cpu = TRUE; ! 90: } ! 91: ! 92: int ! 93: main (int argc, char **argv) ! 94: { ! 95: oskit_clientos_init (); ! 96: ! 97: printf ("Welcome to %s!\r\n", version); ! 98: ! 99: /* ! 100: * Initialize the PIC prior to any possible call to an spl. ! 101: */ ! 102: picinit(); ! 103: ! 104: /* Tell the oskit base_* code what virtual addresses we are using ! 105: to map the linear address space. It can't keep using the 1:1 ! 106: kvtolin mapping once we flush the direct mapping below. ! 107: We must do this before pmap_bootstrap, because pmap_bootstrap ! 108: uses kvtolin to decide where to put its mappings! */ ! 109: linear_base_va = -LINEAR_MIN_KERNEL_ADDRESS; ! 110: ! 111: /* This allocates the kernel page tables and initializes kernel_pmap. */ ! 112: pmap_bootstrap(); ! 113: ! 114: /* ! 115: * Turn paging on. ! 116: * We'll have to temporarily install a direct mapping ! 117: * between physical memory and low linear memory, ! 118: * until we start using our new kernel segment descriptors. ! 119: * One page table (4MB) should do the trick. ! 120: * Also, set the WP bit so that on 486 or better processors ! 121: * page-level write protection works in kernel mode. ! 122: */ ! 123: kernel_page_dir[lin2pdenum(0)] = ! 124: kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)]; ! 125: paging_enable((oskit_addr_t) kernel_page_dir); ! 126: set_cr0 (get_cr0 () | CR0_WP); ! 127: ! 128: if (base_cpuid.feature_flags & CPUF_PAGE_GLOBAL_EXT) { ! 129: /* ! 130: * The processor supports the "global" bit to avoid flushing kernel TLB ! 131: * entries, if we turn it on. pmap_bootstrap checks this feature flag ! 132: * and begins use the global bit in page table entries. But according ! 133: * to the x86 specs we cannot set this bit before we do enable_paging ! 134: * above; setting CR4_PGE first doesn't work on some processors, in fact. ! 135: */ ! 136: set_cr4 (get_cr4 () | CR4_PGE); ! 137: } ! 138: ! 139: /* ! 140: * Initialize and activate the real i386 protected-mode structures. ! 141: */ ! 142: base_gdt_init(); /* reinitialize with linear_base_va */ ! 143: gdt_init(); ! 144: idt_init(); ! 145: int_init(); ! 146: ldt_init(); ! 147: ! 148: base_cpu_load(); /* Load all the new tables into the CPU. */ ! 149: ! 150: /* Now reload the TSS using our slot instead of the oskit's. */ ! 151: base_gdt[sel_idx (KERNEL_TSS)].access &= ~ACC_TSS_BUSY; ! 152: set_tr(KERNEL_TSS); ! 153: ! 154: /* Arrange a callback to our special exit function below, so we can ! 155: try to return to a state the generic oskit reboot code can cope with. */ ! 156: his_exit = oskit_libc_exit; ! 157: oskit_libc_exit = &my_exit; ! 158: ! 159: /* Get rid of the temporary direct mapping and flush it out of the TLB. */ ! 160: kernel_page_dir[lin2pdenum(0)] = 0; ! 161: inval_tlb(); ! 162: ! 163: /* Interrupt stacks are allocated in physical memory, ! 164: while kernel stacks are allocated in kernel virtual memory, ! 165: so phys_last_addr serves as a convenient dividing point. */ ! 166: int_stack_high = phys_mem_max; ! 167: ! 168: #if NCPUS > 1 ! 169: smp_init_paging (); /* This maps physical memory SMP needs. */ ! 170: if (smp_init () != 0) ! 171: printf ("SMP initialization failed!\n"); ! 172: else ! 173: { ! 174: int ncpus; ! 175: printf ("SMP initialized (maximum %d supported by this kernel)."); ! 176: ncpus = smp_get_num_cpus (); ! 177: if (ncpus == 1) ! 178: printf ("Running on a uniprocessor.\n"); ! 179: else ! 180: { ! 181: printf ("Detected %d CPUs.\n"); ! 182: if (ncpus > NCPUS) ! 183: printf ("WARNING: This kernel can only use %d CPUs.\n" ! 184: "The remaining %d CPUs will be completely idle!" ! 185: "\nYou should recompile your kernel with --enable-cpus=%d" ! 186: " or higher.\n", ! 187: NCPUS, ncpus - NCPUS, ncpus); ! 188: } ! 189: master_cpu = smp_find_cur_cpu (); ! 190: ivect[SMP_IPI_VECTOR] = (int (*)())pmap_update_interrupt; ! 191: intpri[SMP_IPI_VECTOR] = SPL1; ! 192: mp_desc_init (master_cpu); ! 193: } ! 194: interrupt_stack_alloc (); ! 195: #endif ! 196: ! 197: setup_machine_slot (master_cpu); ! 198: machine_slot[master_cpu].running = TRUE; ! 199: ! 200: kernel_argv = argv; /* Stash our args for user_bootstrap to use. */ ! 201: ! 202: { /* XXX */ ! 203: static char cmdline[1024]; ! 204: int i; ! 205: strcpy (cmdline, argv[0]); ! 206: for (i = 1; i < argc; ++i) { ! 207: strcat (cmdline, " "); ! 208: strcat (cmdline, argv[i]); ! 209: } ! 210: assert (strlen (cmdline) < sizeof cmdline); ! 211: kernel_cmdline = cmdline; ! 212: } ! 213: ! 214: /* Start the system. This function does not return. */ ! 215: setup_main(); ! 216: /* NOTREACHED */ ! 217: return -1; ! 218: } ! 219: ! 220: /* This is the function we install in `oskit_libc_exit' to be called ! 221: by _exit, panic, et al. The oskit provided an original function ! 222: (now stored in `his_exit'), that will only work properly if we are ! 223: using direct-mapped physical addresses. So we provide here a ! 224: replacement that switches to direct linear addressing and moves ! 225: to a physical-addressed stack and PC to call the oskit's function. */ ! 226: static void ! 227: my_exit (int rc) ! 228: { ! 229: /* Restore direct virtual->physical mapping and switch to ! 230: direct linear addressing code segment, so the oskit ! 231: can cope when it tries to turn paging off. */ ! 232: ! 233: kernel_page_dir[lin2pdenum(0)] ! 234: = kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)]; ! 235: set_cr4 (get_cr4 () &~ CR4_PGE); ! 236: set_pdbr (kvtophys (kernel_page_dir)); ! 237: ! 238: /* Reload the oskit's GDT slots. */ ! 239: base_gdt_init (); ! 240: base_gdt_load (); ! 241: ! 242: asm volatile (" ljmp %0,$1f \n" /* Switch to LINEAR_CS, */ ! 243: "1: movw %w1,%%ds\n" /* Switch %ds to LINEAR_DS. */ ! 244: " movw %w1,%%es\n" /* Switch %es to LINEAR_DS. */ ! 245: " movw %w1,%%ss\n" /* Switch %ss to LINEAR_DS. */ ! 246: " movl %2,%%esp\n" /* and to phys-addr base_stack. */ ! 247: " pushl %3 \n" /* Push argument (RC). */ ! 248: " pushl %4 \n" /* Push bogus return address. */ ! 249: " jmp %*%5" : : /* Jump to oskit, never return. */ ! 250: "i" (LINEAR_CS), "r" (LINEAR_DS), ! 251: "ir" (kvtophys (&base_stack_end)), ! 252: "ir" (rc), "ir" (0), ! 253: "r" (kvtophys (his_exit))); ! 254: /* NOTREACHED */ ! 255: } ! 256: ! 257: boolean_t pmap_valid_page(x) ! 258: vm_offset_t x; ! 259: { ! 260: /* XXX is this OK? What does it matter for? */ ! 261: return (((phys_mem_min <= x) && (x < phys_mem_max)) && ! 262: !(((boot_info.mem_lower * 1024) <= x) && (x < 1024*1024))); ! 263: } ! 264: ! 265: ! 266: ! 267: #include <mach/time_value.h> ! 268: ! 269: startrtclock() ! 270: { ! 271: clkstart(); ! 272: } ! 273: ! 274: static void ! 275: inittodr() ! 276: { ! 277: oskit_timespec_t ts; ! 278: oskit_error_t rc; ! 279: spl_t s; ! 280: ! 281: rc = oskit_rtc_get (&ts); ! 282: if (rc) ! 283: panic (__FUNCTION__); ! 284: ! 285: s = splhigh(); ! 286: #undef tv_sec /* oy */ ! 287: time.seconds = ts.tv_sec; ! 288: time.microseconds = (ts.tv_nsec + 999) / 1000; ! 289: splx(s); ! 290: } ! 291: ! 292: /* This is called from host_set_time at splhigh to reset the hardware clock ! 293: to the new value of `time'. */ ! 294: void ! 295: resettodr() ! 296: { ! 297: oskit_timespec_t ts = { time.seconds, time.microseconds * 1000 }; ! 298: oskit_rtc_set (&ts); ! 299: } ! 300: ! 301: ! 302: ! 303: void ! 304: machine_idle (int mycpu) ! 305: { ! 306: asm volatile ("hlt" : : : "memory"); ! 307: } ! 308: ! 309: void ! 310: halt_cpu () ! 311: { ! 312: while (1) ! 313: asm volatile ("cli; hlt"); ! 314: } ! 315: ! 316: void ! 317: halt_all_cpus(reboot) ! 318: boolean_t reboot; ! 319: { ! 320: exit(reboot ? 0 : 1); ! 321: } ! 322: ! 323: ! 324: void machine_init() ! 325: { ! 326: /* ! 327: * Set up to use floating point. ! 328: */ ! 329: init_fpu(); ! 330: ! 331: /* ! 332: * Get the time ! 333: */ ! 334: inittodr(); ! 335: ! 336: /* ! 337: * Unmap page 0 to trap NULL references. ! 338: * If there is real memory in the first physical page, ! 339: * then it will not be accessible through the normal ! 340: * direct mapping, so we need to take it out of the LMM. ! 341: */ ! 342: if (phys_mem_min < PAGE_SIZE) ! 343: { ! 344: void *block = lmm_alloc_gen (&malloc_lmm, ! 345: PAGE_SIZE - phys_mem_min, 0, 0, 0, ! 346: phys_mem_min, ! 347: PAGE_SIZE - phys_mem_min); ! 348: if ((oskit_addr_t) block != phys_mem_min) ! 349: panic ("cannot allocate first page [%#x,%#x) from physical LMM!", ! 350: phys_mem_min, PAGE_SIZE); ! 351: else ! 352: { ! 353: /* ! 354: * So we have this partial page that we can't use where it is. ! 355: * Rather than waste it, let's map it in someplace else ! 356: * and donate it to someplace that can always use a little ! 357: * chunk of extra wired kernel virtual memory: the zone system. ! 358: */ ! 359: extern vm_map_t zone_map; /* zalloc.c */ ! 360: extern zone_t vm_page_zone; /* vm_resident.c */ ! 361: vm_offset_t kva; ! 362: kern_return_t kr; ! 363: kr = kmem_alloc_pageable (zone_map, &kva, PAGE_SIZE); ! 364: if (kr != KERN_SUCCESS) ! 365: panic ("machine_init: kmem_alloc_pageable zone_map: %#x", ! 366: kr); ! 367: pmap_enter (kernel_pmap, kva, 0, ! 368: VM_PROT_READ | VM_PROT_WRITE, TRUE); ! 369: kva += phys_mem_min; /* Skip mapping below phys_mem_min. */ ! 370: /* ! 371: * The vm_page_zone is always a needy soul early in life. ! 372: */ ! 373: zcram (vm_page_zone, kva, PAGE_SIZE - phys_mem_min); ! 374: } ! 375: } ! 376: pmap_unmap_page_zero(); ! 377: ! 378: /* Catch interrupt stack overflow. */ ! 379: set_b0 (kvtolin (&base_stack_start), DR7_LEN_4, DR7_RW_DATA); ! 380: base_gdt_load(); /* necessary after setting debug regs */ ! 381: ! 382: /* That loaded the oskit's selectors. Now reload ours. */ ! 383: asm volatile("ljmp %0,$1f\n\t1:" : : "i" (KERNEL_CS)); ! 384: set_ds(KERNEL_DS); ! 385: set_es(KERNEL_DS); ! 386: set_ss(KERNEL_DS); ! 387: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.