add LAPIC support of the 64bit kernel

This commit is contained in:
Stefan Lankes 2012-06-10 21:38:01 +02:00
parent 609500a6d8
commit 654e91b0a2
3 changed files with 46 additions and 7 deletions

View file

@ -151,7 +151,7 @@ inline static void wmb(void) { asm volatile("sfence" ::: "memory"); }
* @param d EDX value will be stores here * @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) { 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 /** @brief Read MSR
@ -335,9 +335,7 @@ uint32_t read_eip(void);
inline static int system_init(void) inline static int system_init(void)
{ {
gdt_install(); gdt_install();
#ifdef CONFIG_X86_32
apic_init(); apic_init();
#endif
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
pci_init(); pci_init();
#endif #endif

View file

@ -42,6 +42,13 @@
#error RockCreek is not a SMP system #error RockCreek is not a SMP system
#endif #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. // IO APIC MMIO structure: write reg, then read or write data.
typedef struct { typedef struct {
uint32_t reg; 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 uint32_t boot_processor = MAX_CORES;
static apic_mp_t* apic_mp = NULL; static apic_mp_t* apic_mp = NULL;
static apic_config_table_t* apic_config = 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 volatile ioapic_t* ioapic = NULL;
static uint32_t icr = 0; static uint32_t icr = 0;
static uint32_t ncores = 1; static uint32_t ncores = 1;
@ -329,7 +336,7 @@ void smp_start(uint32_t id)
} }
#endif #endif
#if 1 #ifdef CONFIG_X86_32
static apic_mp_t* search_apic(size_t base, size_t limit) { static apic_mp_t* search_apic(size_t base, size_t limit) {
size_t ptr; size_t ptr;
apic_mp_t* tmp; apic_mp_t* tmp;
@ -446,9 +453,11 @@ int map_apic(void)
if (!has_apic()) if (!has_apic())
return -ENXIO; return -ENXIO;
#ifdef CONFIG_X86_32
lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE); lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
if (BUILTIN_EXPECT(!lapic, 0)) if (BUILTIN_EXPECT(!lapic, 0))
return -ENXIO; return -ENXIO;
#endif
kprintf("Mapped LAPIC at 0x%x\n", lapic); kprintf("Mapped LAPIC at 0x%x\n", lapic);
if (ioapic) { if (ioapic) {
@ -569,12 +578,15 @@ static int apic_probe(void)
int isa_bus = -1; int isa_bus = -1;
#if 1 #if 1
#ifdef CONFIG_X86_32
apic_mp = search_apic(0xF0000, 0x100000); apic_mp = search_apic(0xF0000, 0x100000);
if (apic_mp) if (apic_mp)
goto found_mp; goto found_mp;
apic_mp = search_apic(0x9F000, 0xA0000); apic_mp = search_apic(0x9F000, 0xA0000);
if (apic_mp) if (apic_mp)
goto found_mp; goto found_mp;
#elif defined(CONFIG_X86_64)
#endif
#else #else
// searching MP signature in the reserved memory areas // searching MP signature in the reserved memory areas
if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MEM_MAP)) { if (mb_info && (mb_info->flags & MULTIBOOT_INFO_MEM_MAP)) {
@ -620,7 +632,7 @@ found_mp:
goto no_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) { if (!apic_config || strncmp((void*) &apic_config->signature, "PCMP", 4) !=0) {
kputs("Invalid MP config table\n"); kputs("Invalid MP config table\n");
goto no_mp; goto no_mp;
@ -693,11 +705,16 @@ check_lapic:
if (apic_config) { if (apic_config) {
lapic = apic_config->lapic; lapic = apic_config->lapic;
} else { } else {
uint32_t edx, dummy; uint32_t edx, dummy=0;
cpuid(0x1, &dummy, &dummy, &dummy, &edx); cpuid(0x1, &dummy, &dummy, &dummy, &edx);
if (edx & (1 << 9)) if (edx & (1 << 9))
#ifdef CONFIG_X86_32
lapic = 0xFEE00000; lapic = 0xFEE00000;
#else
// On a x64 system, we already map the lapic below the kernel
lapic = (size_t)&kernel_start - 0x1000;
#endif
} }
if (!lapic) if (!lapic)

View file

@ -177,6 +177,30 @@ L0:
or ebx, 0x00000003 or ebx, 0x00000003
mov DWORD [edi], ebx 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_start ; defined in linker script
extern kernel_end extern kernel_end
mov edi, kernel_start mov edi, kernel_start