diff options
-rw-r--r-- | build.zig | 2 | ||||
-rw-r--r-- | kernel/drivers/acpi.c | 323 | ||||
-rw-r--r-- | kernel/drivers/drivers.c | 3 | ||||
-rw-r--r-- | kernel/include/comus/drivers/acpi.h | 21 | ||||
-rw-r--r-- | kernel/include/comus/mboot.h | 15 | ||||
-rw-r--r-- | kernel/include/comus/memory.h | 2 | ||||
-rw-r--r-- | kernel/lib/kprintf.c | 4 | ||||
-rw-r--r-- | kernel/main.c | 11 | ||||
-rw-r--r-- | kernel/mboot/mboot.c | 13 | ||||
-rw-r--r-- | kernel/mboot/mboot.h | 2 | ||||
-rw-r--r-- | kernel/mboot/mmap.c | 9 | ||||
-rw-r--r-- | kernel/mboot/rsdp.c | 25 | ||||
-rw-r--r-- | kernel/memory/memory.c | 10 | ||||
-rw-r--r-- | user/lib/printf.c | 4 |
14 files changed, 424 insertions, 20 deletions
@@ -28,6 +28,7 @@ const kernel_src = &[_][]const u8{ "kernel/cpu/idt.c", "kernel/cpu/idt.S", "kernel/cpu/pic.c", + "kernel/drivers/acpi.c", "kernel/drivers/clock.c", "kernel/drivers/drivers.c", "kernel/drivers/pci.c", @@ -64,6 +65,7 @@ const kernel_src = &[_][]const u8{ "kernel/lib/xtoa.c", "kernel/mboot/mboot.c", "kernel/mboot/mmap.c", + "kernel/mboot/rsdp.c", "kernel/memory/memory.c", "kernel/memory/paging.c", "kernel/memory/physalloc.c", diff --git a/kernel/drivers/acpi.c b/kernel/drivers/acpi.c new file mode 100644 index 0000000..a222523 --- /dev/null +++ b/kernel/drivers/acpi.c @@ -0,0 +1,323 @@ +#include <lib.h> +#include <comus/drivers/acpi.h> +#include <comus/asm.h> +#include <comus/memory.h> + +struct acpi_header { + uint32_t signature; + uint32_t length; + uint8_t revision; + uint8_t checksum; + uint8_t oem_id[6]; + uint8_t oem_table_id[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; +} __attribute__((packed)); + +// root system descriptor pointer +// ACPI 1.0 +struct rsdp { + uint8_t signature[8]; + uint8_t checksum; + uint8_t oemid[6]; + uint8_t revision; + uint32_t rsdt_addr; +} __attribute__((packed)); + +// eXtended system descriptor pointer +// ACPI 2.0 +struct xsdp { + char signature[8]; + uint8_t checksum; + char oemid[6]; + uint8_t revision; + uint32_t rsdt_addr; + uint32_t length; + uint64_t xsdt_addr; + uint8_t extendeid_checksum; + uint8_t reserved[3]; +} __attribute__((packed)); + +// root system descriptor table +// ACPI 1.0 +struct rsdt { + struct acpi_header h; + uint32_t sdt_pointers[]; +} __attribute__((packed)); + +// eXtended system descriptor table +// ACPI 2.0 +struct xsdt { + struct acpi_header h; + uint64_t sdt_pointers[]; +} __attribute__((packed)); + + +// generic address structure +struct gas { + uint8_t address_space; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t access_size; + uint64_t address; +}; + +// differentiated system description table +struct dsdt { + struct acpi_header h; + char s5_addr[]; +} __attribute__((packed)); + +struct apic { + struct acpi_header h; + // todo +} __attribute__((packed)); + +struct hept { + struct acpi_header h; + // todo +} __attribute__((packed)); + +struct waet { + struct acpi_header h; + // todo +} __attribute__((packed)); + +// fixed acpi description table +struct fadt { + struct acpi_header h; + uint32_t firmware_ctrl; + uint32_t dsdt; + + // field used in ACPI 1.0; no longer in use, for compatibility only + uint8_t reserved; + + uint8_t preferred_power_management_profile; + uint16_t sci_interrupt; + uint32_t smi_command_port; + uint8_t acpi_enable; + uint8_t acpi_disable; + uint8_t s4bios_req; + uint8_t pstate_control; + uint32_t pm1_a_event_block; + uint32_t pm1_b_event_block; + uint32_t pm1_a_control_block; + uint32_t pm1_b_control_block; + uint32_t pm2_control_block; + uint32_t pm_timer_block; + uint32_t gpe0_block; + uint32_t gpe1_block; + uint8_t pm1_event_length; + uint8_t pm1_control_length; + uint8_t pm2_control_length; + uint8_t pm_timer_length; + uint8_t gpe0_length; + uint8_t gpe1_length; + uint8_t gpe1_base; + uint8_t cstate_control; + uint16_t worst_c2_latency; + uint16_t worst_c3_latency; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alarm; + uint8_t month_alarm; + uint8_t century; + + // reserved in ACPI 1.0; used since ACPI 2.0+ + uint16_t boot_architecture_flags; + + uint8_t reserved_2; + uint32_t flags; + + // 12 byte structure; see below for details + struct gas reset_reg; + + uint8_t reset_value; + uint8_t reserved_3[3]; + + // 64bit pointers - Available on ACPI 2.0+ + uint64_t x_firmware_control; + uint64_t x_dsdt; + + struct gas x_pm1_a_event_block; + struct gas x_pm1_b_event_block; + struct gas x_pm1_a_control_block; + struct gas x_pm1_b_control_block; + struct gas x_pm2_control_block; + struct gas x_pm_timer_block; + struct gas x_gpe0_block; + struct gas x_gpe1_block; +} __attribute__((packed)); + +struct acpi_state { + union { + struct xsdt *xsdt; + struct rsdt *rsdt; + } sdt; + struct fadt *fadt; + struct dsdt *dsdt; + struct apic *apic; + struct hept *hept; + struct waet *waet; + uint8_t version; + + uint16_t SLP_TYPa; + uint16_t SLP_TYPb; + uint16_t SLP_EN; + uint16_t SCI_EN; +}; + +/* global state, idk a better way rn */ +static struct acpi_state state; + +static bool checksum(uint8_t *data, size_t len) { + unsigned char sum = 0; + for (size_t i = 0; i < len; i++) + sum += data[i]; + return sum == 0; +} + +static int read_s5_addr(struct dsdt *dsdt) { + char *s5_addr = dsdt->s5_addr; + int dsdt_len = dsdt->h.length - sizeof(struct acpi_header); + + while (0 < dsdt_len--) { + if (memcmp(s5_addr, "_S5_", 4) == 0) + break; + s5_addr++; + } + + if (dsdt_len > 0) { + // check for valid AML structure + if ( ( *(s5_addr-1) == 0x08 || ( *(s5_addr-2) == 0x08 && *(s5_addr-1) == '\\') ) && *(s5_addr+4) == 0x12 ) { + s5_addr += 5; + s5_addr += ((*s5_addr &0xC0)>>6) +2; // calculate PkgLength size + + if (*s5_addr == 0x0A) + s5_addr++; // skip byteprefix + state.SLP_TYPa = *(s5_addr)<<10; + s5_addr++; + + if (*s5_addr == 0x0A) + s5_addr++; // skip byteprefix + state.SLP_TYPb = *(s5_addr)<<10; + + state.SLP_EN = 1<<13; + state.SCI_EN = 1; + + } else { + return -1; + } + } else { + return -1; + } + + return -1; +} + +static void acpi_load_table(uint64_t addr); + +static void acpi_load_rsdt_tables(struct rsdt *rsdt) { + int entries = (rsdt->h.length - sizeof(rsdt->h)) / 4; + for (int i = 0; i < entries; i++) { + uint32_t addr = rsdt->sdt_pointers[i]; + acpi_load_table(addr); + } +} + +static void acpi_load_xsdt_tables(struct xsdt *xsdt) { + int entries = (xsdt->h.length - sizeof(xsdt->h)) / 8; + for (int i = 0; i < entries; i++) { + uint64_t addr = xsdt->sdt_pointers[i]; + acpi_load_table(addr); + } +} + +#define SIG_RSDT 0x54445352 +#define SIG_XSDT 0x54445358 +#define SIG_FACP 0x50434146 +#define SIG_DSDT 0x54445344 +#define SIG_APIC 0x43495041 +#define SIG_HEPT 0x54455048 +#define SIG_WAET 0x54454157 + +static void acpi_handle_table(struct acpi_header *header) { + switch (header->signature) { + case SIG_RSDT: + state.sdt.rsdt = (struct rsdt *) header; + acpi_load_rsdt_tables(state.sdt.rsdt); + break; + case SIG_XSDT: + state.sdt.xsdt = (struct xsdt *) header; + acpi_load_xsdt_tables(state.sdt.xsdt); + break; + case SIG_FACP: + state.fadt = (struct fadt *) header; + acpi_load_table(state.fadt->dsdt); + break; + case SIG_DSDT: + state.dsdt = (struct dsdt *) header; + read_s5_addr(state.dsdt); + break; + case SIG_APIC: + state.apic = (struct apic *) header; + break; + case SIG_HEPT: + state.hept = (struct hept *) header; + break; + case SIG_WAET: + state.waet = (struct waet *) header; + break; + default: + break; + } +} + +static void acpi_load_table(uint64_t addr) { + struct acpi_header *temp, *mapped; + uint32_t length; + temp = (struct acpi_header * ) (uintptr_t) addr; + mapped = kmapaddr(temp, sizeof(struct acpi_header)); + length = mapped->length; + kunmapaddr(mapped); + mapped = kmapaddr(temp, length); + if (!checksum((uint8_t *) mapped, mapped->length)) { + kunmapaddr(mapped); + return; + } + kprintf("%.*s: %#016lx\n", 4, (char*)&mapped->signature, (size_t)temp); + acpi_handle_table(mapped); +} + +void acpi_init(void *rootsdp) { + memset(&state, 0, sizeof(struct acpi_state)); + struct rsdp *rsdp = (struct rsdp *) rootsdp; + if (!checksum((uint8_t *)rsdp, sizeof(struct rsdp))) { + panic("invalid acpi rsdp checksum"); + } + if (memcmp(rsdp->signature, "RSD PTR ", 8) != 0) { + panic("invalid acpi rsdp signature: %.*s\n", 8, rsdp->signature); + } + if (rsdp->revision == 0) { + state.version = 0; + kprintf("ACPI 1.0\n"); + acpi_load_table(rsdp->rsdt_addr); + } else if (rsdp->revision == 2) { + state.version = 2; + struct xsdp *xsdp = (struct xsdp *) rsdp; + kprintf("ACPI 2.0\n"); + acpi_load_table(xsdp->xsdt_addr); + } else { + panic("invalid acpi rev: %d\n", rsdp->revision); + } + kprintf("\n"); + outb(state.fadt->smi_command_port, state.fadt->acpi_enable); +} + +void acpi_shutdown(void) { + outw((unsigned int) state.fadt->pm1_a_control_block, state.SLP_TYPb | state.SLP_EN); + panic("ACPI shutdown failed"); +} diff --git a/kernel/drivers/drivers.c b/kernel/drivers/drivers.c index 9b90eb8..4e8f175 100644 --- a/kernel/drivers/drivers.c +++ b/kernel/drivers/drivers.c @@ -1,9 +1,12 @@ #include <comus/drivers.h> +#include <comus/drivers/acpi.h> #include <comus/drivers/uart.h> #include <comus/drivers/pci.h> +#include <comus/mboot.h> void drivers_init(void) { uart_init(); pci_init(); + acpi_init(mboot_get_rsdp()); } diff --git a/kernel/include/comus/drivers/acpi.h b/kernel/include/comus/drivers/acpi.h new file mode 100644 index 0000000..b28633c --- /dev/null +++ b/kernel/include/comus/drivers/acpi.h @@ -0,0 +1,21 @@ +/** + * @file acpi.h + * + * @author Freya Murphy <freya@freyacat.org> + * + * ACPI definitions + */ + +/** + * Loads the ACPI tables + * https://en.wikipedia.org/wiki/ACPI + * @param rsdp - pointer to the Root System Description Pointer + * usually passed from the bootloader + */ +void acpi_init(void *rsdp); + +/** + * Shutdowns down the system + */ +__attribute__((noreturn)) +void acpi_shutdown(void); diff --git a/kernel/include/comus/mboot.h b/kernel/include/comus/mboot.h index f89427e..ebd5dad 100644 --- a/kernel/include/comus/mboot.h +++ b/kernel/include/comus/mboot.h @@ -11,6 +11,19 @@ #include <comus/memory.h> -void mboot_load_mmap(volatile void *mboot, struct memory_map *map); +/** + * Load the multiboot information passed from the bootloader + */ +void mboot_init(long magic, volatile void *mboot); + +/** + * Get the memory map from multiboot + */ +int mboot_get_mmap(struct memory_map *map); + +/** + * Get the ACPI rsdp addr from multiboot + */ +void *mboot_get_rsdp(void); #endif /* mboot.h */ diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h index 294c795..77d64ff 100644 --- a/kernel/include/comus/memory.h +++ b/kernel/include/comus/memory.h @@ -28,7 +28,7 @@ struct memory_map { /** * Initalize system memory allocator */ -void memory_init(struct memory_map *map); +void memory_init(void); /** * @returns how much memory the system has diff --git a/kernel/lib/kprintf.c b/kernel/lib/kprintf.c index 40cf819..e01b091 100644 --- a/kernel/lib/kprintf.c +++ b/kernel/lib/kprintf.c @@ -129,7 +129,7 @@ static void parse_width(const char **res, options_t *opts) // check varies if (*fmt == '*') { opts->width_varies = true; - *res = fmt++; + *res = ++fmt; return; } @@ -155,7 +155,7 @@ static void parse_precision(const char **res, options_t *opts) // check varies if (*fmt == '*') { opts->precision_varies = true; - *res = fmt++; + *res = ++fmt; return; } diff --git a/kernel/main.c b/kernel/main.c index 5b06ae2..4f91d95 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -5,21 +5,16 @@ #include <comus/fs.h> #include <lib.h> -struct memory_map mmap; - void main(long magic, volatile void *mboot) { - (void)magic; // TODO: check multiboot magic - // initalize idt and pic - // WARNING: must be done before anything else cpu_init(); - // load memory map - mboot_load_mmap(mboot, &mmap); + // load multiboot information + mboot_init(magic, mboot); // initalize memory - memory_init(&mmap); + memory_init(); // initalize devices drivers_init(); diff --git a/kernel/mboot/mboot.c b/kernel/mboot/mboot.c index 9156c3c..ce74cc1 100644 --- a/kernel/mboot/mboot.c +++ b/kernel/mboot/mboot.c @@ -1,7 +1,18 @@ +#include <lib.h> +#include <comus/mboot.h> #include "mboot.h" -void *locate_mboot_table(volatile void *mboot, uint32_t type) +static volatile void *mboot; + +void mboot_init(long magic, volatile void *ptr) +{ + if (magic != MBOOT_HEADER_MAGIC) + panic("invalid multiboot magic"); + mboot = ptr; +} + +void *locate_mboot_table(uint32_t type) { struct mboot_info *info = (struct mboot_info *)mboot; const char *mboot_end = ((char *)info) + info->total_size; diff --git a/kernel/mboot/mboot.h b/kernel/mboot/mboot.h index db85de1..7e8c09a 100644 --- a/kernel/mboot/mboot.h +++ b/kernel/mboot/mboot.h @@ -100,6 +100,6 @@ struct mboot_tag_framebuffer { uint16_t reserved; }; -void *locate_mboot_table(volatile void *mboot, uint32_t type); +void *locate_mboot_table(uint32_t type); #endif /* mboot.h */ diff --git a/kernel/mboot/mmap.c b/kernel/mboot/mmap.c index 8a5f549..1b5f08b 100644 --- a/kernel/mboot/mmap.c +++ b/kernel/mboot/mmap.c @@ -8,9 +8,12 @@ static const char *segment_type[] = { "Reserved", "Free", "Hibernation", "Defective", "Unknown" }; -void mboot_load_mmap(volatile void *mboot, struct memory_map *res) +int mboot_get_mmap(struct memory_map *res) { - void *tag = locate_mboot_table(mboot, MBOOT_MEMORY_MAP); + void *tag = locate_mboot_table(MBOOT_MEMORY_MAP); + if (tag == NULL) + return 1; + struct mboot_tag_mmap *mmap = (struct mboot_tag_mmap *)tag; int idx = 0; @@ -33,4 +36,6 @@ void mboot_load_mmap(volatile void *mboot, struct memory_map *res) res->entries[idx].len = seg->len; } res->entry_count = idx; + + return 0; } diff --git a/kernel/mboot/rsdp.c b/kernel/mboot/rsdp.c new file mode 100644 index 0000000..fb49187 --- /dev/null +++ b/kernel/mboot/rsdp.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <comus/mboot.h> + +#include "mboot.h" + +void *mboot_get_rsdp(void) +{ + void *tag; + + // acpi 2.0 + tag = locate_mboot_table(MBOOT_NEW_RSDP); + if (tag != NULL) { + struct mboot_tag_new_rsdp *rsdp = (struct mboot_tag_new_rsdp *) tag; + return rsdp->rsdp; + } + + // acpi 1.0 + tag = locate_mboot_table(MBOOT_OLD_RSDP); + if (tag != NULL) { + struct mboot_tag_old_rsdp *rsdp = (struct mboot_tag_old_rsdp *) tag; + return rsdp->rsdp; + } + + return NULL; +} diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c index 1334051..145ce2b 100644 --- a/kernel/memory/memory.c +++ b/kernel/memory/memory.c @@ -1,15 +1,21 @@ #include <comus/memory.h> #include <comus/asm.h> +#include <comus/mboot.h> +#include <lib.h> #include "paging.h" #include "virtalloc.h" #include "physalloc.h" -void memory_init(struct memory_map *map) +void memory_init(void) { + struct memory_map mmap; + if (mboot_get_mmap(&mmap)) + panic("failed to load memory map"); + cli(); paging_init(); virtaddr_init(); - physalloc_init(map); + physalloc_init(&mmap); sti(); } diff --git a/user/lib/printf.c b/user/lib/printf.c index 4a85956..53f98a6 100644 --- a/user/lib/printf.c +++ b/user/lib/printf.c @@ -135,7 +135,7 @@ static void parse_width(const char **res, options_t *opts) // check varies if (*fmt == '*') { opts->width_varies = true; - *res = fmt++; + *res = ++fmt; return; } @@ -161,7 +161,7 @@ static void parse_precision(const char **res, options_t *opts) // check varies if (*fmt == '*') { opts->precision_varies = true; - *res = fmt++; + *res = ++fmt; return; } |