#include "arch/i686/mboot.h" #include "arch/i686/paging.h" #include #include #include #include #include #include #include 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) { struct BootTag *tag; if (!get_boot_tag(ID_RSDP, &tag)) { panic("Could not find RSDP"); } struct RootSystemDescriptionPointer *rsdp = tag->data.rsdp; 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; ident_map_addr(rsdt, 1000); if (!checksum((uint8_t*) &rsdt->header, rsdt->header.length)) { panic("RSDT checksum failed to validate"); } return; 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); panic("C"); } void acpi_poweroff(void) { outw((unsigned int) fadt->pm1_a_control_block, SLP_TYPb | SLP_EN); panic("failed to shutdown"); }