WIP x86 smp: start the framework for detecting and starting secondary cores
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
#include <arch/arch_ops.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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
|
||||
@@ -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<const acpi_madt_table*>(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<const uint8_t*>(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<const void*>(&madt_array[off]), length);
|
||||
callback(static_cast<const void*>(&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<const struct acpi_madt_local_apic_entry *>(_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<const struct acpi_madt_io_apic_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);
|
||||
};
|
||||
|
||||
auto int_source_override_callback = [](const void *_entry, size_t entry_len, void *cookie) {
|
||||
const auto *entry = reinterpret_cast<const struct acpi_madt_int_source_override_entry *>(_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:
|
||||
|
||||
@@ -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<void(const void* entry, size_t entry_len)>;
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
63
platform/pc/mp.c
Normal file
63
platform/pc/mp.c
Normal file
@@ -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 <lk/main.h>
|
||||
#include <lib/acpi_lite.h>
|
||||
#include <lk/trace.h>
|
||||
|
||||
#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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <lk/trace.h>
|
||||
#include <arch/x86/mmu.h>
|
||||
#include <platform.h>
|
||||
#include "platform_p.h"
|
||||
#include <platform/pc.h>
|
||||
#include <platform/console.h>
|
||||
#include <platform/keyboard.h>
|
||||
@@ -22,12 +21,13 @@
|
||||
#include <arch/x86.h>
|
||||
#include <arch/mmu.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <lib/acpi_lite.h>
|
||||
|
||||
#include "platform_p.h"
|
||||
|
||||
#if WITH_DEV_BUS_PCI
|
||||
#include <dev/bus/pci.h>
|
||||
#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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user