diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index cfa6544e..9da34e0d 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -151,7 +151,7 @@ inline static void wmb(void) { asm volatile("sfence" ::: "memory"); } * @param d EDX value will be stores here */ inline static void cpuid(uint32_t code, uint32_t* a, uint32_t* b, uint32_t* c, uint32_t* d) { - asm volatile ("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "0"(code)); + asm volatile ("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "0"(code), "2"(*c)); } /** @brief Read MSR @@ -335,9 +335,7 @@ uint32_t read_eip(void); inline static int system_init(void) { gdt_install(); -#ifdef CONFIG_X86_32 apic_init(); -#endif #ifdef CONFIG_PCI pci_init(); #endif diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index ca860d4f..3d76c425 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c @@ -42,6 +42,13 @@ #error RockCreek is not a SMP system #endif +/* + * Note that linker symbols are not variables, they have no memory allocated for + * maintaining a value, rather their address is their value. + */ +extern const void kernel_start; +extern const void kernel_end; + // IO APIC MMIO structure: write reg, then read or write data. typedef struct { uint32_t reg; @@ -53,7 +60,7 @@ static const apic_processor_entry_t* apic_processors[MAX_CORES] = {[0 ... MAX_CO static uint32_t boot_processor = MAX_CORES; static apic_mp_t* apic_mp = NULL; static apic_config_table_t* apic_config = NULL; -static uint32_t lapic = 0; +static size_t lapic = 0; static volatile ioapic_t* ioapic = NULL; static uint32_t icr = 0; static uint32_t ncores = 1; @@ -329,7 +336,7 @@ void smp_start(uint32_t id) } #endif -#if 1 +#ifdef CONFIG_X86_32 static apic_mp_t* search_apic(size_t base, size_t limit) { size_t ptr; apic_mp_t* tmp; @@ -446,9 +453,11 @@ int map_apic(void) if (!has_apic()) return -ENXIO; +#ifdef CONFIG_X86_32 lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE); if (BUILTIN_EXPECT(!lapic, 0)) return -ENXIO; +#endif kprintf("Mapped LAPIC at 0x%x\n", lapic); if (ioapic) { @@ -569,12 +578,15 @@ static int apic_probe(void) int isa_bus = -1; #if 1 +#ifdef CONFIG_X86_32 apic_mp = search_apic(0xF0000, 0x100000); if (apic_mp) goto found_mp; apic_mp = search_apic(0x9F000, 0xA0000); if (apic_mp) goto found_mp; +#elif defined(CONFIG_X86_64) +#endif #else // searching MP signature in the reserved memory areas if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MEM_MAP)) { @@ -620,7 +632,7 @@ found_mp: goto no_mp; } - apic_config = (apic_config_table_t*) apic_mp->mp_config; + apic_config = (apic_config_table_t*) ((size_t) apic_mp->mp_config); if (!apic_config || strncmp((void*) &apic_config->signature, "PCMP", 4) !=0) { kputs("Invalid MP config table\n"); goto no_mp; @@ -693,11 +705,16 @@ check_lapic: if (apic_config) { lapic = apic_config->lapic; } else { - uint32_t edx, dummy; + uint32_t edx, dummy=0; cpuid(0x1, &dummy, &dummy, &dummy, &edx); if (edx & (1 << 9)) +#ifdef CONFIG_X86_32 lapic = 0xFEE00000; +#else + // On a x64 system, we already map the lapic below the kernel + lapic = (size_t)&kernel_start - 0x1000; +#endif } if (!lapic) diff --git a/arch/x86/kernel/entry64.asm b/arch/x86/kernel/entry64.asm index 5a35099a..0769a044 100644 --- a/arch/x86/kernel/entry64.asm +++ b/arch/x86/kernel/entry64.asm @@ -177,6 +177,30 @@ L0: or ebx, 0x00000003 mov DWORD [edi], ebx + ; check if lapic is available + push eax + push ebx + push ecx + push edx + mov eax, 1 + cpuid + and edx, 0x200 + cmp edx, 0 + je no_lapic + ; map lapic at 0xFEE00000 below the kernel + mov edi, kernel_start + sub edi, 0x1000 + shr edi, 9 ; (edi >> 12) * 8 + add edi, boot_pt + mov ebx, 0xFEE00000 + or ebx, 0x00000013 + mov DWORD [edi], ebx +no_lapic: + pop edx + pop ecx + pop ebx + pop eax + extern kernel_start ; defined in linker script extern kernel_end mov edi, kernel_start