]> Zhao Yanbai Git Server - minix.git/commitdiff
segmentless smp fixes
authorBen Gras <ben@minix3.org>
Thu, 12 Jul 2012 22:54:27 +0000 (00:54 +0200)
committerBen Gras <ben@minix3.org>
Sun, 15 Jul 2012 20:47:20 +0000 (22:47 +0200)
adjust the smp booting procedure for segmentless operation. changes are
mostly due to gdt/idt being dependent on paging, because of the high
location, and paging being on much sooner because of that too.

also smaller fixes: redefine DESC_SIZE, fix kernel makefile variable name
(crosscompiling), some null pointer checks that trap now because of a
sparser pagetable, acpi sanity checking

16 files changed:
include/arch/i386/include/archtypes.h
kernel/Makefile
kernel/arch/i386/acpi.c
kernel/arch/i386/apic.c
kernel/arch/i386/arch_clock.c
kernel/arch/i386/arch_smp.c
kernel/arch/i386/include/arch_proto.h
kernel/arch/i386/include/archconst.h
kernel/arch/i386/memory.c
kernel/arch/i386/mpx.S
kernel/arch/i386/pg_utils.c
kernel/arch/i386/pre_init.c
kernel/arch/i386/protect.c
kernel/arch/i386/trampoline.S
kernel/glo.h
kernel/main.c

index 62bc5aaaecf15b5fd7fa9f27c18f6df5eece96aa..06263f6a59ee70fee534119cf020f20a535ebeb2 100644 (file)
@@ -16,6 +16,14 @@ struct segdesc_s {           /* segment descriptor for protected mode */
   u8_t base_high;
 } __attribute__((packed));
 
+struct gatedesc_s {
+  u16_t offset_low;
+  u16_t selector;
+  u8_t pad;                     /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
+  u8_t p_dpl_type;              /* |P|DL|0|TYPE| */
+  u16_t offset_high;
+} __attribute__((packed));
+
 struct desctableptr_s {
   u16_t limit;
   u32_t base;
index b46a65efd7a451e8005e9a2e08f1f1e527238939..5801310e613a7271f2d1df5228391a35bb384b0d 100644 (file)
@@ -8,7 +8,7 @@ PROG=   kernel
 SRCS+= clock.c cpulocals.c interrupt.c main.c proc.c system.c \
        table.c utility.c 
 
-LINKERSCRIPT=${.CURDIR}/arch/${ARCH}/kernel.lds
+LINKERSCRIPT=${.CURDIR}/arch/${MACHINE_ARCH}/kernel.lds
 
 DPADD+=        ${LIBTIMERS} ${LIBSYS} ${LIBEXEC} $(LINKERSCRIPT)
 LDADD+=        -ltimers -lsys -lexec
index 519410f1fac8bc9a4c84bf3c44a12712459c38e9..225467ba2c4bdfeed8b4ace262bb646bfc373229 100644 (file)
@@ -39,6 +39,24 @@ static int acpi_check_signature(const char * orig, const char * match)
        return strncmp(orig, match, ACPI_SDT_SIGNATURE_LEN);
 }
 
+static u32_t acpi_phys2vir(u32_t p)
+{
+       if(!vm_running) {
+               printf("acpi: returning 0x%lx as vir addr\n", p);
+               return p;
+       }
+       panic("acpi: can't get virtual address of arbitrary physical address");
+}
+
+static int acpi_phys_copy(phys_bytes phys, void *target, size_t len)
+{
+       if(!vm_running) {
+               memcpy(target, (void *) phys, len);
+               return 0;
+       }
+       panic("can't acpi_phys_copy with vm");
+}
+
 static int acpi_read_sdt_at(phys_bytes addr,
                                struct acpi_sdt_header * tb,
                                size_t size,
@@ -172,7 +190,7 @@ static int get_acpi_rsdp(void)
        /*
         * Read 40:0Eh - to find the starting address of the EBDA.
         */
-       phys_copy (0x40E, vir2phys(&ebda), sizeof(ebda));
+       acpi_phys_copy (0x40E, &ebda, sizeof(ebda));
        if (ebda) {
                ebda <<= 4;
                if(platform_tbl_ptr(ebda, ebda + 0x400, 16, &acpi_rsdp,
@@ -192,16 +210,10 @@ static int get_acpi_rsdp(void)
        return 0;
 }
 
-static int acpi_read_kernel(phys_bytes addr, void * buff, size_t size)
-{
-       phys_copy(addr, vir2phys(buff), size);
-       return 0;
-}
-
 void acpi_init(void)
 {
        int s, i;
-       read_func = acpi_read_kernel;
+       read_func = acpi_phys_copy;
 
        if (!get_acpi_rsdp()) {
                printf("WARNING : Cannot configure ACPI\n");
@@ -238,7 +250,7 @@ struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
 
        if (idx == 0) {
                madt_hdr = (struct acpi_madt_hdr *)
-                       phys2vir(acpi_get_table_base("APIC"));
+                       acpi_phys2vir(acpi_get_table_base("APIC"));
                if (madt_hdr == NULL)
                        return NULL;
        }
@@ -260,7 +272,7 @@ struct acpi_madt_lapic * acpi_get_lapic_next(void)
 
        if (idx == 0) {
                madt_hdr = (struct acpi_madt_hdr *)
-                       phys2vir(acpi_get_table_base("APIC"));
+                       acpi_phys2vir(acpi_get_table_base("APIC"));
                if (madt_hdr == NULL)
                        return NULL;
        }
index bb342c4b3dae2491c814f94f2fbacdb823b6a809..5c652c0a988266fa036b68a9f298a7ba4b0aee7b 100644 (file)
@@ -365,6 +365,11 @@ void ioapic_disable_all(void)
 
 static void ioapic_disable_irq(unsigned irq)
 {
+       if(!(io_apic_irq[irq].ioa)) {
+               printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq);
+               return;
+       }
+
        assert(io_apic_irq[irq].ioa);
 
        ioapic_disable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
@@ -373,6 +378,11 @@ static void ioapic_disable_irq(unsigned irq)
 
 static void ioapic_enable_irq(unsigned irq)
 {
+       if(!(io_apic_irq[irq].ioa)) {
+               printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq);
+               return;
+       }
+
        assert(io_apic_irq[irq].ioa);
 
        ioapic_enable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
@@ -915,16 +925,17 @@ static int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
                if (acpi_ioa == NULL)
                        break;
 
+               assert(acpi_ioa->address);
+
                ioa[n].id = acpi_ioa->id;
                ioa[n].addr = acpi_ioa->address;
                ioa[n].paddr = (phys_bytes) acpi_ioa->address;
                ioa[n].gsi_base = acpi_ioa->global_int_base;
                ioa[n].pins = ((ioapic_read(ioa[n].addr,
                                IOAPIC_VERSION) & 0xff0000) >> 16)+1;
-               printf("IO APIC %d addr 0x%lx paddr 0x%lx pins %d\n",
-                               acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
+               printf("IO APIC idx %d id %d addr 0x%lx paddr 0x%lx pins %d\n",
+                               n, acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
                                ioa[n].pins);
-
                n++;
        }
 
index 07a006e8db02db67761375cafc8f8691baa2fff6..692a95d92dc9cf60c26577dc05d54dc835a48817 100644 (file)
@@ -206,6 +206,7 @@ void context_stop(struct proc * p)
        u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch);
 #ifdef CONFIG_SMP
        unsigned cpu = cpuid;
+       int must_bkl_unlock = 0;
 
        /*
         * This function is called only if we switch from kernel to user or idle
@@ -222,7 +223,7 @@ void context_stop(struct proc * p)
                tmp = sub64(tsc, *__tsc_ctr_switch);
                kernel_ticks[cpu] = add64(kernel_ticks[cpu], tmp);
                p->p_cycles = add64(p->p_cycles, tmp);
-               BKL_UNLOCK();
+               must_bkl_unlock = 1;
        } else {
                u64_t bkl_tsc;
                atomic_t succ;
@@ -295,6 +296,12 @@ void context_stop(struct proc * p)
        }
 
        *__tsc_ctr_switch = tsc;
+
+#ifdef CONFIG_SMP
+       if(must_bkl_unlock) {
+               BKL_UNLOCK();
+       }
+#endif
 }
 
 void context_stop_idle(void)
index 83a3b0b7e9688feb57a4907e4788c4df561209f7..25c536883f1f18ef2cda178ebd7d662e4f3c9029 100644 (file)
 #include "arch_proto.h"
 #include "kernel/glo.h"
 #include <unistd.h>
+#include <assert.h>
 #include <stdlib.h>
+#include <machine/archtypes.h>
+#include <archconst.h>
 #include <machine/cmos.h>
 #include <machine/bios.h>
 #include <minix/portio.h>
@@ -31,8 +34,9 @@ void trampoline(void);
  * They have to be in location which is reachable using absolute addressing in
  * 16-bit mode
  */
-extern volatile u32_t __ap_id;
+extern volatile u32_t __ap_id, __ap_pt;
 extern volatile struct desctableptr_s __ap_gdt, __ap_idt;
+extern u32_t __ap_gdt_tab, __ap_idt_tab;
 extern void * __trampoline_end;
 
 extern u32_t busclock[CONFIG_MAX_CPUS];
@@ -50,81 +54,84 @@ SPINLOCK_DEFINE(dispq_lock)
 
 static void smp_reinit_vars(void);
 
+/* These are initialized in protect.c */
+extern struct segdesc_s gdt[GDT_SIZE];
+extern struct gatedesc_s idt[IDT_SIZE];
+extern struct tss_s tss[CONFIG_MAX_CPUS];
+extern int prot_init_done;     /* Indicates they are ready */
+
+static phys_bytes trampoline_base;
+
+static u32_t ap_lin_addr(void *vaddr)
+{
+       assert(trampoline_base);
+       return (u32_t) vaddr - (u32_t) &trampoline + trampoline_base;
+}
+
 /*
  * copies the 16-bit AP trampoline code to the first 1M of memory
  */
-static phys_bytes copy_trampoline(void)
+void copy_trampoline(void)
 {
        char * s, *end;
-       phys_bytes tramp_base = 0;
-       unsigned tramp_size;
-
-       tramp_size = (unsigned) &__trampoline_end - (unsigned)&trampoline;
-       s = env_get("memory");
-       if (!s)
-               return 0;
-
-       while (*s != 0) {
-               phys_bytes base = 0xfffffff;
-               unsigned size;
-               /* Read fresh base and expect colon as next char. */ 
-               base = strtoul(s, &end, 0x10);          /* get number */
-               if (end != s && *end == ':')
-                       s = ++end;      /* skip ':' */ 
-               else
-                       *s=0;
-
-               /* Read fresh size and expect comma or assume end. */ 
-               size = strtoul(s, &end, 0x10);          /* get number */
-               if (end != s && *end == ',')
-                       s = ++end;      /* skip ',' */
-
-               tramp_base = (base + 0xfff) & ~(0xfff);
-               /* the address must be less than 1M */
-               if (tramp_base >= (1 << 20))
-                       continue;
-               if (size - (tramp_base - base) < tramp_size)
-                       continue;
-               break;
-       }
+       unsigned tramp_size, tramp_start = (unsigned)&trampoline;;
+
+       /* The trampoline code/data is made to be page-aligned. */
+       assert(!(tramp_start % I386_PAGE_SIZE));
 
-       phys_copy(vir2phys(trampoline), tramp_base, tramp_size);
+       tramp_size = (unsigned) &__trampoline_end - tramp_start;
+       trampoline_base = alloc_lowest(&kinfo, tramp_size);
+
+       /* The memory allocator finds the lowest available memory.. 
+        * Verify it's low enough
+        */
+       assert(trampoline_base + tramp_size < (1 << 20));
 
-       return tramp_base;
+       /* prepare gdt and idt for the new cpus; make copies
+        * of both the tables and the descriptors of them
+        * in their boot addressing environment.
+        */
+       assert(prot_init_done);
+       memcpy(&__ap_gdt_tab, gdt, sizeof(gdt));
+       memcpy(&__ap_idt_tab, gdt, sizeof(idt));
+       __ap_gdt.base = ap_lin_addr(&__ap_gdt_tab);
+       __ap_gdt.limit = sizeof(gdt)-1;
+       __ap_idt.base = ap_lin_addr(&__ap_idt_tab);
+       __ap_idt.limit = sizeof(idt)-1;
+
+       phys_copy(trampoline, trampoline_base, tramp_size);
 }
 
-extern struct desctableptr_s gdt_desc, idt_desc;
+extern int booting_cpu;        /* tell protect.c what to do */
 
 static void smp_start_aps(void)
 {
-       /* 
-        * Find an address and align it to a 4k boundary.
-        */
        unsigned cpu;
-       u32_t biosresetvector;
-       phys_bytes trampoline_base, __ap_id_phys;
+       u32_t biosresetvector, *newptpos;
+       phys_bytes __ap_id_phys;
+       struct proc *bootstrap_pt = get_cpulocal_var(ptproc);
 
        /* TODO hack around the alignment problem */
 
-       phys_copy (0x467, vir2phys(&biosresetvector), sizeof(u32_t));
+       phys_copy (0x467, &biosresetvector, sizeof(u32_t));
 
        /* set the bios shutdown code to 0xA */
        outb(RTC_INDEX, 0xF);
        outb(RTC_IO, 0xA);
 
-       /* prepare gdt and idt for the new cpus */
-       __ap_gdt = gdt_desc;
-       __ap_idt = idt_desc;
+       assert(bootstrap_pt);
+       assert(bootstrap_pt->p_seg.p_cr3);
+       __ap_pt  = bootstrap_pt->p_seg.p_cr3;
+       assert(__ap_pt);
 
-       if (!(trampoline_base = copy_trampoline())) {
-               printf("Copying trampoline code failed, cannot boot SMP\n");
-               ncpus = 1;
-       }
+       copy_trampoline();
+
+       /* New locations for cpu id, pagetable root */
        __ap_id_phys = trampoline_base +
                (phys_bytes) &__ap_id - (phys_bytes)&trampoline;
 
        /* setup the warm reset vector */
-       phys_copy(vir2phys(&trampoline_base), 0x467, sizeof(u32_t));
+       phys_copy(&trampoline_base, 0x467, sizeof(u32_t));
 
        /* okay, we're ready to go.  boot all of the ap's now.  we loop through
         * using the processor's apic id values.
@@ -137,9 +144,8 @@ static void smp_start_aps(void)
                        continue;
                }
 
-               __ap_id = cpu;
-               phys_copy(vir2phys((void *) &__ap_id),
-                       __ap_id_phys, sizeof(__ap_id));
+               __ap_id = booting_cpu = cpu;
+               phys_copy((void *) &__ap_id, __ap_id_phys, sizeof(__ap_id));
                mfence();
                if (apic_send_init_ipi(cpu, trampoline_base) ||
                                apic_send_startup_ipi(cpu, trampoline_base)) {
@@ -161,7 +167,7 @@ static void smp_start_aps(void)
                }
        }
 
-       phys_copy(vir2phys(&biosresetvector),(phys_bytes)0x467,sizeof(u32_t));
+       phys_copy(&biosresetvector,(phys_bytes)0x467,sizeof(u32_t));
 
        outb(RTC_INDEX, 0xF);
        outb(RTC_IO, 0);
@@ -219,9 +225,6 @@ static void ap_finish_booting(void)
        /* inform the world of our presence. */
        ap_cpu_ready = cpu;
 
-       while(!bootstrap_pagetable_done)
-               arch_pause();
-
        /*
         * Finish processor initialisation.  CPUs must be excluded from running.
         * lapic timer calibration locks and unlocks the BKL because of the
@@ -231,14 +234,7 @@ static void ap_finish_booting(void)
        spinlock_lock(&boot_lock);
        BKL_LOCK();
 
-       /*
-        * we must load some page tables befre we turn paging on. As VM is
-        * always present we use those
-        */
-       pg_load();              /* load bootstrap pagetable built by BSP */
-       vm_enable_paging();
-       
-       printf("CPU %d paging is on\n", cpu);
+       printf("CPU %d is up\n", cpu);
 
        cpu_identify();
 
index d6519151a6f1b615d1021e0808276e3017ad7b2e..3693ac46043482aae09b47b7a24b0174528c6707 100644 (file)
@@ -161,12 +161,13 @@ u32_t read_ds(void);
 u32_t read_ss(void);
 
 void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len);
+phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len);
 void vm_enable_paging(void);
 void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end);
 phys_bytes pg_roundup(phys_bytes b);
 void pg_info(reg_t *, u32_t **);
 void pg_clear(void);
-void pg_identity(void);
+void pg_identity(kinfo_t *);
 phys_bytes pg_load(void);
 void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end, kinfo_t *cbi);
 int pg_mapkernel(void);
index 123bc4768ce57024ae2cee322b7e1ba4c8dc1daa..6ae9de784f44c644e9171c0b58f4360d2a96c1b4 100644 (file)
@@ -28,6 +28,8 @@
 #define LDT_SELECTOR SEG_SELECTOR(LDT_INDEX)
 #define TSS_SELECTOR(cpu)      SEG_SELECTOR(TSS_INDEX(cpu))
 
+#define DESC_SIZE      8
+
 /* Privileges. */
 #define INTR_PRIVILEGE       0 /* kernel and interrupt handlers */
 #define USER_PRIVILEGE       3 /* servers and user processes */
index c780776017e16d2f802a5c9d89631ab4ca9dd71c..e876281038f21d93dc2b8398ff544d1ba9998e58 100644 (file)
@@ -164,11 +164,11 @@ static int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
 #ifdef CONFIG_SMP
                unsigned cpu = cpuid;
 
-               if (GET_BIT(srcproc->p_stale_tlb, cpu)) {
+               if (srcproc && GET_BIT(srcproc->p_stale_tlb, cpu)) {
                        changed = 1;
                        UNSET_BIT(srcproc->p_stale_tlb, cpu);
                }
-               if (GET_BIT(dstproc->p_stale_tlb, cpu)) {
+               if (dstproc && GET_BIT(dstproc->p_stale_tlb, cpu)) {
                        changed = 1;
                        UNSET_BIT(dstproc->p_stale_tlb, cpu);
                }
@@ -815,10 +815,13 @@ int arch_phys_map(const int index,
                *flags = VMMF_UNCACHED;
                return OK;
        }
-       else if (ioapic_enabled && index <= ioapic_last_index) {
-               *addr = io_apic[index - 1].paddr;
+       else if (ioapic_enabled && index >= ioapic_first_index && index <= ioapic_last_index) {
+               int ioapic_idx = index - ioapic_first_index;
+               *addr = io_apic[ioapic_idx].paddr;
+               assert(*addr);
                *len = 4 << 10 /* 4kB */;
                *flags = VMMF_UNCACHED;
+               printf("ioapic map: addr 0x%lx\n", *addr);
                return OK;
        }
 #endif
index 830a994151ede7b2ce346849b6777a3030ebc9ba..fa39e74a6f89998a18fdf8ee2c40bbfdc18b33c3 100644 (file)
@@ -479,27 +479,22 @@ ENTRY(startup_ap_32)
        /*
         * we are in protected mode now, %cs is correct and we need to set the
         * data descriptors before we can touch anything
+        *
+        * first load the regular, highly mapped idt, gdt
         */
-       movw    $KERN_DS_SELECTOR, %ax
-       mov     %ax, %ds
-       mov     %ax, %ss
-       mov     %ax, %es
-       movw    $0, %ax
-       mov     %ax, %fs
-       mov     %ax, %gs
-
-       /* load TSS for this cpu which was prepared by BSP */
-       movl    _C_LABEL(__ap_id), %ecx
-       shl     $3, %cx
-       mov     $TSS_SELECTOR(0), %eax
-       add     %cx, %ax
-       ltr     %ax
-       
+
        /*
         * use the boot stack for now. The running CPUs are already using their
         * own stack, the rest is still waiting to be booted
         */
+       movw    $KERN_DS_SELECTOR, %ax
+       mov     %ax, %ds
+       mov     %ax, %ss
        mov     $_C_LABEL(k_boot_stktop) - 4, %esp
+
+       /* load the highly mapped idt, gdt, per-cpu tss */
+       call    _C_LABEL(prot_load_selectors)
+
        jmp     _C_LABEL(smp_ap_boot)
        hlt
 #endif
index 2702500018f0e8eb1455c35b253b353e9a5266b7..f096369a028227d70e415e5447e5e6f37ceda273 100644 (file)
@@ -22,6 +22,17 @@ static phys_bytes kern_kernlen = (phys_bytes) &_kern_size;
 /* page directory we can use to map things */
 static u32_t pagedir[1024]  __aligned(4096);
 
+void print_memmap(kinfo_t *cbi)
+{
+        int m;
+        assert(cbi->mmap_size < MAXMEMMAP);
+        for(m = 0; m < cbi->mmap_size; m++) {
+               phys_bytes addr = cbi->memmap[m].addr, endit = cbi->memmap[m].addr + cbi->memmap[m].len;
+                printf("%08lx-%08lx ",addr, endit);
+        }
+        printf("\nsize %08lx\n", cbi->mmap_size);
+}
+
 void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
 {
         int m;
@@ -32,6 +43,8 @@ void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
         if((o=end % I386_PAGE_SIZE))
                 end += I386_PAGE_SIZE - o;
 
+       assert(kernel_may_alloc);
+
         for(m = 0; m < cbi->mmap_size; m++) {
                 phys_bytes substart = start, subend = end;
                 phys_bytes memaddr = cbi->memmap[m].addr,
@@ -53,10 +66,29 @@ void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
         }
 }
 
+phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len)
+{
+       /* Allocate the lowest physical page we have. */
+       int m;
+#define EMPTY 0xffffffff
+       phys_bytes lowest = EMPTY;
+       assert(len > 0);
+       len = roundup(len, I386_PAGE_SIZE);
+
+       assert(kernel_may_alloc);
+
+       for(m = 0; m < cbi->mmap_size; m++) {
+               if(cbi->memmap[m].len < len) continue;
+               if(cbi->memmap[m].addr < lowest) lowest = cbi->memmap[m].addr;
+       }
+       assert(lowest != EMPTY);
+       cut_memmap(cbi, lowest, len);
+       return lowest;
+}
+
 void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
 {
         int m;
-       phys_bytes highmark;
 #define LIMIT 0xFFFFF000
         /* Truncate available memory at 4GB as the rest of minix
          * currently can't deal with any bigger.
@@ -69,20 +101,25 @@ void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
         if(len == 0) return;
        addr = roundup(addr, I386_PAGE_SIZE);
        len = rounddown(len, I386_PAGE_SIZE);
+
+       assert(kernel_may_alloc);
+
         for(m = 0; m < MAXMEMMAP; m++) {
+               phys_bytes highmark;
                 if(cbi->memmap[m].len) continue;
                 cbi->memmap[m].addr = addr;
                 cbi->memmap[m].len = len;
                 cbi->memmap[m].type = MULTIBOOT_MEMORY_AVAILABLE;
                 if(m >= cbi->mmap_size)
                         cbi->mmap_size = m+1;
+               highmark = addr + len;
+               if(highmark > cbi->mem_high_phys) {
+                       cbi->mem_high_phys = highmark;
+               }
+
                 return;
         }
 
-       highmark = addr + len;
-       if(highmark > cbi->mem_high_phys)
-               cbi->mem_high_phys = highmark;
-
         panic("no available memmap slot");
 }
 
@@ -105,6 +142,9 @@ phys_bytes pg_alloc_page(kinfo_t *cbi)
 {
        int m;
        multiboot_memory_map_t *mmap;
+
+       assert(kernel_may_alloc);
+
        for(m = cbi->mmap_size-1; m >= 0; m--) {
                mmap = &cbi->memmap[m];
                if(!mmap->len) continue;
@@ -120,16 +160,26 @@ phys_bytes pg_alloc_page(kinfo_t *cbi)
        panic("can't find free memory");
 }
 
-void pg_identity(void)
+void pg_identity(kinfo_t *cbi)
 {
        int i;
        phys_bytes phys;
 
+       /* We map memory that does not correspond to physical memory
+        * as non-cacheable. Make sure we know what it is.
+        */
+       assert(cbi->mem_high_phys);
+
         /* Set up an identity mapping page directory */
         for(i = 0; i < I386_VM_DIR_ENTRIES; i++) {
+               u32_t flags = I386_VM_PRESENT | I386_VM_BIGPAGE |
+                       I386_VM_USER | I386_VM_WRITE;
+               if((cbi->mem_high_phys & I386_VM_ADDR_MASK_4MB)
+                       <= (phys & I386_VM_ADDR_MASK_4MB)) {
+                       flags |= I386_VM_PWT | I386_VM_PCD;
+               }
                 phys = i * I386_BIG_PAGE_SIZE;
-                pagedir[i] =  phys | I386_VM_PRESENT | I386_VM_BIGPAGE |
-                        I386_VM_USER | I386_VM_WRITE;
+                pagedir[i] =  phys | flags;
         }
 }
 
@@ -216,6 +266,8 @@ void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end,
        static u32_t *pt = NULL;
        int pde, pte;
 
+       assert(kernel_may_alloc);
+
        if(phys == PG_ALLOCATEME) {
                assert(!(vaddr % I386_PAGE_SIZE));
        } else  {
index 53aac5b6657d8ef377e7ee4fc8009bec2d268def..66e63efe09317288be8c9e68d26e0fc6b899c282 100644 (file)
@@ -37,6 +37,9 @@ char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
 /* String length used for mb_itoa */
 #define ITOA_BUFFER_SIZE 20
 
+/* Kernel may use memory */
+int kernel_may_alloc = 1;
+
 static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi) 
 {
        char *p = bigbuf;
@@ -96,16 +99,6 @@ int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
        return 0;
 }
 
-void print_memmap(kinfo_t *cbi)
-{
-       int m;
-       assert(cbi->mmap_size < MAXMEMMAP);
-       for(m = 0; m < cbi->mmap_size; m++) {
-               printf("%08lx-%08lx ",cbi->memmap[m].addr, cbi->memmap[m].addr + cbi->memmap[m].len);
-       }
-       printf("\nsize %08lx\n", cbi->mmap_size);
-}
-
 void get_parameters(u32_t ebx, kinfo_t *cbi) 
 {
        multiboot_memory_map_t *mmap;
@@ -225,9 +218,6 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx)
         * Here we find out whether we should do serial output.
         */
        get_parameters(ebx, &kinfo);
-       
-       /* Say hello. */
-       printf("MINIX loading\n");
 
        assert(magic == MULTIBOOT_BOOTLOADER_MAGIC);
 
@@ -236,7 +226,7 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx)
         * this code stays where it should be.
         */
        pg_clear();
-       pg_identity();
+       pg_identity(&kinfo);
        kinfo.freepde_start = pg_mapkernel();
        pg_load();
        vm_enable_paging();
index 8efa837f0a4a612650456596ffa5f84da70bd61b..6627cc329df8a0dd42b969f31a0ae7175ad486ff 100644 (file)
 /* This is OK initially, when the 1:1 mapping is still there. */
 char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
 
-struct gatedesc_s {
-  u16_t offset_low;
-  u16_t selector;
-  u8_t pad;                    /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
-  u8_t p_dpl_type;             /* |P|DL|0|TYPE| */
-  u16_t offset_high;
-} __attribute__((packed));
-
 /* Storage for gdt, idt and tss. */
-static struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE);
+struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE);
 struct gatedesc_s idt[IDT_SIZE] __aligned(DESC_SIZE);
 struct tss_s tss[CONFIG_MAX_CPUS];
 
+int prot_init_done = 0;
+
 phys_bytes vir2phys(void *vir)
 {
        extern char _kern_vir_base, _kern_phys_base;    /* in kernel.lds */
@@ -263,12 +257,33 @@ multiboot_module_t *bootmod(int pnr)
        panic("boot module %d not found", pnr);
 }
 
+int booting_cpu = 0;
+
+void prot_load_selectors(void)
+{
+  /* this function is called by both prot_init by the BSP and
+   * the early AP booting code in mpx.S by secondary CPU's.
+   * everything is set up the same except for the TSS that is per-CPU.
+   */
+  x86_lgdt(&gdt_desc); /* Load gdt */ 
+  idt_init();
+  idt_reload();
+  x86_lldt(LDT_SELECTOR);      /* Load bogus ldt */
+  x86_ltr(TSS_SELECTOR(booting_cpu));
+
+  x86_load_kerncs();
+  x86_load_ds(KERN_DS_SELECTOR);
+  x86_load_es(KERN_DS_SELECTOR);
+  x86_load_fs(KERN_DS_SELECTOR);
+  x86_load_gs(KERN_DS_SELECTOR);
+  x86_load_ss(KERN_DS_SELECTOR);
+}
+
 /*===========================================================================*
  *                             prot_init                                    *
  *===========================================================================*/
 void prot_init()
 {
-  int sel_tss;
   extern char k_boot_stktop;
 
   memset(gdt, 0, sizeof(gdt));
@@ -279,7 +294,7 @@ void prot_init()
   gdt_desc.limit = sizeof(gdt)-1;
   idt_desc.base = (u32_t) idt;
   idt_desc.limit = sizeof(idt)-1;
-  sel_tss = tss_init(0, &k_boot_stktop);
+  tss_init(0, &k_boot_stktop);
 
   /* Build GDT */
   init_param_dataseg(&gdt[LDT_INDEX],
@@ -290,22 +305,11 @@ void prot_init()
   init_codeseg(USER_CS_INDEX, USER_PRIVILEGE);
   init_dataseg(USER_DS_INDEX, USER_PRIVILEGE);
 
-  x86_lgdt(&gdt_desc); /* Load gdt */ 
-  idt_init();
-  idt_reload();
-  x86_lldt(LDT_SELECTOR);      /* Load bogus ldt */
-  x86_ltr(sel_tss);    /* Load global TSS */
-
   /* Currently the multiboot segments are loaded; which is fine, but
    * let's replace them with the ones from our own GDT so we test
    * right away whether they work as expected.
    */
-  x86_load_kerncs();
-  x86_load_ds(KERN_DS_SELECTOR);
-  x86_load_es(KERN_DS_SELECTOR);
-  x86_load_fs(KERN_DS_SELECTOR);
-  x86_load_gs(KERN_DS_SELECTOR);
-  x86_load_ss(KERN_DS_SELECTOR);
+  prot_load_selectors();
 
   /* Set up a new post-relocate bootstrap pagetable so that
    * we can map in VM, and we no longer rely on pre-relocated
@@ -313,10 +317,11 @@ void prot_init()
    */
 
   pg_clear();
-  pg_identity(); /* Still need 1:1 for lapic and video mem and such. */
+  pg_identity(&kinfo); /* Still need 1:1 for lapic and video mem and such. */
   pg_mapkernel();
   pg_load();
-  bootstrap_pagetable_done = 1;        /* secondary CPU's can use it too */
+
+  prot_init_done = 1;
 }
 
 void arch_post_init(void)
index a03aedbf80cd7bc0cfc58dcd6706a3c5775203c3..92e4635cda67c124506591a7904fc0054381843a 100644 (file)
@@ -1,4 +1,5 @@
 #include <machine/asm.h>
+#include <machine/vm.h>
 #include "archconst.h"
 
 .balign 4096
@@ -6,7 +7,7 @@
 .code16
 ENTRY(trampoline)
        cli
-       
+
        /* %cs has some value and we must use the same for data */
        mov     %cs, %ax
        mov     %ax, %ds
@@ -20,13 +21,38 @@ ENTRY(trampoline)
        orb     $1, %al
        mov     %eax, %cr0
 
+       /* set page table feature flags: cr4.PSE on, cr4.PGE off */
+       movl    %cr4, %eax
+       orl     $I386_CR4_PSE, %eax     /* Turn on PSE */
+       andl    $~I386_CR4_PGE, %eax    /* Turn off PGE */
+       movl    %eax, %cr4
+
+       /* load boot cr3 and turn PG on so CPU can see all of memory */
+       movl    _C_LABEL(__ap_pt) - _C_LABEL(trampoline), %eax
+       movl    %eax, %cr3
+       movl    %cr0, %ecx
+       orl     $I386_CR0_PG, %ecx
+       movl    %ecx, %cr0
+
+       /* turn on cr4.PGE after cr0.PG is on */
+       movl    %cr4, %eax
+       orl     $I386_CR4_PGE, %eax
+       movl    %eax, %cr4
+
+       /* jump into regular highly mapped kernel */
        ljmpl   $KERN_CS_SELECTOR, $_C_LABEL(startup_ap_32)
 
 .balign 4
 LABEL(__ap_id)
 .space 4
+LABEL(__ap_pt)
+.space 4
 LABEL(__ap_gdt)
 .space 8
 LABEL(__ap_idt)
 .space 8
+LABEL(__ap_gdt_tab)
+.space GDT_SIZE*DESC_SIZE
+LABEL(__ap_idt_tab)
+.space IDT_SIZE*DESC_SIZE
 LABEL(__trampoline_end)
index 4bb96da5216c189d15ec7cc00a6a8e28356817f0..52471c819b38b2861d763b6eff0bd5b660d6479b 100644 (file)
@@ -59,11 +59,11 @@ EXTERN u64_t cpu_hz[CONFIG_MAX_CPUS];
 #ifdef CONFIG_SMP
 EXTERN int config_no_smp; /* optionaly turn off SMP */
 #endif
-EXTERN int bootstrap_pagetable_done;
 
 /* VM */
 EXTERN int vm_running;
 EXTERN int catch_pagefaults;
+EXTERN int kernel_may_alloc;
 
 /* Variables that are initialized elsewhere are just extern here. */
 extern struct boot_image image[NR_BOOT_PROCS];         /* system image processes */
index 5cf56e1db569835f340be281cf6fbf65dab72c67..7d92ce437f6f26492aca3393c5bf1466e6776949 100644 (file)
@@ -107,6 +107,9 @@ void bsp_finish_booting(void)
   machine.bsp_id = 0;
 #endif
 
+  /* Kernel may no longer use bits of memory as VM will be running soon */
+  kernel_may_alloc = 0;
+
   switch_to_user();
   NOT_REACHABLE;
 }
@@ -128,6 +131,9 @@ void kmain(kinfo_t *local_cbi)
   /* We can talk now */
   printf("MINIX booting\n");
 
+  /* Kernel may use bits of main memory before VM is started */
+  kernel_may_alloc = 1;
+
   assert(sizeof(kinfo.boot_procs) == sizeof(image));
   memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));