initgraph, whole lot of refactor
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <x86_64/asm.h>
|
||||
#include <x86_64/defs.h>
|
||||
#include <x86_64/gdt.h>
|
||||
|
||||
+11
-5
@@ -1,7 +1,10 @@
|
||||
#include <zinnia/acpi.h>
|
||||
#include <zinnia/assert.h>
|
||||
#include <zinnia/clock.h>
|
||||
#include <zinnia/cmdline.h>
|
||||
#include <zinnia/initgraph.h>
|
||||
#include <zinnia/mmio.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/pmap.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/utils.h>
|
||||
@@ -47,15 +50,15 @@ static struct hpet hpet_clock = {
|
||||
},
|
||||
};
|
||||
|
||||
static char table_buf[0x1000];
|
||||
|
||||
void hpet_init() {
|
||||
static void hpet_init(struct boot_info*) {
|
||||
if (!use_hpet)
|
||||
return;
|
||||
|
||||
uacpi_setup_early_table_access(table_buf, sizeof(table_buf));
|
||||
uacpi_table table = {0};
|
||||
assert(!uacpi_table_find_by_signature("HPET", &table), "HPET table not found!\n");
|
||||
if (uacpi_table_find_by_signature("HPET", &table) != UACPI_STATUS_OK) {
|
||||
log("x86_64/hpet: No HPET table found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct acpi_hpet* hpet = table.ptr;
|
||||
|
||||
@@ -73,3 +76,6 @@ void hpet_init() {
|
||||
|
||||
assert(clock_switch(&hpet_clock.clock), "Unable to switch to HPET!\n");
|
||||
}
|
||||
INIT_TASK(hpet_stage, "arch.x86_64.hpet", hpet_init);
|
||||
INIT_DEPENDS(hpet_stage, acpi_stage);
|
||||
INIT_ENTAILS(hpet_stage, percpu_stage);
|
||||
|
||||
@@ -11,19 +11,21 @@
|
||||
#define ELF_ST_BIND ELF64_ST_BIND
|
||||
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||
|
||||
#define elf_ehdr elf64_ehdr
|
||||
#define elf_phdr elf64_phdr
|
||||
#define elf_dyn elf64_dyn
|
||||
#define elf_addr elf64_addr
|
||||
#define elf_off elf64_off
|
||||
#define elf_nhdr elf64_nhdr
|
||||
#define elf_auxv elf64_auxv
|
||||
#define elf_sym elf64_sym
|
||||
#define elf_rela elf64_rela
|
||||
#define elf_rel elf64_rel
|
||||
typedef elf64_ehdr_t elf_ehdr_t;
|
||||
typedef elf64_phdr_t elf_phdr_t;
|
||||
typedef elf64_dyn_t elf_dyn_t;
|
||||
typedef elf64_addr_t elf_addr_t;
|
||||
typedef elf64_off_t elf_off_t;
|
||||
typedef elf64_nhdr_t elf_nhdr_t;
|
||||
typedef elf64_auxv_t elf_auxv_t;
|
||||
typedef elf64_sym_t elf_sym_t;
|
||||
typedef elf64_rela_t elf_rela_t;
|
||||
typedef elf64_rel_t elf_rel_t;
|
||||
typedef elf64_relr_t elf_relr_t;
|
||||
|
||||
enum {
|
||||
R_NONE = 0,
|
||||
R_64 = 1,
|
||||
R_COPY = 5,
|
||||
R_GLOB_DAT = 6,
|
||||
R_JUMP_SLOT = 7,
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void hpet_init();
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <stddef.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <x86_64/gdt.h>
|
||||
|
||||
@@ -17,7 +17,7 @@ struct [[__packed]] smp_info {
|
||||
uint64_t hhdm_offset;
|
||||
uint64_t percpu;
|
||||
uint32_t lapic_id;
|
||||
_Atomic(uint8_t) booted;
|
||||
atomic_bool booted;
|
||||
};
|
||||
|
||||
// Discovers all APs and starts them.
|
||||
|
||||
@@ -23,3 +23,7 @@ kernel_sources += files(
|
||||
'tsc.c',
|
||||
'usercopy.c',
|
||||
)
|
||||
|
||||
if kconfig.get('CONFIG_PCI', 'n') == 'y'
|
||||
kernel_sources += files('pci.c')
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <zinnia/init.h>
|
||||
#include <zinnia/pci.h>
|
||||
#include <zinnia/spin.h>
|
||||
#include <x86_64/asm.h>
|
||||
|
||||
constexpr uint16_t PCI_CONFIG_ADDRESS = 0xcf8;
|
||||
constexpr uint16_t PCI_CONFIG_DATA = 0xcfc;
|
||||
|
||||
static struct spinlock port_lock = {};
|
||||
|
||||
static void port_select(const struct pci_address* addr, uint16_t offset) {
|
||||
asm_outl(
|
||||
PCI_CONFIG_ADDRESS,
|
||||
1u << 31 | (uint32_t)addr->bus << 16 | (uint32_t)(addr->device & 0x1f) << 11 |
|
||||
(uint32_t)(addr->function & 0x7) << 8 | (offset & 0xfc)
|
||||
);
|
||||
}
|
||||
|
||||
static uint32_t port_read32(struct pci_access*, const struct pci_address* addr, uint16_t offset) {
|
||||
spin_lock(&port_lock);
|
||||
port_select(addr, offset);
|
||||
uint32_t value = asm_inl(PCI_CONFIG_DATA);
|
||||
spin_unlock(&port_lock);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void port_write32(struct pci_access*, const struct pci_address* addr, uint16_t offset, uint32_t value) {
|
||||
spin_lock(&port_lock);
|
||||
port_select(addr, offset);
|
||||
asm_outl(PCI_CONFIG_DATA, value);
|
||||
spin_unlock(&port_lock);
|
||||
}
|
||||
|
||||
static struct pci_access port_access = {
|
||||
.name = "port",
|
||||
.domain = 0,
|
||||
.start_bus = 0,
|
||||
.end_bus = 255,
|
||||
.priority = PCI_ACCESS_PRIO_LEGACY,
|
||||
.read32 = port_read32,
|
||||
.write32 = port_write32,
|
||||
};
|
||||
|
||||
[[__init]]
|
||||
static void pci_x86_stage_init(struct boot_info*) {
|
||||
pci_access_register(&port_access);
|
||||
}
|
||||
INIT_TASK(pci_x86_stage, "arch.x86_64.pci", pci_x86_stage_init);
|
||||
INIT_DEPENDS(pci_x86_stage, mem_stage);
|
||||
INIT_ENTAILS(pci_x86_stage, pci_stage);
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <zinnia/initgraph.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <config.h>
|
||||
@@ -6,7 +7,6 @@
|
||||
#include <x86_64/asm.h>
|
||||
#include <x86_64/defs.h>
|
||||
#include <x86_64/gdt.h>
|
||||
#include <x86_64/hpet.h>
|
||||
#include <x86_64/idt.h>
|
||||
#include <x86_64/percpu.h>
|
||||
#include <x86_64/smp.h>
|
||||
@@ -132,7 +132,6 @@ void x86_64_cpu_setup(struct percpu* cpu) {
|
||||
}
|
||||
|
||||
void arch_percpu_init() {
|
||||
hpet_init();
|
||||
#if CONFIG_TSC
|
||||
tsc_init();
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <zinnia/console.h>
|
||||
#include <zinnia/init.h>
|
||||
#include <zinnia/initgraph.h>
|
||||
#include <stdint.h>
|
||||
#include <x86_64/asm.h>
|
||||
|
||||
@@ -44,4 +46,10 @@ static struct console serial_con = {
|
||||
.write = serial_write,
|
||||
.init = serial_setup,
|
||||
};
|
||||
DEFINE_CONSOLE(&serial_con);
|
||||
|
||||
[[__init]]
|
||||
static void serial_init(struct boot_info*) {
|
||||
console_register(&serial_con);
|
||||
}
|
||||
INIT_TASK(serial_stage, "arch.x86_64.serial", serial_init);
|
||||
INIT_ENTAILS(serial_stage, console_stage);
|
||||
|
||||
+17
-13
@@ -1,3 +1,5 @@
|
||||
#define pr_fmt(fmt) "smp: " fmt
|
||||
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/assert.h>
|
||||
#include <zinnia/clock.h>
|
||||
@@ -7,13 +9,13 @@
|
||||
#include <zinnia/pmap.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <zinnia/types.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <zinnia/vma.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/tables.h>
|
||||
#include <x86_64/apic.h>
|
||||
@@ -37,11 +39,12 @@ static void smp_trampoline() {
|
||||
" cld\n"
|
||||
" jmp .Lmode16\n"
|
||||
|
||||
".org smp_trampoline_start + %c[data_off]\n"
|
||||
".global smp_trampoline_data\n"
|
||||
"smp_trampoline_data:\n"
|
||||
" .skip %c[info_size]\n"
|
||||
|
||||
".set .Ldata_offset, (smp_trampoline_data - smp_trampoline_start)\n"
|
||||
".set .Ldata_offset, %c[data_off]\n"
|
||||
".set .Lgdtr_offset, (.Ldata_offset + %c[gdtr])\n"
|
||||
".set .Lfarjmp_offset, (.Ldata_offset + %c[farjmp])\n"
|
||||
".set .Ltemp_stack_offset, (.Ldata_offset + %c[temp_stack])\n"
|
||||
@@ -130,7 +133,8 @@ static void smp_trampoline() {
|
||||
".popsection\n"
|
||||
" ud2\n"
|
||||
:
|
||||
: [info_size] "i"(sizeof(struct smp_info)),
|
||||
: [data_off] "i"(8),
|
||||
[info_size] "i"(sizeof(struct smp_info)),
|
||||
[gdtr] "i"(offsetof(struct smp_info, gdtr)),
|
||||
[farjmp] "i"(offsetof(struct smp_info, farjmp_offset)),
|
||||
[temp_stack] "i"(offsetof(struct smp_info, temp_stack)),
|
||||
@@ -170,7 +174,7 @@ static void ap_entry(phys_t info_addr) {
|
||||
// `info` must not be touched after this point.
|
||||
atomic_store_explicit(&info->booted, 1, memory_order_release);
|
||||
|
||||
log("smp: CPU %zu online\n", cpu->id);
|
||||
log("CPU %zu online\n", cpu->id);
|
||||
|
||||
sched_yield(&cpu->sched);
|
||||
unreachable();
|
||||
@@ -181,18 +185,18 @@ static bool start_ap(phys_t trampoline, uint32_t temp_cr3, uint32_t lapic_id) {
|
||||
|
||||
phys_t stack;
|
||||
if (mem_phys_alloc(AP_BOOT_STACK_SIZE / arch_mem_page_size(), ALLOC_MEM32 | ALLOC_NOZERO, &stack)) {
|
||||
log("smp: Failed to allocate a boot stack for LAPIC %u\n", lapic_id);
|
||||
log_err("Failed to allocate a boot stack for LAPIC %u\n", lapic_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct percpu* cpu = percpu_new();
|
||||
if (!cpu) {
|
||||
log("smp: Failed to allocate per-CPU data for LAPIC %u\n", lapic_id);
|
||||
log_err("Failed to allocate per-CPU data for LAPIC %u\n", lapic_id);
|
||||
mem_phys_free(stack, AP_BOOT_STACK_SIZE / arch_mem_page_size());
|
||||
return false;
|
||||
}
|
||||
|
||||
log("smp: Starting CPU %zu\n", cpu->id);
|
||||
log("Starting CPU %zu\n", cpu->id);
|
||||
|
||||
memcpy(HHDM_PTR(trampoline), smp_trampoline_start, trampoline_size);
|
||||
|
||||
@@ -230,7 +234,7 @@ static bool start_ap(phys_t trampoline, uint32_t temp_cr3, uint32_t lapic_id) {
|
||||
for (uint64_t waited = 0; !atomic_load_explicit(&info->booted, memory_order_acquire); waited += 1'000'000) {
|
||||
if (waited >= AP_BOOT_TIMEOUT_NS) {
|
||||
// The per-CPU data and boot stack are leaked on purpose, in case the AP still comes up.
|
||||
log("smp: CPU %zu (LAPIC %u) did not respond\n", cpu->id, lapic_id);
|
||||
log_err("CPU %zu (LAPIC %u) did not respond\n", cpu->id, lapic_id);
|
||||
return false;
|
||||
}
|
||||
clock_spin_ns(1'000'000);
|
||||
@@ -279,20 +283,20 @@ void x86_64_smp_init() {
|
||||
|
||||
uacpi_table table;
|
||||
if (uacpi_table_find_by_signature(ACPI_MADT_SIGNATURE, &table) != UACPI_STATUS_OK) {
|
||||
log("smp: No MADT found, not starting any APs\n");
|
||||
log_warn("No MADT found, not starting any APs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
phys_t trampoline;
|
||||
if (mem_phys_alloc(1, ALLOC_MEM20, &trampoline)) {
|
||||
log("smp: Failed to allocate 20-bit memory for the AP trampoline\n");
|
||||
log_err("Failed to allocate 20-bit memory for the AP trampoline\n");
|
||||
uacpi_table_unref(&table);
|
||||
return;
|
||||
}
|
||||
|
||||
phys_t temp_table;
|
||||
if (build_temp_table(&temp_table)) {
|
||||
log("smp: Failed to allocate a temporary page table\n");
|
||||
log_err("Failed to allocate a temporary page table\n");
|
||||
mem_phys_free(trampoline, 1);
|
||||
uacpi_table_unref(&table);
|
||||
return;
|
||||
@@ -311,7 +315,7 @@ void x86_64_smp_init() {
|
||||
|
||||
// Don't trust malformed firmware tables.
|
||||
if (hdr->length < sizeof(struct acpi_entry_hdr) || entry + hdr->length > end) {
|
||||
log("smp: MADT contains a malformed entry\n");
|
||||
log_warn("MADT contains a malformed entry\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -348,5 +352,5 @@ void x86_64_smp_init() {
|
||||
mem_phys_free(trampoline, 1);
|
||||
}
|
||||
|
||||
log("smp: %zu CPU(s) online\n", num_cpus);
|
||||
log("%zu CPU(s) online\n", num_cpus);
|
||||
}
|
||||
|
||||
+9
-6
@@ -1,3 +1,4 @@
|
||||
#define pr_fmt(fmt) "x86_64/tsc: " fmt
|
||||
#include <zinnia/clock.h>
|
||||
#include <zinnia/cmdline.h>
|
||||
#include <zinnia/print.h>
|
||||
@@ -42,11 +43,13 @@ static struct clock tsc_clock = {
|
||||
};
|
||||
|
||||
void tsc_init() {
|
||||
if (!use_tsc)
|
||||
if (!use_tsc) {
|
||||
log_warn("TSC disabled on the command line");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(asm_cpuid(1, 0).edx & CPUID_1D_TSC) || !(asm_cpuid(0x8000'0007, 0).edx & (1 << 8))) {
|
||||
log("x86_64/tsc: No invariant TSC detected!\n");
|
||||
log_warn("No invariant TSC detected!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,17 +72,17 @@ void tsc_init() {
|
||||
// On a normal system, this should usually never be called and is a last resort
|
||||
// since at this point we have at least the HPET timer.
|
||||
if (tsc_leaf.ecx != 0 && tsc_leaf.ebx != 0 && tsc_leaf.eax != 0) {
|
||||
log("x86_64/tsc: Calibrating TSC using CPUID 0x15");
|
||||
log("Calibrating TSC using CPUID 0x15");
|
||||
tsc_freq = (uint64_t)tsc_leaf.ecx * tsc_leaf.ebx / tsc_leaf.eax;
|
||||
} else {
|
||||
log("x86_64/tsc: Unable to calibrate TSC using CPUID frequency information");
|
||||
log_err("Unable to calibrate TSC using CPUID frequency information");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
log("x86_64/tsc: Unable to calibrate the TSC without a clock or static frequency info!\n");
|
||||
log_err("Unable to calibrate the TSC without a clock or static frequency info!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
log("x86_64/tsc: Timer frequency is %lu MHz\n", tsc_freq / 1'000'000);
|
||||
log("Timer frequency is %lu MHz\n", tsc_freq / 1'000'000);
|
||||
clock_switch(&tsc_clock);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user