diff --git a/conf/make/amd64.mk b/conf/make/amd64.mk index 3926178..7520789 100644 --- a/conf/make/amd64.mk +++ b/conf/make/amd64.mk @@ -15,14 +15,17 @@ OBJS+=$(O)/arch/amd64/kernel.o \ $(O)/arch/amd64/hw/pic8259.o \ $(O)/arch/amd64/hw/irqs.o \ $(O)/arch/amd64/mm/map.o \ - $(O)/arch/amd64/hw/timer.o + $(O)/arch/amd64/hw/timer.o \ + $(O)/arch/amd64/acpi/tables.o \ + $(O)/arch/amd64/acpi/hpet.o kernel_OBJS=$(O)/arch/amd64/entry.o \ $(OBJS) kernel_LINKER=$(S)/arch/amd64/link.ld kernel_LDFLAGS=-nostdlib -T$(kernel_LINKER) kernel_CFLAGS=-ffreestanding -I. $(DEFINES) $(CFLAGS) -mcmodel=large -m64 DIRS+=$(O)/arch/amd64/mm \ - $(O)/arch/amd64/hw + $(O)/arch/amd64/hw \ + $(O)/arch/amd64/acpi # add .inc includes for asm HEADERS+=$(shell find $(S) -name "*.inc") diff --git a/include/arch/amd64/acpi/hpet.h b/include/arch/amd64/acpi/hpet.h new file mode 100644 index 0000000..a739fe1 --- /dev/null +++ b/include/arch/amd64/acpi/hpet.h @@ -0,0 +1,23 @@ +#pragma once +#include + +struct hpet_timer_block { + uint64_t timer_cfgr; + uint64_t timer_cmpr; + uint64_t timer_intr; + uint64_t __res0; +}; + +struct hpet { + uint64_t hpet_caps; + uint64_t __res0; + uint64_t hpet_cfgr; + uint64_t __res1; + uint64_t hpet_isr; + char __res2[200]; + uint64_t hpet_cntr; + uint64_t __res3; + struct hpet_timer_block timers[32]; +}; + +struct hpet *acpi_hpet_get(void); diff --git a/include/arch/amd64/acpi/tables.h b/include/arch/amd64/acpi/tables.h new file mode 100644 index 0000000..b39937c --- /dev/null +++ b/include/arch/amd64/acpi/tables.h @@ -0,0 +1,99 @@ +#pragma once +#include + +struct acpi_rsdp { + char signature[8]; + char checksum; + char oemid[6]; + char rev; + uint32_t rsdt_addr; +}; + +struct acpi_rsdp_extended { + struct acpi_rsdp rsdp; + uint32_t length; + uint64_t xsdt_addr; + char checksum2; + char res[3]; +}; + +struct acpi_sdt_header { + char signature[4]; + uint32_t length; + char rev; + char checksum; + char oemid[6]; + char oemtableid[8]; + uint32_t oemrev; + uint32_t creatorid; + uint32_t creatorrev; +}; + +struct acpi_rsdt { + struct acpi_sdt_header header; + uint32_t entries[1]; +}; + +struct acpi_xsdt { + struct acpi_sdt_header header; + uint64_t entries[1]; +}; + +struct acpi_fadt { + struct acpi_sdt_header header; + uint32_t firmware_ctrl; + uint32_t dsdt; + char res0; + char preferred_pm_profile; + uint16_t sci_int; + uint32_t smi_cmd; + char acpi_enable; + char acpi_disable; + char s4bios_req; + char pstate_cnt; + uint32_t pm1a_evt_blk; + uint32_t pm1b_evt_blk; + uint32_t pm1a_cnt_blk; + uint32_t pm1b_cnt_blk; + uint32_t pm2_cnt_blk; + uint32_t pm_tmr_blk; + uint32_t gpe0_blk; + uint32_t gpe1_blk; + char pm1_evt_len; + char pm1_cnt_len; + char pm2_cnt_len; + char pm_tmr_len; + char gpe0_blk_len; + char gpe1_blk_len; + char gpe1_base; + char cst_cnt; + uint16_t p_lvl2_lat; + uint16_t p_lvl3_lat; + uint16_t flush_size; + uint16_t flush_stride; + char duty_offset; + char duty_width; + char day_alrm; + char mon_alrm; + char century; + uint16_t ipac_boot_arch; + char res1; + uint32_t flags; + char reset_reg[12]; + char reset_value; + uint16_t arm_boot_arch; + char fadt_minor_version; +}; + +enum acpi_table_type { + ACPI_FADT, + ACPI_APIC, + ACPI_HPET, + ACPI_TABLE_TYPE_COUNT +}; + +//// + +extern uintptr_t acpi_tables[ACPI_TABLE_TYPE_COUNT]; + +int acpi_tables_init(void); diff --git a/include/sys/mem.h b/include/sys/mem.h index 5a0580f..c95e4a2 100644 --- a/include/sys/mem.h +++ b/include/sys/mem.h @@ -3,3 +3,4 @@ #include void *memset(void *blk, int v, size_t sz); +void *memcpy(void *dst, const void *src, size_t sz); diff --git a/include/sys/string.h b/include/sys/string.h index 1679ac4..df82ad9 100644 --- a/include/sys/string.h +++ b/include/sys/string.h @@ -2,3 +2,4 @@ #include size_t strlen(const char *s); +int strncmp(const char *a, const char *b, size_t lim); diff --git a/src/arch/amd64/acpi/hpet.c b/src/arch/amd64/acpi/hpet.c new file mode 100644 index 0000000..987795b --- /dev/null +++ b/src/arch/amd64/acpi/hpet.c @@ -0,0 +1,11 @@ +#include "arch/amd64/acpi/hpet.h" +#include "arch/amd64/acpi/tables.h" +#include "sys/mm.h" + +struct hpet *acpi_hpet_get(void) { + if (acpi_tables[ACPI_HPET] == MM_NADDR) { + return 0; + } + + return (struct hpet *) MM_VIRTUALIZE(acpi_tables[ACPI_HPET]); +} diff --git a/src/arch/amd64/acpi/tables.c b/src/arch/amd64/acpi/tables.c new file mode 100644 index 0000000..8803c40 --- /dev/null +++ b/src/arch/amd64/acpi/tables.c @@ -0,0 +1,125 @@ +#include "arch/amd64/acpi/tables.h" +#include "sys/string.h" +#include "sys/panic.h" +#include "sys/debug.h" +#include "sys/mem.h" +#include "sys/mm.h" + +#define ACPI_SIGN_RSDP "RSD PTR " +#define ACPI_SIGN_FADT "FACP" +#define ACPI_SIGN_APIC "APIC" +#define ACPI_SIGN_HPET "HPET" + +static const char *acpi_table_type_name[ACPI_TABLE_TYPE_COUNT] = { + ACPI_SIGN_FADT, + ACPI_SIGN_APIC, + ACPI_SIGN_HPET +}; +uintptr_t acpi_tables[ACPI_TABLE_TYPE_COUNT] = { MM_NADDR }; + +static char acpi_checksum(const void *block, size_t count) { + char r = 0; + for (size_t i = 0; i < count; ++i) { + r += ((const char *) block)[i]; + } + return r; +} + +static int acpi_xsdp_read(const struct acpi_rsdp_extended *xsdp) { + panic("Not yet implemented\n"); + return 0; +} + +static int acpi_rsdp_read(const struct acpi_rsdp *rsdp) { + struct acpi_rsdt *rsdt = (struct acpi_rsdt *) MM_VIRTUALIZE(rsdp->rsdt_addr); + + if (strncmp(rsdt->header.signature, "RSDT", 4)) { + panic("RSDP does not point to a valid RSDT\n"); + } + + if (acpi_checksum(rsdt, rsdt->header.length)) { + panic("RSDT checksum is invalid\n"); + } + + uint32_t nentr = (rsdt->header.length - sizeof(struct acpi_sdt_header)) / 4; + kdebug("RSDT contains %u entries\n", nentr); + + // Dump entries + for (uint32_t i = 0; i < nentr; ++i) { + struct acpi_sdt_header *header = (struct acpi_sdt_header *) MM_VIRTUALIZE(rsdt->entries[i]); + // Find out the type of the table + for (size_t j = 0; j < ACPI_TABLE_TYPE_COUNT; ++j) { + if (!strncmp(header->signature, acpi_table_type_name[j], 4)) { + kdebug("%u: %s\n", i, acpi_table_type_name[j]); + acpi_tables[j] = (uintptr_t) header; + continue; + } + } + // Ignore the table otherwise - it's unknown to us + } + + // Must have FADT table + if (acpi_tables[ACPI_FADT] == MM_NADDR) { + panic("RSDT contained no FADT pointer\n"); + } + + return 0; +} + +int acpi_tables_init(void) { + kdebug("Trying to locate ACPI tables\n"); + + struct acpi_rsdp *rsdp = (struct acpi_rsdp *) MM_NADDR; + struct acpi_rsdp_extended *xsdp = (struct acpi_rsdp_extended *) MM_NADDR; + + // 1. Try locating in EBDA + uintptr_t ebda_base = ((uintptr_t) (*((uint16_t *) MM_VIRTUALIZE(0x040E)))) << 4; + ebda_base = MM_VIRTUALIZE(ebda_base); + kdebug("Possible EBDA location: %p\n", ebda_base); + + for (uintptr_t addr = ebda_base & ~0xF; addr < ebda_base + 1024; ++addr) { + if (!strncmp((const char *) addr, ACPI_SIGN_RSDP, 8)) { + rsdp = (struct acpi_rsdp *) addr; + if (acpi_checksum(rsdp, sizeof(struct acpi_rsdp))) { + rsdp = (struct acpi_rsdp *) MM_NADDR; + continue; + } + kdebug("Found RSDP in EBDA @ %p\n", addr); + break; + } + } + + // 2. Try searching in 0xE0000 - 0xFFFFF + for (uintptr_t addr = MM_VIRTUALIZE(0xE0000); addr < MM_VIRTUALIZE(0xFFFFF); ++addr) { + if (!strncmp((const char *) addr, ACPI_SIGN_RSDP, 8)) { + rsdp = (struct acpi_rsdp *) addr; + if (acpi_checksum(rsdp, sizeof(struct acpi_rsdp))) { + rsdp = (struct acpi_rsdp *) MM_NADDR; + continue; + } + kdebug("Found RSDP in BIOS romem @ %p\n", addr); + break; + } + } + + if (rsdp == (struct acpi_rsdp *) MM_NADDR) { + return -1; + } + + kdebug("RSDP revision is %d\n", rsdp->rev); + // Check if RSDP is an extended one + if (rsdp->rev == 2) { + xsdp = (struct acpi_rsdp_extended *) rsdp; + if (acpi_xsdp_read(xsdp) != 0) { + return -1; + } + } else { + kdebug("Falling back to ACPI 1.0\n"); + if (acpi_rsdp_read(rsdp) != 0) { + return -1; + } + } + // TODO: FADT does not validate on qemu, neither have I tested ACPI > 1.0 + + return 0; +} diff --git a/src/arch/amd64/hw/timer.c b/src/arch/amd64/hw/timer.c index 23e5a14..69da31a 100644 --- a/src/arch/amd64/hw/timer.c +++ b/src/arch/amd64/hw/timer.c @@ -34,6 +34,7 @@ uint64_t amd64_timer_ticks = 0; void amd64_timer_configure(void) { + // TODO: HPET init uint32_t div = PIT_FREQ_BASE / 1000; outb(PIT_CMD, PIT_CH0 | PIT_BCD_NO | PIT_ACC_16 | PIT_MODE_RATEG); diff --git a/src/arch/amd64/kernel.c b/src/arch/amd64/kernel.c index c4ebb9e..f8900f0 100644 --- a/src/arch/amd64/kernel.c +++ b/src/arch/amd64/kernel.c @@ -4,6 +4,7 @@ #include "arch/amd64/hw/pic8259.h" #include "arch/amd64/hw/ints.h" #include "arch/amd64/hw/timer.h" +#include "arch/amd64/acpi/tables.h" // TODO: move to some util header #define __wfe() asm volatile ("sti; hlt") @@ -19,6 +20,7 @@ void kernel_main(void) { amd64_mm_init(); amd64_gdt_init(); pic8259_init(); + acpi_tables_init(); amd64_timer_configure(); amd64_idt_init(); diff --git a/src/sys/mem.c b/src/sys/mem.c index 4338ac5..d9d5ebe 100644 --- a/src/sys/mem.c +++ b/src/sys/mem.c @@ -6,3 +6,10 @@ void *memset(void *blk, int v, size_t sz) { } return blk; } + +void *memcpy(void *dst, const void *src, size_t sz) { + for (size_t i = 0; i < sz; ++i) { + ((char *) dst)[i] = ((const char *) src)[i]; + } + return dst; +} diff --git a/src/sys/string.c b/src/sys/string.c index bbedab2..d14e5e0 100644 --- a/src/sys/string.c +++ b/src/sys/string.c @@ -7,3 +7,13 @@ size_t strlen(const char *a) { } return s; } + +int strncmp(const char *a, const char *b, size_t n) { + size_t c = 0; + for (; c < n && (*a || *b); ++c, ++a, ++b) { + if (*a != *b) { + return -1; + } + } + return 0; +}