stivale2: Finish implementing x2APIC support
This commit is contained in:
parent
b830c71d90
commit
e886a6fa76
@ -219,7 +219,7 @@ struct stivale2_header_tag_smp {
|
||||
uint64_t identifier; // Identifier: 0x1ab015085f3273df
|
||||
uint64_t next;
|
||||
uint64_t flags; // Flags:
|
||||
// bit 0: 0 = use xAPIC, 1 = use x2APIC
|
||||
// bit 0: 0 = use xAPIC, 1 = use x2APIC (if available)
|
||||
// All other flags are undefined.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
@ -395,6 +395,10 @@ This tag reports to the kernel info about the firmware.
|
||||
struct stivale2_struct_tag_smp {
|
||||
uint64_t identifier; // Identifier: 0x34d1d96339647025
|
||||
uint64_t next;
|
||||
uint64_t flags; // Flags:
|
||||
// bit 0: Set if x2APIC was requested and it
|
||||
// was supported and enabled.
|
||||
// All other bits undefined.
|
||||
uint64_t cpu_count; // Total number of logical CPUs (including BSP)
|
||||
struct stivale2_smp_info smp_info[]; // Array of smp_info structs, one per
|
||||
// logical processor, including BSP.
|
||||
|
BIN
limine.bin
BIN
limine.bin
Binary file not shown.
@ -17,6 +17,7 @@
|
||||
#include <drivers/vbe.h>
|
||||
#include <lib/term.h>
|
||||
#include <sys/pic.h>
|
||||
#include <sys/lapic.h>
|
||||
#include <fs/file.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <stivale/stivale2.h>
|
||||
@ -328,6 +329,8 @@ void stivale2_load(char *cmdline, int boot_drive) {
|
||||
struct stivale2_struct_tag_smp *tag = conv_mem_alloc(sizeof(struct stivale2_struct_tag_smp));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_SMP_ID;
|
||||
|
||||
tag->flags |= (smp_hdr_tag->flags & 1) && x2apic_check();
|
||||
|
||||
init_smp((size_t*)&tag->cpu_count, bits == 64, level5pg && level5pg_requested,
|
||||
pagemap, smp_hdr_tag->flags & 1);
|
||||
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <lib/blib.h>
|
||||
|
||||
#define LAPIC_REG_ICR0 0x300
|
||||
#define LAPIC_REG_ICR1 0x310
|
||||
@ -20,4 +22,33 @@ static inline void lapic_write(uint32_t reg, uint32_t data) {
|
||||
mmoutd((void *)(lapic_mmio_base + reg), data);
|
||||
}
|
||||
|
||||
static inline bool x2apic_check(void) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
cpuid(1, 0, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
if (!(ecx & (1 << 21)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool x2apic_enable(void) {
|
||||
if (!x2apic_check())
|
||||
return false;
|
||||
|
||||
uint64_t ia32_apic_base = rdmsr(0x1b);
|
||||
ia32_apic_base |= (1 << 10);
|
||||
wrmsr(0x1b, ia32_apic_base);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint64_t x2apic_read(uint32_t reg) {
|
||||
return rdmsr(0x800 + (reg >> 4));
|
||||
}
|
||||
|
||||
static inline void x2apic_write(uint32_t reg, uint64_t data) {
|
||||
wrmsr(0x800 + (reg >> 4), data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -29,6 +29,14 @@ struct madt_lapic {
|
||||
uint32_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct madt_x2apic {
|
||||
struct madt_header;
|
||||
uint8_t reserved[2];
|
||||
uint32_t x2apic_id;
|
||||
uint32_t flags;
|
||||
uint32_t acpi_processor_uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct gdtr {
|
||||
uint16_t limit;
|
||||
uint32_t ptr;
|
||||
@ -46,24 +54,36 @@ uint8_t smp_tpl_booted_flag;
|
||||
uint32_t smp_tpl_pagemap;
|
||||
uint8_t smp_tpl_target_mode;
|
||||
|
||||
static bool smp_start_ap(uint8_t lapic_id, struct gdtr *gdtr,
|
||||
static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
|
||||
struct smp_information *info_struct,
|
||||
bool longmode, bool lv5, uint32_t pagemap) {
|
||||
bool longmode, bool lv5, uint32_t pagemap,
|
||||
bool x2apic) {
|
||||
// Prepare the trampoline
|
||||
smp_tpl_info_struct = info_struct;
|
||||
smp_tpl_booted_flag = 0;
|
||||
smp_tpl_pagemap = pagemap;
|
||||
smp_tpl_target_mode = ((uint32_t)lv5 << 1) | (uint32_t)longmode;
|
||||
smp_tpl_target_mode = ((uint32_t)x2apic << 2)
|
||||
| ((uint32_t)lv5 << 1)
|
||||
| (uint32_t)longmode;
|
||||
smp_tpl_gdt = *gdtr;
|
||||
|
||||
// Send the INIT IPI
|
||||
lapic_write(LAPIC_REG_ICR1, lapic_id << 24);
|
||||
lapic_write(LAPIC_REG_ICR0, 0x500);
|
||||
if (x2apic) {
|
||||
x2apic_write(LAPIC_REG_ICR0, ((uint64_t)lapic_id << 32) | 0x500);
|
||||
} else {
|
||||
lapic_write(LAPIC_REG_ICR1, lapic_id << 24);
|
||||
lapic_write(LAPIC_REG_ICR0, 0x500);
|
||||
}
|
||||
delay(5000);
|
||||
|
||||
// Send the Startup IPI
|
||||
lapic_write(LAPIC_REG_ICR1, lapic_id << 24);
|
||||
lapic_write(LAPIC_REG_ICR0, ((size_t)smp_trampoline / 4096) | 0x600);
|
||||
if (x2apic) {
|
||||
x2apic_write(LAPIC_REG_ICR0, ((uint64_t)lapic_id << 32) |
|
||||
((size_t)smp_trampoline / 4096) | 0x600);
|
||||
} else {
|
||||
lapic_write(LAPIC_REG_ICR1, lapic_id << 24);
|
||||
lapic_write(LAPIC_REG_ICR0, ((size_t)smp_trampoline / 4096) | 0x600);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (locked_read(&smp_tpl_booted_flag) == 1) {
|
||||
@ -92,6 +112,8 @@ struct smp_information *init_smp(size_t *cpu_count,
|
||||
struct smp_information *ret = conv_mem_alloc_aligned(0, 1);
|
||||
*cpu_count = 0;
|
||||
|
||||
x2apic = x2apic && x2apic_enable();
|
||||
|
||||
// Parse the MADT entries
|
||||
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
|
||||
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->length;
|
||||
@ -99,9 +121,6 @@ struct smp_information *init_smp(size_t *cpu_count,
|
||||
switch (*madt_ptr) {
|
||||
case 0: {
|
||||
// Processor local xAPIC
|
||||
if (x2apic)
|
||||
continue;
|
||||
|
||||
struct madt_lapic *lapic = (void *)madt_ptr;
|
||||
|
||||
// Check if we can actually try to start the AP
|
||||
@ -120,11 +139,51 @@ struct smp_information *init_smp(size_t *cpu_count,
|
||||
continue;
|
||||
}
|
||||
|
||||
print("smp: Found candidate AP for bring-up. LAPIC ID: %u\n", lapic->lapic_id);
|
||||
print("smp: [xAPIC] Found candidate AP for bring-up. LAPIC ID: %u\n", lapic->lapic_id);
|
||||
|
||||
// Try to start the AP
|
||||
if (!smp_start_ap(lapic->lapic_id, &gdtr, info_struct,
|
||||
longmode, lv5, (uint32_t)pagemap.top_level)) {
|
||||
longmode, lv5, (uint32_t)pagemap.top_level,
|
||||
x2apic)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
conv_mem_rewind(sizeof(struct smp_information));
|
||||
continue;
|
||||
}
|
||||
|
||||
print("smp: Successfully brought up AP\n");
|
||||
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
case 9: {
|
||||
// Processor local x2APIC
|
||||
if (!x2apic)
|
||||
continue;
|
||||
|
||||
struct madt_x2apic *x2apic = (void *)madt_ptr;
|
||||
|
||||
// Check if we can actually try to start the AP
|
||||
if (!((x2apic->flags & 1) ^ ((x2apic->flags >> 1) & 1)))
|
||||
continue;
|
||||
|
||||
struct smp_information *info_struct =
|
||||
conv_mem_alloc_aligned(sizeof(struct smp_information), 1);
|
||||
|
||||
info_struct->acpi_processor_uid = x2apic->acpi_processor_uid;
|
||||
info_struct->lapic_id = x2apic->x2apic_id;
|
||||
|
||||
// Do not try to restart the BSP
|
||||
if (x2apic->x2apic_id == 0) {
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
print("smp: [x2APIC] Found candidate AP for bring-up. LAPIC ID: %u\n", x2apic->x2apic_id);
|
||||
|
||||
// Try to start the AP
|
||||
if (!smp_start_ap(x2apic->x2apic_id, &gdtr, info_struct,
|
||||
longmode, lv5, (uint32_t)pagemap.top_level,
|
||||
true)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
conv_mem_rewind(sizeof(struct smp_information));
|
||||
continue;
|
||||
|
@ -36,6 +36,16 @@ smp_trampoline:
|
||||
btr eax, 30
|
||||
mov cr0, eax
|
||||
|
||||
test dword [smp_tpl_target_mode], (1 << 2)
|
||||
jz .nox2apic
|
||||
|
||||
mov ecx, 0x1b
|
||||
rdmsr
|
||||
bts eax, 10
|
||||
bts eax, 11
|
||||
wrmsr
|
||||
|
||||
.nox2apic:
|
||||
test dword [smp_tpl_target_mode], (1 << 0)
|
||||
jz parking32
|
||||
|
||||
|
@ -141,6 +141,7 @@ struct stivale2_smp_info {
|
||||
|
||||
struct stivale2_struct_tag_smp {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t flags;
|
||||
uint64_t cpu_count;
|
||||
struct stivale2_smp_info smp_info[];
|
||||
} __attribute__((packed));
|
||||
|
@ -18,7 +18,7 @@ lv5:
|
||||
smp:
|
||||
dq 0x1ab015085f3273df
|
||||
dq 0
|
||||
dq 0
|
||||
dq 1
|
||||
|
||||
section .bss
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user