[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:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
15
src/libraries/bootproto/bootproto/acpi.h
Normal file
15
src/libraries/bootproto/bootproto/acpi.h
Normal 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
|
||||||
@@ -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
104
src/user/srv.init/acpi.cpp
Normal 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 ®ion = 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
12
src/user/srv.init/acpi.h
Normal 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);
|
||||||
@@ -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",
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user