Skip to content
Merged
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#export DEBUG = 1
export DEBUG_LOGGING = 1

export SUPPRESS_ACPICA_BUILD_OUTPUT = 1

# Global options

# Optional boot modules
Expand All @@ -38,8 +40,14 @@ export BUILD_KERNEL_MEM_TEST = 1
export BUILD_DRIVERS_SERIAL = 1
export BUILD_DRIVERS_HPET = 1

export BUILD_DRIVERS_AHCI = 1

# End of options

ifdef BUILD_DRIVERS_AHCI
export BUILD_DRIVERS_SATA = 1
endif

export SRC_TREE_ROOT = .
export OBJ_DIR = build

Expand Down
15 changes: 11 additions & 4 deletions drivers/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,25 @@ $(call add_directory,apic,APIC)
$(call add_directory,ioapic,IOAPIC)
$(call add_directory,acpi,ACPI)
$(call add_directory,acpica_osl,ACPICA_OSL)
$(call add_directory,pci,PCI)
$(call add_directory,pcie,PCIE)
$(call add_directory,disk,DISK)

ifdef BUILD_DRIVERS_HPET
$(call add_directory,hpet,HPET)
endif

#TODO: switch to PCIe


ifdef BUILD_DRIVERS_SERIAL
$(call add_directory,serial,SERIAL)
endif

ifdef BUILD_DRIVERS_AHCI
$(call add_directory,ahci,AHCI)
endif

ifdef BUILD_DRIVERS_SATA
$(call add_directory,sata,SATA)
endif

include $(SRC_TREE_ROOT)/scripts/Makefile.kcflags
include $(SRC_TREE_ROOT)/scripts/Makefile.targets

Expand Down
187 changes: 135 additions & 52 deletions drivers/acpi/tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <kernel/core/logging.h>
#include <kernel/core/paging.h>
#include <kernel/core/alloc.h>
#include <kernel/core/mm.h>

#include <kernel/lib/kmemcmp.h>
#include <kernel/lib/kmemcpy.h>
Expand All @@ -41,6 +42,9 @@
#else /* HPET */
#define FOUND_HPET 0x00
#endif /* HPET */
#define FOUND_MCFG 0x08

#define FOUND_ALL (FOUND_FADT | FOUND_MADT | FOUND_HPET | FOUND_MCFG)

#define GAS_TYPE_SYS 0
#define GAS_TYPE_IO 1
Expand Down Expand Up @@ -166,6 +170,28 @@ struct acpi_madt_t {
uint8_t InterruptControllerStructure[];
} __attribute__((packed));

struct acpi_mcfg_conf_entry_t {
uint64_t base;
uint16_t group;
uint8_t bus_start;
uint8_t bus_end;
uint32_t resv;
} __attribute__((packed));

struct acpi_mcfg_t {
uint8_t Signature[4];
uint32_t Length;
uint8_t Revision;
uint8_t Checksum;
uint8_t OEMID[6];
uint8_t OEMTableID[8];
uint32_t OEMRevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
uint64_t Reserved;
struct acpi_mcfg_conf_entry_t conf[];
} __attribute__((packed));

#ifdef HPET
struct acpi_hpet_t {
uint8_t Signature[4];
Expand All @@ -191,6 +217,7 @@ struct acpi_hpet_t {

static struct acpi_fadt_t* acpi_fadt;
static struct acpi_madt_t* acpi_madt;
static struct acpi_mcfg_t* acpi_mcfg;
#ifdef HPET
static struct acpi_hpet_t* acpi_hpet[8];
static uint8_t hpet_count;
Expand All @@ -207,11 +234,7 @@ static uint8_t hpet_count;
#define CHECK_AND_COPY(sig, tbl, store, fnd, post) \
do { \
if (!kmemcmp((uint8_t*)gen->Signature, sig, 4)) { \
map_table(gen); \
if (verify_checksum(gen)) { \
CHECK_FAIL(sig); \
} \
logging_log_info("Found ACPI " tbl " @ 0x%lX", (uint64_t)gen); \
logging_log_info("Copying ACPI " tbl " @ 0x%lX", (uint64_t)gen); \
store = kmalloc(gen->Length); \
kmemcpy((void*)store, (void*)gen, gen->Length); \
found |= fnd; \
Expand All @@ -220,45 +243,68 @@ static uint8_t hpet_count;
} \
while (0)

static void map_header(const volatile void* table) {
// ACPI memory will never collide, so identity map everything
static inline uint8_t verify_checksum(const volatile struct acpi_gen_header_t* table) {
const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table;
uint64_t alloc_base = (uint64_t)gen & PAGE_BASE_MASK;
return hash_byte_sum((void*)gen, gen->Length);
}

if (!paging_map(alloc_base, alloc_base, PAGE_PRESENT | PAT_MMIO_4K, PAGE_4K)) {
logging_log_error("Failed to map ACPI header");
panic(PANIC_PAGING);
static volatile void* map_table(const volatile void* table) {
uint64_t base = (uint64_t)table & PAGE_BASE_MASK, vaddr, len, off;
volatile struct acpi_gen_header_t* v_table;

vaddr = mm_alloc_v(PAGE_SIZE_4K * 2);
if (!vaddr) {
logging_log_error("Failed to allocate memory for ACPI table");
panic(PANIC_NO_MEM);
}

if ((uint64_t)gen != alloc_base) {
alloc_base += PAGE_SIZE_4K;
if (!paging_map(alloc_base, alloc_base, PAGE_PRESENT | PAT_MMIO_4K, PAGE_4K)) {
logging_log_error("Failed to map ACPI header");
panic(PANIC_PAGING);
}
paging_map(vaddr, base, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K);
paging_map(vaddr + PAGE_SIZE_4K, base + PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K);

v_table = (volatile struct acpi_gen_header_t*)(vaddr + (uint64_t)table - base);
if (!vaddr) {
logging_log_error("Failed to allocate memory for ACPI table");
panic(PANIC_NO_MEM);
}
}

static void map_table(const volatile void* table) {
const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table;
uint64_t alloc_base = (uint64_t)gen & PAGE_BASE_MASK;
logging_log_debug("Found ACPI table %4.4s", &v_table->Signature[0]);
if (verify_checksum(v_table)) {
paging_unmap(vaddr + base, PAGE_4K);
paging_unmap(vaddr + PAGE_SIZE_4K, PAGE_4K);

if ((uint64_t)gen != alloc_base) {
alloc_base += PAGE_SIZE_4K;
mm_free_v(vaddr, PAGE_SIZE_4K * 2);

logging_log_warning("Bad Checksum for %4.4s", &v_table->Signature[0]);
return 0;
}

while (alloc_base < (uint64_t)gen + gen->Length) {
alloc_base += PAGE_SIZE_4K;
if (!paging_map(alloc_base, alloc_base, PAGE_PRESENT | PAT_MMIO_4K, PAGE_4K)) {
logging_log_error("Failed to map ACPI table");
panic(PANIC_PAGING);
}
len = v_table->Length + (uint64_t)table - base;

paging_unmap(vaddr, PAGE_4K);
paging_unmap(vaddr + PAGE_SIZE_4K, PAGE_4K);

mm_free_v(vaddr, PAGE_SIZE_4K * 2);

vaddr = mm_alloc_v(len);
for (off = 0; off < len; off += PAGE_SIZE_4K) {
paging_map(vaddr + off, base + off, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K);
}

return (void*)(vaddr + (uint64_t)table - base);
}

static inline uint8_t verify_checksum(const volatile void* table) {
const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table;
return hash_byte_sum((void*)gen, gen->Length);
static void unmap_table(const volatile void* table) {
volatile struct acpi_gen_header_t* v_table = (volatile struct acpi_gen_header_t*)table;
uint64_t base, len, off;

base = (uint64_t)table & PAGE_BASE_MASK;
len = v_table->Length + (uint64_t)table - base;

for (off = 0; off < len; off += PAGE_SIZE_4K) {
paging_unmap(base + off, PAGE_4K);
}

mm_free_v(base, len);
}

void acpi_copy_tables(void) {
Expand All @@ -283,16 +329,15 @@ void acpi_copy_tables(void) {
case RSDPV1:
fallback:
found = 0;
const struct acpi_rsdt_t* rsdt = (const struct acpi_rsdt_t*)(uint64_t)boot_context.rsdp.RsdtAddress;
map_header(rsdt);
if (kmemcmp(rsdt->Signature, "RSDT", 4)) {
logging_log_error("Bad ACPI RSDT signature");
volatile struct acpi_rsdt_t* rsdt = (volatile struct acpi_rsdt_t*)(uint64_t)boot_context.rsdp.RsdtAddress;
rsdt = map_table(rsdt);
if (!rsdt) {
logging_log_error("Bad RSDT checksum");
panic(PANIC_ACPI);
}
map_table(rsdt);

if (verify_checksum(rsdt)) {
logging_log_error("Bad ACPI RSDT checksum");
if (kmemcmp((void*)rsdt->Signature, "RSDT", 4)) {
logging_log_error("Bad ACPI RSDT signature");
panic(PANIC_ACPI);
}

Expand All @@ -301,28 +346,37 @@ void acpi_copy_tables(void) {
for (const volatile uint32_t* entry = &rsdt->Entry[0];
(uint64_t)entry < (uint64_t)rsdt + rsdt->Length; entry++) {
gen = (const volatile struct acpi_gen_header_t*)(uint64_t)*entry;
map_header(gen);
gen = map_table(gen);

if (!gen) {
continue;
}

#define CHECK_FAIL(sig) CHECK_FAIL_RSDPV1(sig)
CHECK_AND_COPY("FACP", "FADT", acpi_fadt, FOUND_FADT, (void)0);
CHECK_AND_COPY("APIC", "MADT", acpi_madt, FOUND_MADT, (void)0);
#ifdef HPET
CHECK_AND_COPY("HPET", "HPET", acpi_hpet[hpet_count], FOUND_HPET, hpet_count++);
#endif /* HPET */
CHECK_AND_COPY("MCFG", "MCFG", acpi_mcfg, FOUND_MCFG, (void)0);
#undef CHECK_FAIL

unmap_table(gen);
}

if (found != (FOUND_FADT | FOUND_MADT | FOUND_HPET )) {
if (found != FOUND_ALL) {
logging_log_error("Could not find all ACPI tables");
unmap_table(rsdt);
panic(PANIC_ACPI);
}

if (kmemcmp((uint8_t*)rsdt->OEMTableID, (uint8_t*)acpi_fadt->OEMTableID, 8)) {
logging_log_error("Bad ACPI FACP OEM Table ID. Falling back to RSDPV1");
goto fallback;
logging_log_error("Bad ACPI FACP OEM Table ID");
unmap_table(rsdt);
panic(PANIC_ACPI);
}

unmap_table(rsdt);
break;
default:
// backwards compat, so everything else is v2
Expand All @@ -335,16 +389,16 @@ void acpi_copy_tables(void) {
}

found = 0;
const struct acpi_xsdt_t* xsdt = (const struct acpi_xsdt_t*)boot_context.rsdp.XsdtAddress;
map_header(xsdt);
if (kmemcmp(xsdt->Signature, "XSDT", 4)) {
logging_log_warning("Bad ACPI XSDT signature. Falling back to RSDPV1");
volatile struct acpi_xsdt_t* xsdt = (volatile struct acpi_xsdt_t*)boot_context.rsdp.XsdtAddress;
xsdt = map_table(xsdt);

if (!xsdt) {
logging_log_warning("Bad ACPI XSDT checksum. Falling back to RSDPV1");
goto fallback;
}
map_table(xsdt);

if (verify_checksum(xsdt)) {
logging_log_warning("Bad ACPI XSDT checksum. Falling back to RSDPV1");
if (kmemcmp((void*)xsdt->Signature, "XSDT", 4)) {
logging_log_warning("Bad ACPI XSDT signature. Falling back to RSDPV1");
goto fallback;
}

Expand All @@ -353,26 +407,37 @@ void acpi_copy_tables(void) {
for (const volatile uint64_t* entry = &xsdt->Entry[0];
(uint64_t)entry < (uint64_t)xsdt + xsdt->Length; entry++) {
gen = (const volatile struct acpi_gen_header_t*)*entry;
map_header(gen);
gen = map_table(gen);

if (!gen) {
continue;
}

#define CHECK_FAIL(sig) CHECK_FAIL_RSDPV2(sig)
CHECK_AND_COPY("FACP", "FADT", acpi_fadt, FOUND_FADT, (void)0);
CHECK_AND_COPY("APIC", "MADT", acpi_madt, FOUND_MADT, (void)0);
#ifdef HPET
CHECK_AND_COPY("HPET", "HPET", acpi_hpet[hpet_count], FOUND_HPET, hpet_count++);
#endif /* HPET */
CHECK_AND_COPY("MCFG", "MCFG", acpi_mcfg, FOUND_MCFG, (void)0);
#undef CHECK_FAIL

unmap_table(gen);
}

if (found != (FOUND_FADT | FOUND_MADT | FOUND_HPET)) {
if (found != FOUND_ALL) {
logging_log_warning("Could not find all ACPI tables. Falling back to RSDPV1");
unmap_table(xsdt);
goto fallback;
}

if (kmemcmp((uint8_t*)xsdt->OEMTableID, (uint8_t*)acpi_fadt->OEMTableID, 8)) {
logging_log_error("Bad ACPI FACP OEM Table ID. Falling back to RSDPV1");
unmap_table(xsdt);
goto fallback;
}

unmap_table(xsdt);
break;
}
}
Expand All @@ -396,6 +461,24 @@ uint16_t acpi_get_sci_int(void) {
return acpi_fadt->SCI_INT;
}

void acpi_parse_mcfg_conf_start(uint64_t* handle) {
*handle = (uint64_t)&acpi_mcfg->conf[0];
}

void acpi_parse_mcfg_conf(struct acpi_mcfg_conf_t* conf, uint64_t* handle) {
if (*handle + sizeof(struct acpi_mcfg_conf_entry_t) > (uint64_t)acpi_mcfg + acpi_mcfg->Length) {
*handle = 0;
return;
}

const struct acpi_mcfg_conf_entry_t* entry = (struct acpi_mcfg_conf_entry_t*)*handle;
conf->base = entry->base;
conf->segment = entry->group;
conf->bus_start = entry->bus_start;
conf->bus_end = entry->bus_end;
*handle = (uint64_t)(entry + 1);
}

#ifdef HPET
void acpi_get_hpet_bases(uint64_t* bases) {
bases[0] = bases[1] = bases[2] = bases[3] =
Expand Down
4 changes: 4 additions & 0 deletions drivers/acpica/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ $(OBJ_DIR)/../acpica.a: $(OBJ_DIR)/acpica.a
ln $< $@

$(TARGETS): $(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)/
ifdef SUPPRESS_ACPICA_BUILD_OUTPUT
$(CC) $(CFLAGS) -I $(SRC_TREE_ROOT)/include/drivers/acpica/ -Wno-error -o $@ $< 2> /dev/null
else
$(CC) $(CFLAGS) -I $(SRC_TREE_ROOT)/include/drivers/acpica/ -Wno-error -o $@ $<
endif

$(OBJ_DIR)/acpica.a: $(TARGETS)
rm -f $@
Expand Down
Loading