]> Zhao Yanbai Git Server - minix.git/commitdiff
SMP - Kernel is loaded above 1M by default
authorTomas Hruby <tom@minix3.org>
Wed, 15 Sep 2010 14:10:00 +0000 (14:10 +0000)
committerTomas Hruby <tom@minix3.org>
Wed, 15 Sep 2010 14:10:00 +0000 (14:10 +0000)
- the 16-bit trampoline must be within the first megabyte of physical
  memory thus the smp trampoline is copied explicitly below 1M

kernel/arch/i386/arch_smp.c
kernel/arch/i386/trampoline.S
kernel/start.c

index 13daca166593cc166978caaf7c4457d674d5a764..5ef8d5d1689caa20eabb77622a7a445b282c530b 100644 (file)
@@ -31,6 +31,7 @@ _PROTOTYPE(void trampoline, (void));
  */
 extern volatile u32_t __ap_id;
 extern volatile struct segdesc_s __ap_gdt, __ap_idt;
+extern void * __trampoline_end;
 
 extern u32_t busclock[CONFIG_MAX_CPUS];
 extern int panicking;
@@ -47,6 +48,49 @@ SPINLOCK_DEFINE(dispq_lock)
 FORWARD _PROTOTYPE(void smp_init_vars, (void));
 FORWARD _PROTOTYPE(void smp_reinit_vars, (void));
 
+/*
+ * copies the 16-bit AP trampoline code to the first 1M of memory
+ */
+PRIVATE phys_bytes copy_trampoline(void)
+{
+       char * s, *end;
+       phys_bytes tramp_base;
+       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;
+       }
+
+       phys_copy(vir2phys(trampoline), tramp_base, tramp_size);
+
+       return tramp_base;
+}
+
 PRIVATE void smp_start_aps(void)
 {
        /* 
@@ -54,7 +98,7 @@ PRIVATE void smp_start_aps(void)
         */
        unsigned cpu;
        u32_t biosresetvector;
-       phys_bytes trampoline_base = vir2phys(trampoline);
+       phys_bytes trampoline_base, __ap_id_phys;
 
        /* TODO hack around the alignment problem */
 
@@ -64,13 +108,20 @@ PRIVATE void smp_start_aps(void)
        outb(RTC_INDEX, 0xF);
        outb(RTC_IO, 0xA);
 
-       /* setup the warm reset vector */
-       phys_copy(vir2phys(&trampoline_base), 0x467, sizeof(u32_t));
-
        /* prepare gdt and idt for the new cpus */
        __ap_gdt = gdt[GDT_INDEX];
        __ap_idt = gdt[IDT_INDEX];
 
+       if (!(trampoline_base = copy_trampoline())) {
+               printf("Copying trampoline code failed, cannot boot SMP\n");
+               ncpus = 1;
+       }
+       __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));
+
        /* okay, we're ready to go.  boot all of the ap's now.  we loop through
         * using the processor's apic id values.
         */
@@ -86,6 +137,8 @@ PRIVATE void smp_start_aps(void)
                }
 
                __ap_id = cpu;
+               phys_copy(vir2phys(__ap_id), __ap_id_phys, sizeof(__ap_id));
+               mfence();
                if (apic_send_init_ipi(cpu, trampoline_base) ||
                                apic_send_startup_ipi(cpu, trampoline_base)) {
                        printf("WARNING cannot boot cpu %d\n", cpu);
@@ -222,7 +275,7 @@ PUBLIC void smp_init (void)
        /* set smp idt entries. */ 
        apic_idt_init(0); /* Not a reset ! */
        idt_reload();
-       
+
        BOOT_VERBOSE(printf("SMP initialized\n"));
 
        switch_k_stack((char *)get_k_stack_top(bsp_cpu_id) -
index 1ec8919b6bfc76c6ecab94b665f70fc3d6aabbb9..90e9a415c92aeb2e773706ef1b92642b879d91b3 100644 (file)
@@ -29,3 +29,4 @@ LABEL(__ap_gdt)
 .space 8
 LABEL(__ap_idt)
 .space 8
+LABEL(__trampoline_end)
index 1c178914bc7c5a764be5fbb9f531e19ea5ceeca7..7c6a5cf3cd2c575675bba59f9dd4867641fdcaf8 100644 (file)
@@ -123,7 +123,7 @@ PUBLIC void cstart(
  *                             get_value                                    *
  *===========================================================================*/
 
-PRIVATE char *get_value(
+PUBLIC char *get_value(
   const char *params,                  /* boot monitor parameters */
   const char *name                     /* key to look up */
 )