diff options
author | Tyler Murphy <=> | 2023-07-17 19:34:52 -0400 |
---|---|---|
committer | Tyler Murphy <=> | 2023-07-17 19:34:52 -0400 |
commit | 7a912d1b668ab86ffe088eca3ac7e6f78a04a0c5 (patch) | |
tree | 4e86ff20e73171285156631db043e12aaf63bf04 /kernel/src/arch/i686/acpi.c | |
parent | paging (diff) | |
download | finix-7a912d1b668ab86ffe088eca3ac7e6f78a04a0c5.tar.gz finix-7a912d1b668ab86ffe088eca3ac7e6f78a04a0c5.tar.bz2 finix-7a912d1b668ab86ffe088eca3ac7e6f78a04a0c5.zip |
refactoring
Diffstat (limited to 'kernel/src/arch/i686/acpi.c')
-rw-r--r-- | kernel/src/arch/i686/acpi.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/kernel/src/arch/i686/acpi.c b/kernel/src/arch/i686/acpi.c new file mode 100644 index 0000000..7807558 --- /dev/null +++ b/kernel/src/arch/i686/acpi.c @@ -0,0 +1,106 @@ +#include <panic.h> +#include <string.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <arch/i686/acpi.h> +#include <arch/i686/asm.h> + +extern uintptr_t KERNEL_MAPPING; + +static struct RootSystemDescriptionTable *rsdt; +static struct FixedACPIDescriptionTable *fadt; + +static uint16_t SLP_TYPa; +static uint16_t SLP_TYPb; +static uint16_t SLP_EN; +static uint16_t SCI_EN; + +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 void *find_fadt(void) { + int entries = (rsdt->header.length - sizeof(rsdt->header)) / 4; + + for (int i = 0; i < entries; i++) { + uintptr_t sdt_ptr = rsdt->sdt_table[i]; + struct SystemDescriptionTableHeader *h = (void*) sdt_ptr; + if (!strncmp(h->signature, "FACP", 4)) + return (void *) h; + } + + return NULL; +} + +static void read_s5_addr(void) { + uintptr_t ptr = fadt->dsdt; + char *s5_addr = (void*) (ptr + 36); + + int dsdt_len = *((int*) (ptr+1)) - 36; + 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 + SLP_TYPa = *(s5_addr)<<10; + s5_addr++; + + if (*s5_addr == 0x0A) + s5_addr++; // skip byteprefix + SLP_TYPb = *(s5_addr)<<10; + + SLP_EN = 1<<13; + SCI_EN = 1; + + } else { + panic("\\_S5 parse error."); + } + } else { + panic("\\_S5 not present."); + } +} + +void acpi_init(void *ptr) { + + struct RootSystemDescriptionPointer *rsdp = ptr; + if (!checksum((uint8_t*) rsdp, sizeof(struct RootSystemDescriptionPointer))) { + panic("RSDP checksum failed to validate"); + } + + uintptr_t rsdt_ptr = rsdp->rsdt_address; + rsdt = (void *) rsdt_ptr; + if (!checksum((uint8_t*) &rsdt->header, rsdt->header.length)) { + panic("RSDT checksum failed to validate"); + } + + fadt = find_fadt(); + if (fadt == NULL) { + panic("Could not find FADT"); + } + + if (!checksum((uint8_t*) &fadt->header, fadt->header.length)) { + panic("FADT checksum failed to validate"); + } + + read_s5_addr(); + + outb(fadt->smi_command_port,fadt->acpi_enable); +} + +void acpi_poweroff(void) { + outw((unsigned int) fadt->pm1_a_control_block, SLP_TYPb | SLP_EN); + panic("failed to shutdown"); +} |