stivale2: Finish implementing x2APIC support

This commit is contained in:
mintsuki 2020-09-27 01:32:47 +02:00
parent b830c71d90
commit e886a6fa76
8 changed files with 122 additions and 14 deletions

View File

@ -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.

Binary file not shown.

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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));

View File

@ -18,7 +18,7 @@ lv5:
smp:
dq 0x1ab015085f3273df
dq 0
dq 0
dq 1
section .bss