Added AP initialization code

This commit is contained in:
Mark
2019-10-09 23:45:19 +03:00
parent c3cc760b2c
commit 992e08a93a
11 changed files with 258 additions and 26 deletions
+2
View File
@@ -34,4 +34,6 @@ typedef struct {
uintptr_t offset;
} __attribute__((packed)) amd64_gdt_ptr_t;
extern amd64_gdt_ptr_t amd64_gdtr;
void amd64_gdt_init(void);
+8
View File
@@ -1,3 +1,11 @@
#pragma once
#include "sys/types.h"
struct amd64_idtr {
uint16_t size;
uintptr_t offset;
} __attribute__((packed));
extern const struct amd64_idtr amd64_idtr;
void amd64_idt_init(void);
+12 -1
View File
@@ -1,5 +1,7 @@
include sys/amd64/compiler.mk
.PHONY+=$(O)/sys/amd64/hw/ap_code_blob.o
all:
### Kernel build
DEFINES+=-DARCH_AMD64
@@ -12,7 +14,8 @@ OBJS+=$(O)/sys/amd64/hw/rs232.o \
$(O)/sys/amd64/hw/apic.o \
$(O)/sys/amd64/hw/idt.o \
$(O)/sys/amd64/hw/exc_s.o \
$(O)/sys/amd64/hw/irq0.o
$(O)/sys/amd64/hw/irq0.o \
$(O)/sys/amd64/hw/ap_code_blob.o
kernel_OBJS=$(O)/sys/amd64/entry.o \
$(OBJS)
kernel_LINKER=sys/amd64/link.ld
@@ -59,6 +62,14 @@ $(O)/sys/%.o: sys/%.c $(HEADERS)
@printf " CC\t%s\n" $(@:$(O)/%=%)
@$(CC64) $(kernel_CFLAGS) -c -o $@ $<
$(O)/sys/amd64/hw/ap_code_blob.o: $(O)/sys/amd64/hw/ap_code.bin
@printf " AS\t%s\n" $(@:$(O)/%=%)
@$(CC64) $(kernel_CFLAGS) -c -DAP_CODE_BIN='"$<"' -o $@ sys/amd64/hw/ap_code_blob.S
$(O)/sys/amd64/hw/ap_code.bin: sys/amd64/hw/ap_code.nasm
@printf " NASM\t%s\n" $(@:$(O)/%=%)
@nasm -f bin -o $@ $<
### Kernel loader build
TARGETS+=$(O)/sys/amd64/image.iso
DIRS+=$(O)/sys/amd64/loader
+8
View File
@@ -13,7 +13,15 @@ _start:
hlt
jmp 1b
// Entrypoint for AP bootstrap code
.global ap_kernel_stacks_top
.section .bss
kernel_stack_bottom:
.skip 65536
kernel_stack_top:
.set MAX_CPUS, 4
ap_kernel_stacks_bottom:
.skip 65536 * (MAX_CPUS - 1)
ap_kernel_stacks_top:
+111
View File
@@ -0,0 +1,111 @@
; vi: ft=asm :
org 0x7000
bits 16
; Application processor bootstrapping code
; --------------------------------------------
; Parameters passed to us from BSP:
; 0x7FC0 Kernel PML4 physical address
; 0x7FC8 GDTR physical address
; 0x7FD0 IDTR
; 0x7FD8 Kernel AP core entrypoint
; 0x7FE0 Kernel AP stack
; --------------------------------------------
ap_startup:
cli
mov ax, 0
mov ds, ax
; Disable NMI
in al, 0x70
or al, 0x80
out 0x70, al
; Load protected-mode GDT
lgdt [ap_prot_gdtr]
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x08:ap_startup_prot
bits 32
ap_startup_prot:
cli
mov eax, 0x10
mov ds, eax
; Enable PAE, PSE
mov eax, cr4
or eax, (1 << 5) | (1 << 4)
mov cr4, eax
; Load cr3 = PML4
mov eax, dword [0x7FC0]
mov cr3, eax
; Enable EFER.LME
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
; Enable paging
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
; Load long-mode GDT (will be reloaded with upper address)
mov eax, [0x7FC8]
lgdt [eax]
jmp 0x08:ap_startup_long
bits 64
align 8
ap_startup_long:
mov rax, 0x10
mov ds, rax
; Reload GDT from upper memory pointer
mov rax, [0x7FC8]
mov rcx, 0xFFFFFF0000000000
add rax, rcx
lgdt [rax]
mov rax, 0x10
mov ds, rax
mov ss, rax
mov es, rax
mov fs, rax
mov gs, rax
; Load IDT
mov rax, qword [0x7FD0]
lidt [rax]
; Load stack
mov rsp, qword [0x7FE0]
; Jump to kernel entry
mov rax, qword [0x7FD8]
jmp rax
; Protected-mode GDT
align 4
ap_prot_gdt:
; 0x00 - Null
dq 0
; 0x08 - Code: 32-bit, ex, pr, sys
dq 0xCF98000000FFFF
; 0x10 - Data: 32-bit, rw, pr, sys
dq 0xCF92000000FFFF
ap_prot_gdt_end:
ap_prot_gdtr:
dw ap_prot_gdt_end - ap_prot_gdt - 1
dd ap_prot_gdt
+8
View File
@@ -0,0 +1,8 @@
.section .rodata
.global amd64_ap_code_start
.global amd64_ap_code_end
.align 8
amd64_ap_code_start:
.incbin AP_CODE_BIN
amd64_ap_code_end:
+99 -6
View File
@@ -1,4 +1,8 @@
#include "sys/amd64/hw/apic.h"
#include "sys/amd64/hw/gdt.h"
#include "sys/amd64/hw/idt.h"
#include "sys/amd64/mm/mm.h"
#include "sys/string.h"
#include "sys/debug.h"
#define IA32_APIC_BASE_MSR 0x1B
@@ -27,12 +31,6 @@ static uint64_t rdmsr(uint32_t addr) {
return v;
}
// static void wrmsr(uint32_t addr, uint64_t v) {
// uint32_t low = v & 0xFFFFFFFF;
// uint32_t high = v >> 32;
// asm volatile ("wrmsr"::"c"(addr),"d"(high),"a"(low));
// }
/////
struct acpi_apic_field_type {
@@ -65,6 +63,10 @@ static uint32_t bsp_lapic_id;
// (mapped to per-CPU LAPICs, while the address is the same)
static uintptr_t lapic_base;
extern char ap_kernel_stacks_top[];
// TODO: use mutual exclusion for this
static size_t started_up_aps = 0;
/////
static uintptr_t amd64_apic_base(void) {
@@ -86,6 +88,76 @@ static void amd64_pic8259_disable(void) {
);
}
static void amd64_ap_code_entry(void) {
// Can do this as core should've bootstrapped BEFORE BSP checks this value again
++started_up_aps;
while (1) {
asm ("cli; hlt");
}
}
static void amd64_load_ap_code(void) {
extern const char amd64_ap_code_start[];
extern const char amd64_ap_code_end[];
//extern void amd64_ap_code_entry(void);
size_t ap_code_size = (uintptr_t) amd64_ap_code_end - (uintptr_t) amd64_ap_code_start;
// Startup vector physical address, below 1M boundary
uintptr_t physical_address = 0x7000;
// Load code at 0x7000
memcpy((void *) (0xFFFFFF0000000000 + 0x7000), amd64_ap_code_start, ap_code_size);
// These parameters are shared and may be loaded only once
// Write AP code startup parameters
extern mm_space_t mm_kernel;
uintptr_t mm_kernel_phys = (uintptr_t) mm_kernel - 0xFFFFFF0000000000;
uintptr_t amd64_gdtr_phys = (uintptr_t) &amd64_gdtr - 0xFFFFFF0000000000;
// 0x7FC0 - MM_PHYS(mm_kernel)
*((uint64_t *) 0xFFFFFF0000007FC0) = mm_kernel_phys;
// 0x7FC8 - MM_PHYS(amd64_gdtr)
*((uint64_t *) 0xFFFFFF0000007FC8) = amd64_gdtr_phys;
// 0x7FD0 - amd64_idtr
*((uint64_t *) 0xFFFFFF0000007FD0) = (uintptr_t) &amd64_idtr;
// 0x7FD8 - amd64_core_entry
*((uint64_t *) 0xFFFFFF0000007FD8) = (uintptr_t) amd64_ap_code_entry;
}
static void amd64_set_ap_params(void) {
// Allocate a new AP kernel stack
uintptr_t stack_ptr = (uintptr_t) ap_kernel_stacks_top - started_up_aps * 65536;
// 0x7FE0 - stack_ptr
*((uint64_t *) 0xFFFFFF0000007FE0) = stack_ptr;
}
static void amd64_core_wakeup(uint8_t core_id) {
amd64_set_ap_params();
uint8_t entry_vector = 0x7000 >> 12;
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_CMD1) = ((uint32_t) core_id) << 24;
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_CMD0) = entry_vector | (5 << 8) | (1 << 14);
for (uint64_t i = 0; i < 1000000; ++i);
size_t old_ap_count = started_up_aps;
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_CMD1) = ((uint32_t) core_id) << 24;
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_CMD0) = entry_vector | (6 << 8) | (1 << 14);
for (uint64_t i = 0; i < 10000000; ++i);
if (started_up_aps == old_ap_count) {
kdebug("AP failed to start: LAPIC ID %d\n", core_id);
while (1) {
asm ("cli; hlt");
};
}
}
void amd64_apic_init(struct acpi_madt *madt) {
// Get LAPIC base
lapic_base = amd64_apic_base() + 0xFFFFFF0000000000;
@@ -107,4 +179,25 @@ void amd64_apic_init(struct acpi_madt *madt) {
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_LVTT) = 32 | 0x20000;
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_TMRDIV) = 0x3;
*(uint32_t *) (lapic_base + IA32_LAPIC_REG_TMRINITCNT) = 100000;
// Load the code APs are expected to run
amd64_load_ap_code();
// Get other LAPICs from MADT
size_t offset = 0;
while (offset < madt->hdr.length - sizeof(struct acpi_madt)) {
struct acpi_apic_field_type *ent_hdr = (struct acpi_apic_field_type *) &madt->entry[offset];
if (ent_hdr->type == 0) {
// LAPIC entry
struct acpi_lapic_entry *ent = (struct acpi_lapic_entry *) ent_hdr;
// It's not us
if (ent->apic_id != bsp_lapic_id) {
// Initiate wakeup sequence
amd64_core_wakeup(ent->apic_id);
}
}
offset += ent_hdr->length;
}
}
+2 -2
View File
@@ -4,7 +4,7 @@
extern void amd64_gdt_load(void *p);
static amd64_gdt_entry_t gdt[GDT_SIZE] = { 0 };
static amd64_gdt_ptr_t gdtr = {
amd64_gdt_ptr_t amd64_gdtr = {
sizeof(gdt) - 1,
(uintptr_t) gdt
};
@@ -42,5 +42,5 @@ void amd64_gdt_init(void) {
0,
GDT_ACC_PR | GDT_ACC_S | GDT_ACC_RW);
amd64_gdt_load(&gdtr);
amd64_gdt_load(&amd64_gdtr);
}
+2 -5
View File
@@ -27,10 +27,7 @@ static struct amd64_idt_entry {
uint32_t zero1;
} __attribute__((packed)) idt[256] __attribute__((aligned(0x10)));
static const struct {
uint16_t size;
uintptr_t offset;
} __attribute__((packed)) idtr __attribute__((aligned(0x10))) = {
const struct amd64_idtr amd64_idtr = {
.size = sizeof(idt) - 1,
.offset = (uintptr_t) idt
};
@@ -52,5 +49,5 @@ void amd64_idt_init(void) {
}
amd64_idt_set(32, (uintptr_t) amd64_irq0, 0x08, IDT_FLG_P | IDT_FLG_R0 | IDT_FLG_INT32);
asm volatile ("lidt idtr(%rip)");
asm volatile ("lidt amd64_idtr(%rip)");
}
+3 -11
View File
@@ -1,11 +1,6 @@
.section .text
.global amd64_irq0
amd64_irq0:
pushq %rax
movq $0xFFFFFF00FEE000B0, %rax
movl $0, (%rax)
popq %rax
pushq %rax
pushq %rcx
pushq %rdx
@@ -14,9 +9,9 @@ amd64_irq0:
pushq %rdi
pushq %rsi
xorq %rdi, %rdi
leaq _tmr_msg(%rip), %rsi
call debugs
// EOI
movq $0xFFFFFF00FEE000B0, %rax
movl $0, (%rax)
popq %rsi
popq %rdi
@@ -27,6 +22,3 @@ amd64_irq0:
popq %rax
iretq
_tmr_msg:
.string "T!\n"
+3 -1
View File
@@ -27,6 +27,8 @@ void amd64_mm_init(struct amd64_loader_data *data) {
memset((void *) (0x200000 - 2 * 0x1000), 0, 0x1000 * 2);
// 0x0000000000000000 -> 0 Mapping for AP bootstrapping
pml4[0] = ((uintptr_t) pdpt) | 1 | 2 | 4;
// 0xFFFFFF0000000000 -> 0 (512GiB) mapping
pml4[AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 39] = ((uintptr_t) pdpt) | 1 | 2 | 4;
for (uint64_t i = 0; i < 4; ++i) {
@@ -40,7 +42,7 @@ void amd64_mm_init(struct amd64_loader_data *data) {
// Create a pool located right after kernel image
// amd64_mm_pool_init((uintptr_t) &_kernel_end, MM_POOL_SIZE);
// mm_kernel = (mm_space_t) (MM_VIRTUALIZE(pml4));
mm_kernel = (mm_space_t) (MM_VIRTUALIZE(pml4));
// // Allocate some pages for kernel heap (base size: 16MiB)
// uintptr_t heap_base_phys = amd64_phys_alloc_contiguous(KERNEL_HEAP >> 12);