summaryrefslogtreecommitdiff
path: root/kernel/src/arch/i686/acpi.c
diff options
context:
space:
mode:
authorTyler Murphy <=>2023-07-17 19:34:52 -0400
committerTyler Murphy <=>2023-07-17 19:34:52 -0400
commit7a912d1b668ab86ffe088eca3ac7e6f78a04a0c5 (patch)
tree4e86ff20e73171285156631db043e12aaf63bf04 /kernel/src/arch/i686/acpi.c
parentpaging (diff)
downloadfinix-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.c106
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");
+}