diff --git a/arch/x86/mp.c b/arch/x86/mp.c index d0173aa0..96e20c84 100644 --- a/arch/x86/mp.c +++ b/arch/x86/mp.c @@ -15,6 +15,8 @@ #include #include +#if WITH_SMP + // the boot cpu's percpu struct static x86_percpu_t x86_boot_percpu; // pointer to an array of percpu structs for each of the secondary cpus @@ -47,7 +49,6 @@ void x86_percpu_init_early(uint cpu_num, uint apic_id) { x86_set_gdt_descriptor(selector, percpu, sizeof(*percpu), 1, 0, 1, SEG_TYPE_DATA_RW, 0, 1); x86_set_gs(selector); #endif - __UNUSED volatile uint foo = x86_get_cpu_num(); } status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) { @@ -56,3 +57,9 @@ status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) { void arch_mp_init_percpu(void) { } + +#else + +void x86_percpu_init_early(uint cpu_num, uint apic_id) {} + +#endif \ No newline at end of file diff --git a/lib/acpi_lite/acpi_lite.cpp b/lib/acpi_lite/acpi_lite.cpp index beb1c2b5..5752a586 100644 --- a/lib/acpi_lite/acpi_lite.cpp +++ b/lib/acpi_lite/acpi_lite.cpp @@ -407,7 +407,7 @@ void acpi_lite_dump_tables(bool full_dump) { } } -status_t acpi_process_madt_entries_etc(const uint8_t search_type, const madt_entry_callback callback) { +status_t acpi_process_madt_entries_etc(const uint8_t search_type, const madt_entry_callback callback, void *cookie) { const acpi_madt_table* madt = reinterpret_cast(acpi_get_table_by_sig(ACPI_MADT_SIG)); if (!madt) { @@ -417,14 +417,17 @@ status_t acpi_process_madt_entries_etc(const uint8_t search_type, const madt_ent // bytewise array of the same table const uint8_t* madt_array = reinterpret_cast(madt); + LTRACEF("table at %p\n", madt_array); + // walk the table off the end of the header, looking for the requested type size_t off = sizeof(*madt); while (off < madt->header.length) { uint8_t type = madt_array[off]; uint8_t length = madt_array[off + 1]; + LTRACEF("type %u, length %u\n", type, length); if (type == search_type) { - callback(static_cast(&madt_array[off]), length); + callback(static_cast(&madt_array[off]), length, cookie); } off += length; @@ -433,4 +436,32 @@ status_t acpi_process_madt_entries_etc(const uint8_t search_type, const madt_ent return NO_ERROR; } +void acpi_lite_dump_madt_table() { + auto local_apic_callback = [](const void *_entry, size_t entry_len, void *cookie) { + const auto *entry = reinterpret_cast(_entry); + + printf("\tLOCAL APIC id %d, processor id %d, flags %#x\n", + entry->apic_id, entry->processor_id, entry->flags); + }; + + auto io_apic_callback = [](const void *_entry, size_t entry_len, void *cookie) { + const auto *entry = reinterpret_cast(_entry); + + printf("\tIO APIC id %d, address %#x gsi base %u\n", + entry->io_apic_id, entry->io_apic_address, entry->global_system_interrupt_base); + }; + + auto int_source_override_callback = [](const void *_entry, size_t entry_len, void *cookie) { + const auto *entry = reinterpret_cast(_entry); + + printf("\tINT OVERRIDE bus %u, source %u, gsi %u, flags %#x\n", + entry->bus, entry->source, entry->global_sys_interrupt, entry->flags); + }; + printf("MADT/APIC table:\n"); + acpi_process_madt_entries_etc(ACPI_MADT_TYPE_LOCAL_APIC, local_apic_callback, nullptr); + acpi_process_madt_entries_etc(ACPI_MADT_TYPE_IO_APIC, io_apic_callback, nullptr); + acpi_process_madt_entries_etc(ACPI_MADT_TYPE_INT_SOURCE_OVERRIDE, int_source_override_callback, nullptr); +} + + // vim: set ts=2 sw=2 expandtab: diff --git a/lib/acpi_lite/include/lib/acpi_lite.h b/lib/acpi_lite/include/lib/acpi_lite.h index 47a63942..01fbaadf 100644 --- a/lib/acpi_lite/include/lib/acpi_lite.h +++ b/lib/acpi_lite/include/lib/acpi_lite.h @@ -17,12 +17,14 @@ __BEGIN_CDECLS status_t acpi_lite_init(paddr_t rsdt); void acpi_lite_dump_tables(bool full_dump); +void acpi_lite_dump_madt_table(void); const struct acpi_sdt_header* acpi_get_table_by_sig(const char* sig); // A routine to iterate over all the MADT entries of a particular type via a callback //using MadtEntryCallback = fbl::Function; -typedef void (*madt_entry_callback)(const void* entry, size_t entry_len); -status_t acpi_process_madt_entries_etc(uint8_t search_type, const madt_entry_callback); +typedef void (*madt_entry_callback)(const void* entry, size_t entry_len, void *cookie); +status_t acpi_process_madt_entries_etc(uint8_t search_type, const madt_entry_callback, void *cookie); + __END_CDECLS diff --git a/lib/acpi_lite/include/lib/acpi_lite/structs.h b/lib/acpi_lite/include/lib/acpi_lite/structs.h index b84c810d..df9d0d5c 100644 --- a/lib/acpi_lite/include/lib/acpi_lite/structs.h +++ b/lib/acpi_lite/include/lib/acpi_lite/structs.h @@ -230,6 +230,7 @@ static_assert(sizeof(struct acpi_madt_int_source_override_entry) == 10, ""); #define ACPI_MADT_FLAG_TRIGGER_MASK 0b1100 // DBG2 table +// From https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/acpi-debug-port-table #define ACPI_DBG2_SIG "DBG2" struct acpi_dbg2_table { struct acpi_sdt_header header; @@ -263,7 +264,13 @@ static_assert(sizeof(struct acpi_dbg2_device) == 22, ""); // debug port subtypes #define ACPI_DBG2_SUBTYPE_16550_COMPATIBLE 0x0000 #define ACPI_DBG2_SUBTYPE_16550_SUBSET 0x0001 +#define ACPI_DBG2_SUBTYPE_PL011 0x0003 +#define ACPI_DBG2_SUBTYPE_ARM_SBSA 0x000e +#define ACPI_DBG2_SUBTYPE_16550_DESCRIBED 0x0012 +#define ACPI_DBG2_SUBTYPE_RISCV_SBI 0x0015 + #define ACPI_DBG2_SUBTYPE_1394_STANDARD 0x0000 + #define ACPI_DBG2_SUBTYPE_USB_XHCI 0x0000 #define ACPI_DBG2_SUBTYPE_USB_EHCI 0x0001 diff --git a/platform/pc/mp.c b/platform/pc/mp.c new file mode 100644 index 00000000..2df28721 --- /dev/null +++ b/platform/pc/mp.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ + +#include "platform_p.h" + +#include +#include +#include + +#define LOCAL_TRACE 1 + +static void start_cpu(uint cpu_num, uint32_t apic_id) { + LTRACEF("cpu_num %u, apic_id %u\n", cpu_num, apic_id); + + // XXX do work here +} + +struct detected_cpus { + uint32_t num_detected; + uint32_t apic_ids[SMP_MAX_CPUS]; +}; + +static void local_apic_callback(const void *_entry, size_t entry_len, void *cookie) { + const struct acpi_madt_local_apic_entry *entry = _entry; + struct detected_cpus *cpus = cookie; + + if (entry->apic_id == 0) { + // skip the boot cpu + return; + } + if (cpus->num_detected < SMP_MAX_CPUS) { + cpus->apic_ids[cpus->num_detected++] = entry->apic_id; + } +} + +void platform_start_secondary_cpus(void) { + struct detected_cpus cpus; + cpus.num_detected = 1; + cpus.apic_ids[0] = 0; // the boot cpu + + acpi_process_madt_entries_etc(ACPI_MADT_TYPE_LOCAL_APIC, &local_apic_callback, &cpus); + + // TODO: fall back to legacy methods if ACPI fails + // TODO: deal with cpu topology + + // start up the secondary cpus + if (cpus.num_detected > 1) { + dprintf(INFO, "PC: detected %u cpus\n", cpus.num_detected); + + lk_init_secondary_cpus(cpus.num_detected - 1); + + for (uint i = 1; i < cpus.num_detected; i++) { + dprintf(INFO, "PC: starting cpu %u\n", cpus.apic_ids[i]); + start_cpu(i, cpus.apic_ids[i]); + } + } +} + diff --git a/platform/pc/platform.c b/platform/pc/platform.c index c01c248e..7bd968ac 100644 --- a/platform/pc/platform.c +++ b/platform/pc/platform.c @@ -13,7 +13,6 @@ #include #include #include -#include "platform_p.h" #include #include #include @@ -22,12 +21,13 @@ #include #include #include -#include #include #include #include #include +#include "platform_p.h" + #if WITH_DEV_BUS_PCI #include #endif @@ -218,44 +218,28 @@ void platform_early_init(void) { dprintf(INFO, "PC: total memory detected %" PRIu64 " bytes\n", total_mem); } -void local_apic_callback(const void *_entry, size_t entry_len) { - const struct acpi_madt_local_apic_entry *entry = _entry; - - printf("\tLOCAL APIC id %d, processor id %d, flags %#x\n", - entry->apic_id, entry->processor_id, entry->flags); -} - -void io_apic_callback(const void *_entry, size_t entry_len) { - const struct acpi_madt_io_apic_entry *entry = _entry; - - printf("\tIO APIC id %d, address %#x gsi base %u\n", - entry->io_apic_id, entry->io_apic_address, entry->global_system_interrupt_base); -} - -void int_source_override_callback(const void *_entry, size_t entry_len) { - const struct acpi_madt_int_source_override_entry *entry = _entry; - - printf("\tINT OVERRIDE bus %u, source %u, gsi %u, flags %#x\n", - entry->bus, entry->source, entry->global_sys_interrupt, entry->flags); -} - void platform_init(void) { platform_init_debug(); platform_init_keyboard(&console_input_buf); -#if WITH_DEV_BUS_PCI - bool pci_initted = false; + // Look for the root ACPI table + bool found_acpi = false; if (acpi_lite_init(0) == NO_ERROR) { if (LOCAL_TRACE) { acpi_lite_dump_tables(false); } + acpi_lite_dump_madt_table(); + found_acpi = true; + } - // dump the APIC table - printf("MADT/APIC table:\n"); - acpi_process_madt_entries_etc(ACPI_MADT_TYPE_LOCAL_APIC, &local_apic_callback); - acpi_process_madt_entries_etc(ACPI_MADT_TYPE_IO_APIC, &io_apic_callback); - acpi_process_madt_entries_etc(ACPI_MADT_TYPE_INT_SOURCE_OVERRIDE, &int_source_override_callback); + // Look for secondary cpus + platform_start_secondary_cpus(); + +#if WITH_DEV_BUS_PCI + bool pci_initted = false; + if (found_acpi) { + // TODO: handle interrupt source overrides from the MADT table // try to find the mcfg table const struct acpi_mcfg_table *table = (const struct acpi_mcfg_table *)acpi_get_table_by_sig(ACPI_MCFG_SIG); diff --git a/platform/pc/platform_p.h b/platform/pc/platform_p.h index 59e340fd..516aea8e 100644 --- a/platform/pc/platform_p.h +++ b/platform/pc/platform_p.h @@ -26,3 +26,5 @@ void pic_mask_interrupts(void); void lapic_init(void); void lapic_eoi(unsigned int vector); +// secondary cpus +void platform_start_secondary_cpus(void); diff --git a/platform/pc/rules.mk b/platform/pc/rules.mk index 9b62107d..dba1abfe 100644 --- a/platform/pc/rules.mk +++ b/platform/pc/rules.mk @@ -23,6 +23,7 @@ MODULE_SRCS += \ $(LOCAL_DIR)/interrupts.c \ $(LOCAL_DIR)/keyboard.c \ $(LOCAL_DIR)/lapic.c \ + $(LOCAL_DIR)/mp.c \ $(LOCAL_DIR)/pic.c \ $(LOCAL_DIR)/platform.c \ $(LOCAL_DIR)/timer.c \