[init] Move PCIe probing to srv.init

This was kept in the kernel as a way to keep exercising the code, but it
doesn't belong there. This moves it to init, which doesn't do anything
but probe for devices currently - but at least it's executing the code
in userspace now.
This commit is contained in:
Justin C. Miller
2023-02-20 11:23:49 -08:00
parent 15e2f8abf3
commit 3a7a18011c
16 changed files with 294 additions and 235 deletions

View File

@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <bootproto/acpi.h>
#include <bootproto/bootconfig.h> #include <bootproto/bootconfig.h>
#include <bootproto/kernel.h> #include <bootproto/kernel.h>
#include <bootproto/memory.h> #include <bootproto/memory.h>
@@ -176,9 +177,23 @@ efi_main(uefi::handle image, uefi::system_table *st)
bootproto::entrypoint kentry = bootproto::entrypoint kentry =
load_resources(args, screen, image, pager, bs); load_resources(args, screen, image, pager, bs);
bootproto::module *acpi_mod =
g_alloc.allocate_module(sizeof(bootproto::acpi));
acpi_mod->type = bootproto::module_type::acpi;
bootproto::acpi *acpi = acpi_mod->data<bootproto::acpi>();
acpi->root = args->acpi_table;
pager.update_kernel_args(args); pager.update_kernel_args(args);
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services); memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
for (size_t i = 0; i < args->mem_map.count; ++i) {
bootproto::mem_entry &e = args->mem_map.pointer[i];
if (e.type == bootproto::mem_type::acpi) {
acpi->region = util::buffer::from(e.start, e.pages * memory::page_size);
break;
}
}
args->allocations = allocs; args->allocations = allocs;
args->init_modules = reinterpret_cast<uintptr_t>(modules); args->init_modules = reinterpret_cast<uintptr_t>(modules);

View File

@@ -6,7 +6,9 @@
#include <util/enum_bitfields.h> #include <util/enum_bitfields.h>
#include <util/misc.h> // for byteswap32 #include <util/misc.h> // for byteswap32
struct acpi_table_header namespace acpi {
struct table_header
{ {
uint32_t type; uint32_t type;
uint32_t length; uint32_t length;
@@ -18,24 +20,26 @@ struct acpi_table_header
uint32_t creator_id; uint32_t creator_id;
uint32_t creator_revision; uint32_t creator_revision;
bool validate(uint32_t expected_type = 0) const; bool validate() const { return util::checksum(this, length) == 0; }
} __attribute__ ((packed)); } __attribute__ ((packed));
#define TABLE_HEADER(signature) \ #define TABLE_HEADER(signature) \
static constexpr uint32_t type_id = util::byteswap32(signature); \ static constexpr uint32_t type_id = util::byteswap32(signature); \
acpi_table_header header; table_header header;
template <typename T> template <typename T>
bool acpi_validate(const T *t) { return t->header.validate(T::type_id); } bool validate(const T *t) {
return t->header.validate(T::type_id);
}
template <typename T> template <typename T>
size_t acpi_table_entries(const T *t, size_t size) size_t table_entries(const T *t, size_t size) {
{
return (t->header.length - sizeof(T)) / size; return (t->header.length - sizeof(T)) / size;
} }
enum class acpi_gas_type : uint8_t
enum class gas_type : uint8_t
{ {
system_memory, system_memory,
system_io, system_io,
@@ -46,9 +50,9 @@ enum class acpi_gas_type : uint8_t
functional_fixed = 0x7f functional_fixed = 0x7f
}; };
struct acpi_gas struct gas
{ {
acpi_gas_type type; gas_type type;
uint8_t reg_bits; uint8_t reg_bits;
uint8_t reg_offset; uint8_t reg_offset;
@@ -58,7 +62,7 @@ struct acpi_gas
} __attribute__ ((packed)); } __attribute__ ((packed));
enum class acpi_fadt_flags : uint32_t enum class fadt_flags : uint32_t
{ {
wbinvd = 0x00000001, wbinvd = 0x00000001,
wbinvd_flush = 0x00000002, wbinvd_flush = 0x00000002,
@@ -83,9 +87,9 @@ enum class acpi_fadt_flags : uint32_t
hw_reduced_acpi = 0x00100000, hw_reduced_acpi = 0x00100000,
low_pwr_s0_idle = 0x00200000 low_pwr_s0_idle = 0x00200000
}; };
is_bitfield(acpi_fadt_flags); is_bitfield(fadt_flags);
struct acpi_fadt struct fadt
{ {
TABLE_HEADER('FACP'); TABLE_HEADER('FACP');
@@ -130,9 +134,9 @@ struct acpi_fadt
uint16_t iapc_boot_arch; uint16_t iapc_boot_arch;
uint8_t reserved1; uint8_t reserved1;
acpi_fadt_flags flags; fadt_flags flags;
acpi_gas reset_reg; gas reset_reg;
uint8_t reset_value; uint8_t reset_value;
uint16_t arm_boot_arch; uint16_t arm_boot_arch;
@@ -142,28 +146,28 @@ struct acpi_fadt
uint64_t x_facs; uint64_t x_facs;
uint64_t x_dsdt; uint64_t x_dsdt;
acpi_gas x_pm1a_event_block; gas x_pm1a_event_block;
acpi_gas x_pm1b_event_block; gas x_pm1b_event_block;
acpi_gas x_pm1a_control_block; gas x_pm1a_control_block;
acpi_gas x_pm1b_control_block; gas x_pm1b_control_block;
acpi_gas x_pm2_control_block; gas x_pm2_control_block;
acpi_gas x_pm_timer_block; gas x_pm_timer_block;
acpi_gas x_gpe0_block; gas x_gpe0_block;
acpi_gas x_gpe1_block; gas x_gpe1_block;
acpi_gas sleep_control_reg; gas sleep_control_reg;
acpi_gas sleep_status_reg; gas sleep_status_reg;
uint64_t hypervisor_vendor_id; uint64_t hypervisor_vendor_id;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct acpi_xsdt struct xsdt
{ {
TABLE_HEADER('XSDT'); TABLE_HEADER('XSDT');
acpi_table_header *headers[0]; table_header *headers[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct acpi_apic struct apic
{ {
TABLE_HEADER('APIC'); TABLE_HEADER('APIC');
uint32_t local_address; uint32_t local_address;
@@ -171,7 +175,7 @@ struct acpi_apic
uint8_t controller_data[0]; uint8_t controller_data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct acpi_mcfg_entry struct mcfg_entry
{ {
uint64_t base; uint64_t base;
uint16_t group; uint16_t group;
@@ -180,24 +184,24 @@ struct acpi_mcfg_entry
uint32_t reserved; uint32_t reserved;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct acpi_mcfg struct mcfg
{ {
TABLE_HEADER('MCFG'); TABLE_HEADER('MCFG');
uint64_t reserved; uint64_t reserved;
acpi_mcfg_entry entries[0]; mcfg_entry entries[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct acpi_hpet struct hpet
{ {
TABLE_HEADER('HPET'); TABLE_HEADER('HPET');
uint32_t hardware_id; uint32_t hardware_id;
acpi_gas base_address; gas base_address;
uint8_t index; uint8_t index;
uint16_t periodic_min; uint16_t periodic_min;
uint8_t attributes; uint8_t attributes;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct acpi_bgrt struct bgrt
{ {
TABLE_HEADER('BGRT'); TABLE_HEADER('BGRT');
uint16_t version; uint16_t version;
@@ -208,3 +212,35 @@ struct acpi_bgrt
uint32_t offset_y; uint32_t offset_y;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct rsdp1
{
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
} __attribute__ ((packed));
struct rsdp2
{
char signature[8];
uint8_t checksum10;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
uint32_t length;
table_header *xsdt_address;
uint8_t checksum20;
uint8_t reserved[3];
} __attribute__ ((packed));
template <typename T> static const T *
check_get_table(const table_header *header)
{
if (!header || header->type != T::type_id)
return nullptr;
return reinterpret_cast<const T *>(header);
}
} // namespace acpi

View File

@@ -3,9 +3,9 @@
#include <stdint.h> #include <stdint.h>
#include <util/misc.h> // for checksum #include <util/misc.h> // for checksum
#include <util/pointers.h> #include <util/pointers.h>
#include <arch/acpi/tables.h>
#include "assert.h" #include "assert.h"
#include "acpi_tables.h"
#include "apic.h" #include "apic.h"
#include "clock.h" #include "clock.h"
#include "device_manager.h" #include "device_manager.h"
@@ -21,37 +21,6 @@ static const char expected_signature[] = "RSD PTR ";
device_manager device_manager::s_instance; device_manager device_manager::s_instance;
struct acpi1_rsdp
{
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
} __attribute__ ((packed));
struct acpi2_rsdp
{
char signature[8];
uint8_t checksum10;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
uint32_t length;
acpi_table_header *xsdt_address;
uint8_t checksum20;
uint8_t reserved[3];
} __attribute__ ((packed));
bool
acpi_table_header::validate(uint32_t expected_type) const
{
if (util::checksum(this, length) != 0) return false;
return !expected_type || (expected_type == type);
}
device_manager::device_manager() : device_manager::device_manager() :
m_lapic_base(0) m_lapic_base(0)
{ {
@@ -63,37 +32,32 @@ device_manager::device_manager() :
m_irqs[2] = {ignore_event, 0}; m_irqs[2] = {ignore_event, 0};
} }
template <typename T> static const T *
check_get_table(const acpi_table_header *header)
{
kassert(header && header->validate(T::type_id), "Invalid ACPI table.");
return reinterpret_cast<const T *>(header);
}
void void
device_manager::parse_acpi(const void *root_table) device_manager::parse_acpi(const void *root_table)
{ {
kassert(root_table != 0, "ACPI root table pointer is null."); kassert(root_table != 0, "ACPI root table pointer is null.");
const acpi1_rsdp *acpi1 = mem::to_virtual( const acpi::rsdp1 *acpi1 = mem::to_virtual(
reinterpret_cast<const acpi1_rsdp *>(root_table)); reinterpret_cast<const acpi::rsdp1 *>(root_table));
for (int i = 0; i < sizeof(acpi1->signature); ++i) for (int i = 0; i < sizeof(acpi1->signature); ++i)
kassert(acpi1->signature[i] == expected_signature[i], kassert(acpi1->signature[i] == expected_signature[i],
"ACPI RSDP table signature mismatch"); "ACPI RSDP table signature mismatch");
uint8_t sum = util::checksum(acpi1, sizeof(acpi1_rsdp), 0); uint8_t sum = util::checksum(acpi1, sizeof(acpi::rsdp1), 0);
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch."); kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
kassert(acpi1->revision > 1, "ACPI 1.0 not supported."); kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
const acpi2_rsdp *acpi2 = const acpi::rsdp2 *acpi2 =
reinterpret_cast<const acpi2_rsdp *>(acpi1); reinterpret_cast<const acpi::rsdp2 *>(acpi1);
sum = util::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp)); sum = util::checksum(acpi2, sizeof(acpi::rsdp2), sizeof(acpi::rsdp1));
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch."); kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
load_xsdt(mem::to_virtual(acpi2->xsdt_address)); const acpi::table_header *xsdt = mem::to_virtual(acpi2->xsdt_address);
kassert(xsdt->validate(), "Bad XSDT table");
load_xsdt(xsdt);
} }
const device_manager::apic_nmi * const device_manager::apic_nmi *
@@ -129,53 +93,50 @@ put_sig(char *into, uint32_t type)
} }
void void
device_manager::load_xsdt(const acpi_table_header *header) device_manager::load_xsdt(const acpi::table_header *header)
{ {
const auto *xsdt = check_get_table<acpi_xsdt>(header); const auto *xsdt = acpi::check_get_table<acpi::xsdt>(header);
char sig[5] = {0,0,0,0,0}; char sig[5] = {0,0,0,0,0};
log::info(logs::device, "ACPI 2.0+ tables loading"); log::info(logs::device, "ACPI 2.0+ tables loading");
put_sig(sig, xsdt->header.type); put_sig(sig, xsdt->header.type);
log::verbose(logs::device, " Found table %s", sig); log::verbose(logs::device, " Loading table %s", sig);
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*)); size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
for (size_t i = 0; i < num_tables; ++i) { for (size_t i = 0; i < num_tables; ++i) {
const acpi_table_header *header = const acpi::table_header *header =
mem::to_virtual(xsdt->headers[i]); mem::to_virtual(xsdt->headers[i]);
put_sig(sig, header->type);
log::verbose(logs::device, " Found table %s", sig);
kassert(header->validate(), "Table failed validation."); kassert(header->validate(), "Table failed validation.");
put_sig(sig, header->type);
switch (header->type) { switch (header->type) {
case acpi_apic::type_id: case acpi::apic::type_id:
log::verbose(logs::device, " Loading table %s", sig);
load_apic(header); load_apic(header);
break; break;
case acpi_mcfg::type_id: case acpi::hpet::type_id:
load_mcfg(header); log::verbose(logs::device, " Loading table %s", sig);
break;
case acpi_hpet::type_id:
load_hpet(header); load_hpet(header);
break; break;
default: default:
log::verbose(logs::device, " Skipping table %s", sig);
break; break;
} }
} }
} }
void void
device_manager::load_apic(const acpi_table_header *header) device_manager::load_apic(const acpi::table_header *header)
{ {
const auto *apic = check_get_table<acpi_apic>(header); const auto *apic = acpi::check_get_table<acpi::apic>(header);
m_lapic_base = apic->local_address; m_lapic_base = apic->local_address;
size_t count = acpi_table_entries(apic, 1); size_t count = acpi::table_entries(apic, 1);
uint8_t const *p = apic->controller_data; uint8_t const *p = apic->controller_data;
uint8_t const *end = p + count; uint8_t const *end = p + count;
@@ -265,33 +226,9 @@ device_manager::load_apic(const acpi_table_header *header)
} }
void void
device_manager::load_mcfg(const acpi_table_header *header) device_manager::load_hpet(const acpi::table_header *header)
{ {
const auto *mcfg = check_get_table<acpi_mcfg>(header); const auto *hpet = acpi::check_get_table<acpi::hpet>(header);
size_t count = acpi_table_entries(mcfg, sizeof(acpi_mcfg_entry));
m_pci.set_size(count);
m_devices.set_capacity(16);
for (unsigned i = 0; i < count; ++i) {
const acpi_mcfg_entry &mcfge = mcfg->entries[i];
m_pci[i].group = mcfge.group;
m_pci[i].bus_start = mcfge.bus_start;
m_pci[i].bus_end = mcfge.bus_end;
m_pci[i].base = mem::to_virtual<uint32_t>(mcfge.base);
log::spam(logs::device, " Found MCFG entry: base %lx group %d bus %d-%d",
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
}
probe_pci();
}
void
device_manager::load_hpet(const acpi_table_header *header)
{
const auto *hpet = check_get_table<acpi_hpet>(header);
log::verbose(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x", log::verbose(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x",
hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes); hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes);
@@ -311,28 +248,6 @@ device_manager::load_hpet(const acpi_table_header *header)
reinterpret_cast<uint64_t*>(hpet->base_address.address + mem::linear_offset)); reinterpret_cast<uint64_t*>(hpet->base_address.address + mem::linear_offset));
} }
void
device_manager::probe_pci()
{
for (auto &pci : m_pci) {
log::verbose(logs::device, "Probing PCI group at base %016lx", pci.base);
for (int bus = pci.bus_start; bus <= pci.bus_end; ++bus) {
for (int dev = 0; dev < 32; ++dev) {
if (!pci.has_device(bus, dev, 0)) continue;
auto &d0 = m_devices.emplace(pci, bus, dev, 0);
if (!d0.multi()) continue;
for (int i = 1; i < 8; ++i) {
if (pci.has_device(bus, dev, i))
m_devices.emplace(pci, bus, dev, i);
}
}
}
}
}
static uint64_t static uint64_t
tsc_clock_source(void*) tsc_clock_source(void*)
{ {
@@ -366,7 +281,7 @@ device_manager::init_drivers()
// becomes the singleton // becomes the singleton
master_clock = new clock(h.rate(), hpet_clock_source, &h); master_clock = new clock(h.rate(), hpet_clock_source, &h);
log::info(logs::clock, "Created master clock using HPET 0: Rate %d", h.rate()); log::info(logs::timer, "Created master clock using HPET 0: Rate %d", h.rate());
} else { } else {
//TODO: Other clocks, APIC clock? //TODO: Other clocks, APIC clock?
master_clock = new clock(5000, tsc_clock_source, nullptr); master_clock = new clock(5000, tsc_clock_source, nullptr);
@@ -410,10 +325,10 @@ device_manager::unbind_irqs(obj::event *target)
} }
} }
/*
bool bool
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data) device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
{ {
/*
// TODO: find gaps to fill // TODO: find gaps to fill
uint8_t irq = m_irqs.count(); uint8_t irq = m_irqs.count();
isr vector = isr::irq00 + irq; isr vector = isr::irq00 + irq;
@@ -424,12 +339,6 @@ device_manager::allocate_msi(const char *name, pci_device &device, irq_callback
device.write_msi_regs( device.write_msi_regs(
0xFEE00000, 0xFEE00000,
static_cast<uint16_t>(vector)); static_cast<uint16_t>(vector));
*/
return true; return true;
} }
*/
void
device_manager::register_block_device(block_device *blockdev)
{
m_blockdevs.append(blockdev);
}

View File

@@ -6,11 +6,13 @@
#include "apic.h" #include "apic.h"
#include "hpet.h" #include "hpet.h"
#include "pci.h"
struct acpi_table_header;
class block_device; class block_device;
namespace acpi {
struct table_header;
}
namespace obj { namespace obj {
class event; class event;
} }
@@ -53,18 +55,6 @@ public:
/// \arg target The endpoint to remove /// \arg target The endpoint to remove
void unbind_irqs(obj::event *target); void unbind_irqs(obj::event *target);
/// Allocate an MSI IRQ for a device
/// \arg name Name of the interrupt, for display to user
/// \arg device Device this MSI is being allocated for
/// \arg cb Callback to call when the interrupt is received
/// \arg data Data to pass to the callback
/// \returns True if an interrupt was allocated successfully
bool allocate_msi(
const char *name,
pci_device &device,
irq_callback cb,
void *data);
/// Dispatch an IRQ interrupt /// Dispatch an IRQ interrupt
/// \arg irq The irq number of the interrupt /// \arg irq The irq number of the interrupt
/// \returns True if the interrupt was handled /// \returns True if the interrupt was handled
@@ -103,23 +93,6 @@ public:
/// configuration, or null if no configuration was provided /// configuration, or null if no configuration was provided
const irq_override * get_irq_override(uint8_t irq) const; const irq_override * get_irq_override(uint8_t irq) const;
/// Register the existance of a block device.
/// \arg blockdev Pointer to the block device
void register_block_device(block_device *blockdev);
/// Get the number of block devices in the system
/// \returns A count of devices
inline unsigned get_num_block_devices() const { return m_blockdevs.count(); }
/// Get a block device
/// \arg i Index of the device to get
/// \returns A pointer to the requested device, or nullptr
inline block_device * get_block_device(unsigned i)
{
return i < m_blockdevs.count() ?
m_blockdevs[i] : nullptr;
}
/// Get an HPET device /// Get an HPET device
/// \arg i Index of the device to get /// \arg i Index of the device to get
/// \returns A pointer to the requested device, or nullptr /// \returns A pointer to the requested device, or nullptr
@@ -132,23 +105,15 @@ public:
private: private:
/// Parse the ACPI XSDT and load relevant sub-tables. /// Parse the ACPI XSDT and load relevant sub-tables.
/// \arg xsdt Pointer to the XSDT from the firmware /// \arg xsdt Pointer to the XSDT from the firmware
void load_xsdt(const acpi_table_header *xsdt); void load_xsdt(const acpi::table_header *xsdt);
/// Parse the ACPI MADT and initialize APICs from it. /// Parse the ACPI MADT and initialize APICs from it.
/// \arg apic Pointer to the MADT from the XSDT /// \arg apic Pointer to the MADT from the XSDT
void load_apic(const acpi_table_header *apic); void load_apic(const acpi::table_header *apic);
/// Parse the ACPI MCFG and initialize PCIe from it.
/// \arg mcfg Pointer to the MCFG from the XSDT
void load_mcfg(const acpi_table_header *mcfg);
/// Parse the ACPI HPET and initialize an HPET from it. /// Parse the ACPI HPET and initialize an HPET from it.
/// \arg hpet Pointer to the HPET from the XSDT /// \arg hpet Pointer to the HPET from the XSDT
void load_hpet(const acpi_table_header *hpet); void load_hpet(const acpi::table_header *hpet);
/// Probe the PCIe busses and add found devices to our
/// device list. The device list is destroyed and rebuilt.
void probe_pci();
/// Handle a bad IRQ. Called when an interrupt is dispatched /// Handle a bad IRQ. Called when an interrupt is dispatched
/// that has no callback. /// that has no callback.
@@ -162,9 +127,6 @@ private:
util::vector<apic_nmi> m_nmis; util::vector<apic_nmi> m_nmis;
util::vector<irq_override> m_overrides; util::vector<irq_override> m_overrides;
util::vector<pci_group> m_pci;
util::vector<pci_device> m_devices;
struct irq_binding struct irq_binding
{ {
obj::event *target = nullptr; obj::event *target = nullptr;
@@ -172,8 +134,6 @@ private:
}; };
util::vector<irq_binding> m_irqs; util::vector<irq_binding> m_irqs;
util::vector<block_device *> m_blockdevs;
static device_manager s_instance; static device_manager s_instance;
device_manager(const device_manager &) = delete; device_manager(const device_manager &) = delete;

View File

@@ -43,7 +43,6 @@ kernel = module("kernel",
"objects/vm_area.cpp", "objects/vm_area.cpp",
"page_table.cpp", "page_table.cpp",
"page_tree.cpp", "page_tree.cpp",
"pci.cpp",
"scheduler.cpp", "scheduler.cpp",
"smp.cpp", "smp.cpp",
"smp.s", "smp.s",

View File

@@ -3,6 +3,7 @@
bp = module("bootproto", bp = module("bootproto",
kind = "lib", kind = "lib",
public_headers = [ public_headers = [
"bootproto/acpi.h",
"bootproto/bootconfig.h", "bootproto/bootconfig.h",
"bootproto/devices/framebuffer.h", "bootproto/devices/framebuffer.h",
"bootproto/init.h", "bootproto/init.h",

View File

@@ -0,0 +1,15 @@
#pragma once
/// \file bootproto/acpi.h
/// Data structures for passing ACPI tables to the init server
#include <util/counted.h>
namespace bootproto {
struct acpi
{
util::const_buffer region;
void const *root;
};
} // namespace bootproto

View File

@@ -10,7 +10,7 @@
namespace bootproto { namespace bootproto {
enum class module_type : uint8_t { none, initrd, device, }; enum class module_type : uint8_t { none, initrd, device, acpi };
struct module struct module
{ {

104
src/user/srv.init/acpi.cpp Normal file
View File

@@ -0,0 +1,104 @@
#include <arch/acpi/tables.h>
#include <bootproto/acpi.h>
#include <bootproto/init.h>
#include <j6/syslog.hh>
#include "acpi.h"
#include "loader.h"
#include "pci.h"
inline constexpr size_t bus_mmio_size = 0x1000'0000;
inline constexpr j6_vm_flags mmio_flags = (j6_vm_flags)(j6_vm_flag_write | j6_vm_flag_mmio);
void
probe_pci(j6_handle_t sys, pci_group &pci)
{
j6::syslog("Probing PCI group at base %016lx", pci.base);
map_phys(sys, pci.base, bus_mmio_size, mmio_flags);
for (unsigned b = pci.bus_start; b <= pci.bus_end; ++b) {
uint8_t bus = static_cast<uint8_t>(b);
for (uint8_t dev = 0; dev < 32; ++dev) {
if (!pci.has_device(bus, dev, 0)) continue;
pci_device d0 {pci, bus, dev, 0};
if (!d0.multi()) continue;
for (uint8_t i = 1; i < 8; ++i) {
if (pci.has_device(bus, dev, i))
pci_device dn {pci, bus, dev, i};
}
}
}
}
void
load_mcfg(j6_handle_t sys, const acpi::table_header *header)
{
const auto *mcfg = acpi::check_get_table<acpi::mcfg>(header);
size_t count = acpi::table_entries(mcfg, sizeof(acpi::mcfg_entry));
/*
m_pci.set_size(count);
m_devices.set_capacity(16);
*/
for (unsigned i = 0; i < count; ++i) {
const acpi::mcfg_entry &mcfge = mcfg->entries[i];
pci_group group = {
.group = mcfge.group,
.bus_start = mcfge.bus_start,
.bus_end = mcfge.bus_end,
.base = reinterpret_cast<uint32_t*>(mcfge.base),
};
probe_pci(sys, group);
j6::syslog(" Found MCFG entry: base %lx group %d bus %d-%d",
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
}
//probe_pci();
}
void
load_acpi(j6_handle_t sys, const bootproto::module *mod)
{
const bootproto::acpi *info = mod->data<bootproto::acpi>();
const util::const_buffer &region = info->region;
map_phys(sys, region.pointer, region.count);
const void *root_table = info->root;
if (!root_table) {
j6::syslog("null ACPI root table pointer");
return;
}
const acpi::rsdp2 *acpi2 =
reinterpret_cast<const acpi::rsdp2 *>(root_table);
const auto *xsdt =
acpi::check_get_table<acpi::xsdt>(acpi2->xsdt_address);
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
for (size_t i = 0; i < num_tables; ++i) {
const acpi::table_header *header = xsdt->headers[i];
if (!header->validate()) {
j6::syslog("ACPI table at %lx failed validation", header);
continue;
}
switch (header->type) {
case acpi::mcfg::type_id:
load_mcfg(sys, header);
break;
default:
break;
}
}
}

12
src/user/srv.init/acpi.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
/// \file acpi.h
/// Routines for loading and parsing ACPI tables
#include <util/counted.h>
#include <j6/types.h>
namespace bootproto {
struct module;
}
void load_acpi(j6_handle_t sys, const bootproto::module *mod);

View File

@@ -6,10 +6,12 @@ init = module("srv.init",
description = "Init server", description = "Init server",
ld_script = "init.ld", ld_script = "init.ld",
sources = [ sources = [
"acpi.cpp",
"j6romfs.cpp", "j6romfs.cpp",
"loader.cpp", "loader.cpp",
"main.cpp", "main.cpp",
"modules.cpp", "modules.cpp",
"pci.cpp",
"service_locator.cpp", "service_locator.cpp",
"start.s", "start.s",
]) ])

View File

@@ -19,17 +19,14 @@ constexpr size_t stack_size = 0x10000;
constexpr uintptr_t stack_top = 0x80000000000; constexpr uintptr_t stack_top = 0x80000000000;
j6_handle_t j6_handle_t
map_phys(j6_handle_t sys, uintptr_t phys, size_t len, uintptr_t addr) map_phys(j6_handle_t sys, uintptr_t phys, size_t len, j6_vm_flags flags)
{ {
j6_handle_t vma = j6_handle_invalid; j6_handle_t vma = j6_handle_invalid;
j6_status_t res = j6_system_map_phys(sys, &vma, phys, len, 0); j6_status_t res = j6_system_map_phys(sys, &vma, phys, len, flags);
if (res != j6_status_ok) if (res != j6_status_ok)
return j6_handle_invalid; return j6_handle_invalid;
if (!addr) res = j6_vma_map(vma, 0, phys);
addr = phys;
res = j6_vma_map(vma, 0, addr);
if (res != j6_status_ok) if (res != j6_status_ok)
return j6_handle_invalid; return j6_handle_invalid;

View File

@@ -3,6 +3,7 @@
/// Routines for loading and starting other programs /// Routines for loading and starting other programs
#include <j6/types.h> #include <j6/types.h>
#include <j6/flags.h>
#include <util/counted.h> #include <util/counted.h>
namespace bootproto { namespace bootproto {
@@ -15,8 +16,8 @@ bool load_program(
j6_handle_t sys, j6_handle_t slp, j6_handle_t sys, j6_handle_t slp,
const bootproto::module *arg = nullptr); const bootproto::module *arg = nullptr);
j6_handle_t map_phys(j6_handle_t sys, uintptr_t phys, size_t len, uintptr_t addr = 0); j6_handle_t map_phys(j6_handle_t sys, uintptr_t phys, size_t len, j6_vm_flags flags = j6_vm_flag_none);
inline j6_handle_t map_phys(j6_handle_t sys, const void *phys, size_t len, uintptr_t addr = 0) { inline j6_handle_t map_phys(j6_handle_t sys, const void *phys, size_t len, j6_vm_flags flags = j6_vm_flag_none) {
return map_phys(sys, reinterpret_cast<uintptr_t>(phys), len, addr); return map_phys(sys, reinterpret_cast<uintptr_t>(phys), len, flags);
} }

View File

@@ -9,9 +9,11 @@
#include <j6/syslog.hh> #include <j6/syslog.hh>
#include <j6/types.h> #include <j6/types.h>
#include <bootproto/acpi.h>
#include <bootproto/init.h> #include <bootproto/init.h>
#include <bootproto/devices/framebuffer.h> #include <bootproto/devices/framebuffer.h>
#include "acpi.h"
#include "j6romfs.h" #include "j6romfs.h"
#include "loader.h" #include "loader.h"
#include "modules.h" #include "modules.h"
@@ -86,6 +88,7 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
load_modules(modules_addr, sys, 0, mods); load_modules(modules_addr, sys, 0, mods);
module const *initrd_module = nullptr; module const *initrd_module = nullptr;
module const *acpi_module = nullptr;
std::vector<module const*> devices; std::vector<module const*> devices;
for (auto mod : mods) { for (auto mod : mods) {
@@ -94,6 +97,10 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
initrd_module = mod; initrd_module = mod;
break; break;
case module_type::acpi:
acpi_module = mod;
break;
case module_type::device: case module_type::device:
devices.push_back(mod); devices.push_back(mod);
break; break;
@@ -105,7 +112,10 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
} }
if (!initrd_module) if (!initrd_module)
return 1; return 2;
if (!acpi_module)
return 3;
util::const_buffer initrd_buf = *initrd_module->data<util::const_buffer>(); util::const_buffer initrd_buf = *initrd_module->data<util::const_buffer>();
@@ -120,6 +130,7 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
// have driver_source objects.. // have driver_source objects..
j6romfs::fs initrd {initrd_buf}; j6romfs::fs initrd {initrd_buf};
load_acpi(sys, acpi_module);
const j6romfs::inode *driver_dir = initrd.lookup_inode("/jsix/drivers"); const j6romfs::inode *driver_dir = initrd.lookup_inode("/jsix/drivers");
if (!driver_dir) { if (!driver_dir) {

View File

@@ -1,6 +1,7 @@
#include "assert.h" #include <assert.h>
#include "logger.h"
#include "interrupts.h" #include <j6/syslog.hh>
#include "pci.h" #include "pci.h"
struct pci_cap_msi struct pci_cap_msi
@@ -73,7 +74,6 @@ pci_device::pci_device() :
m_subclass(0), m_subclass(0),
m_progif(0), m_progif(0),
m_revision(0), m_revision(0),
m_irq(isr::isrIgnore0),
m_header_type(0) m_header_type(0)
{ {
} }
@@ -81,8 +81,7 @@ pci_device::pci_device() :
pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) : pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) :
m_base(group.base_for(bus, device, func)), m_base(group.base_for(bus, device, func)),
m_msi(nullptr), m_msi(nullptr),
m_bus_addr(bus_addr(bus, device, func)), m_bus_addr(bus_addr(bus, device, func))
m_irq(isr::isrIgnore0)
{ {
m_vendor = m_base[0] & 0xffff; m_vendor = m_base[0] & 0xffff;
m_device = (m_base[0] >> 16) & 0xffff; m_device = (m_base[0] >> 16) & 0xffff;
@@ -100,11 +99,11 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
uint16_t *status = command + 1; uint16_t *status = command + 1;
log::info(logs::device, "Found PCIe device at %02d:%02d:%d of type %x.%x.%x id %04x:%04x", j6::syslog("Found PCIe device at %02d:%02d:%d of type %x.%x.%x id %04x:%04x",
bus, device, func, m_class, m_subclass, m_progif, m_vendor, m_device); bus, device, func, m_class, m_subclass, m_progif, m_vendor, m_device);
log::spam(logs::device, " = BAR0 %016lld", get_bar(0)); j6::syslog(" = BAR0 %016lld", get_bar(0));
log::spam(logs::device, " = BAR1 %016lld", get_bar(1)); j6::syslog(" = BAR1 %016lld", get_bar(1));
if (*status & 0x0010) { if (*status & 0x0010) {
// Walk the extended capabilities list // Walk the extended capabilities list
@@ -112,7 +111,7 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
while (next) { while (next) {
pci_cap *cap = reinterpret_cast<pci_cap *>(util::offset_pointer(m_base, next)); pci_cap *cap = reinterpret_cast<pci_cap *>(util::offset_pointer(m_base, next));
next = cap->next; next = cap->next;
log::verbose(logs::device, " - found PCI cap type %02x", cap->id); //log::verbose(logs::device, " - found PCI cap type %02x", cap->id);
if (cap->id == pci_cap::type::msi) { if (cap->id == pci_cap::type::msi) {
m_msi = cap; m_msi = cap;
@@ -128,11 +127,10 @@ uint32_t
pci_device::get_bar(unsigned i) pci_device::get_bar(unsigned i)
{ {
if (m_header_type == 0) { if (m_header_type == 0) {
kassert(i < 6, "Requested BAR >5 for PCI device"); assert(i < 6); // Device max BAR is 5
} else if (m_header_type == 1) {
kassert(i < 2, "Requested BAR >1 for PCI bridge");
} else { } else {
kassert(0, "Requested BAR for other PCI device type"); assert(m_header_type == 1); // Only device or bridge
assert(i < 2); // Bridge max BAR is 1
} }
return m_base[4+i]; return m_base[4+i];
@@ -142,11 +140,10 @@ void
pci_device::set_bar(unsigned i, uint32_t val) pci_device::set_bar(unsigned i, uint32_t val)
{ {
if (m_header_type == 0) { if (m_header_type == 0) {
kassert(i < 6, "Requested BAR >5 for PCI device"); assert(i < 6); // Device max BAR is 5
} else if (m_header_type == 1) {
kassert(i < 2, "Requested BAR >1 for PCI bridge");
} else { } else {
kassert(0, "Requested BAR for other PCI device type"); assert(m_header_type == 1); // Only device or bridge
assert(i < 2); // Bridge max BAR is 1
} }
m_base[4+i] = val; m_base[4+i] = val;
@@ -155,7 +152,9 @@ pci_device::set_bar(unsigned i, uint32_t val)
void void
pci_device::write_msi_regs(uintptr_t address, uint16_t data) pci_device::write_msi_regs(uintptr_t address, uint16_t data)
{ {
kassert(m_msi, "Tried to write MSI for a device without that cap"); if (!m_msi)
return;
if (m_msi->id == pci_cap::type::msi) { if (m_msi->id == pci_cap::type::msi) {
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(m_msi); pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(m_msi);
if (mcap->control & 0x0080) { if (mcap->control & 0x0080) {
@@ -172,7 +171,7 @@ pci_device::write_msi_regs(uintptr_t address, uint16_t data)
control |= 0x0001; // Enable MSI control |= 0x0001; // Enable MSI
mcap->control = control; mcap->control = control;
} else { } else {
kassert(0, "MIS-X is NYI"); assert(0 && "MIS-X is NYI");
} }
} }

View File

@@ -104,8 +104,6 @@ private:
uint8_t m_revision; uint8_t m_revision;
bool m_multi; bool m_multi;
// Might as well cache these to fill out the struct align
isr m_irq;
uint8_t m_header_type; uint8_t m_header_type;
}; };