Annotation of OSKit-Mach/oskit/x86/main.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.