From b762345c4960689c2de05c63ee3037c8baaed1dd Mon Sep 17 00:00:00 2001 From: Baptiste Wicht Date: Sun, 24 Jul 2016 12:30:24 +0200 Subject: [PATCH] Use ACPICA directly for shutdown --- kernel/src/acpi.cpp | 330 ++++++++------------------------------------ 1 file changed, 59 insertions(+), 271 deletions(-) diff --git a/kernel/src/acpi.cpp b/kernel/src/acpi.cpp index 17e32005..0e438fbe 100644 --- a/kernel/src/acpi.cpp +++ b/kernel/src/acpi.cpp @@ -13,266 +13,50 @@ #include "console.hpp" #include "logging.hpp" #include "scheduler.hpp" +#include "arch.hpp" namespace { +// This is copied from acexcep.h +// This could be used with ACPI_DEFINE_EXCEPTION_TABLE but this +// generates too many warnings and errors + +static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Env[] = { + EXCEP_TXT ("AE_OK", "No error"), + EXCEP_TXT ("AE_ERROR", "Unspecified error"), + EXCEP_TXT ("AE_NO_ACPI_TABLES", "ACPI tables could not be found"), + EXCEP_TXT ("AE_NO_NAMESPACE", "A namespace has not been loaded"), + EXCEP_TXT ("AE_NO_MEMORY", "Insufficient dynamic memory"), + EXCEP_TXT ("AE_NOT_FOUND", "A requested entity is not found"), + EXCEP_TXT ("AE_NOT_EXIST", "A required entity does not exist"), + EXCEP_TXT ("AE_ALREADY_EXISTS", "An entity already exists"), + EXCEP_TXT ("AE_TYPE", "The object type is incorrect"), + EXCEP_TXT ("AE_NULL_OBJECT", "A required object was missing"), + EXCEP_TXT ("AE_NULL_ENTRY", "The requested object does not exist"), + EXCEP_TXT ("AE_BUFFER_OVERFLOW", "The buffer provided is too small"), + EXCEP_TXT ("AE_STACK_OVERFLOW", "An internal stack overflowed"), + EXCEP_TXT ("AE_STACK_UNDERFLOW", "An internal stack underflowed"), + EXCEP_TXT ("AE_NOT_IMPLEMENTED", "The feature is not implemented"), + EXCEP_TXT ("AE_SUPPORT", "The feature is not supported"), + EXCEP_TXT ("AE_LIMIT", "A predefined limit was exceeded"), + EXCEP_TXT ("AE_TIME", "A time limit or timeout expired"), + EXCEP_TXT ("AE_ACQUIRE_DEADLOCK", "Internal error, attempt was made to acquire a mutex in improper order"), + EXCEP_TXT ("AE_RELEASE_DEADLOCK", "Internal error, attempt was made to release a mutex in improper order"), + EXCEP_TXT ("AE_NOT_ACQUIRED", "An attempt to release a mutex or Global Lock without a previous acquire"), + EXCEP_TXT ("AE_ALREADY_ACQUIRED", "Internal error, attempt was made to acquire a mutex twice"), + EXCEP_TXT ("AE_NO_HARDWARE_RESPONSE", "Hardware did not respond after an I/O operation"), + EXCEP_TXT ("AE_NO_GLOBAL_LOCK", "There is no FACS Global Lock"), + EXCEP_TXT ("AE_ABORT_METHOD", "A control method was aborted"), + EXCEP_TXT ("AE_SAME_HANDLER", "Attempt was made to install the same handler that is already installed"), + EXCEP_TXT ("AE_NO_HANDLER", "A handler for the operation is not installed"), + EXCEP_TXT ("AE_OWNER_ID_LIMIT", "There are no more Owner IDs available for ACPI tables or control methods"), + EXCEP_TXT ("AE_NOT_CONFIGURED", "The interface is not part of the current subsystem configuration"), + EXCEP_TXT ("AE_ACCESS", "Permission denied for the requested operation"), + EXCEP_TXT ("AE_IO_ERROR", "An I/O error occurred") +}; + volatile bool acpi_initialized = false; -uint32_t SMI_CMD; //ptr -uint8_t ACPI_ENABLE; -uint8_t ACPI_DISABLE; -uint32_t PM1a_CNT; //ptr -uint32_t PM1b_CNT; //ptr -uint16_t SLP_TYPa; -uint16_t SLP_TYPb; -uint16_t SLP_EN; -uint16_t SCI_EN; -uint8_t PM1_CNT_LEN; - -bool version_2 = false; - -struct RSDPtr { - uint8_t Signature[8]; - uint8_t CheckSum; - uint8_t OemID[6]; - uint8_t Revision; - uint32_t RsdtAddress; //ptr -}; - -struct FACP { - uint8_t Signature[4]; - uint32_t Length; - uint8_t unneded1[40 - 8]; - uint32_t DSDT; //ptr - uint8_t unneded2[48 - 44]; - uint32_t SMI_CMD; //ptr - uint8_t ACPI_ENABLE; - uint8_t ACPI_DISABLE; - uint8_t unneded3[64 - 54]; - uint32_t PM1a_CNT_BLK; //ptr - uint32_t PM1b_CNT_BLK; //ptr - uint8_t unneded4[89 - 72]; - uint8_t PM1_CNT_LEN; -}; - -// check if the given address has a valid header -unsigned int* check_rsd_ptr(unsigned int *ptr) { - const char* sig = "RSD PTR "; - auto rsdp = reinterpret_cast(ptr); - - if (std::equal_n(sig, reinterpret_cast(rsdp), 8)){ - uint8_t check = 0; - - // check checksum rsdpd - auto bptr = reinterpret_cast(ptr); - for (size_t i=0; iRevision != 0; - - return reinterpret_cast(rsdp->RsdtAddress); - } - } - - return nullptr; -} - -// finds the acpi header and returns the address of the rsdt -unsigned int *get_rsd_ptr(void){ - // search below the 1mb mark for RSDP signature - for (auto addr = reinterpret_cast(0x000E0000); reinterpret_cast(addr) < 0x00100000; addr += 0x10 / sizeof(addr)){ - auto rsdp = check_rsd_ptr(addr); - if (rsdp){ - return rsdp; - } - } - - // at address 0x40:0x0E is the RM segment of the ebda - unsigned int ebda = *(reinterpret_cast(0x40E)); // get pointer - ebda = ebda * 0x10 & 0x000FFFFF; // transform segment into linear address - - // search Extended BIOS Data Area for the Root System Description Pointer signature - for (auto addr = reinterpret_cast(ebda); reinterpret_cast(addr) < ebda + 1024; addr += 0x10 / sizeof(addr)){ - auto rsdp = check_rsd_ptr(addr); - if (rsdp){ - return rsdp; - } - } - - return nullptr; -} - -// checks for a given header and validates checksum -int check_header(unsigned int *ptr, const char* sig){ - if (std::equal_n(reinterpret_cast(ptr), sig, 4)){ - char *checkPtr = reinterpret_cast(ptr); - int len = *(ptr + 1); - char check = 0; - - while (0(ptr)); - - if(!paging::identity_map_pages(aligned_ptr, 2)){ - k_print_line("Impossible to identity map the ACPI tables"); - - return -1; - } - - // check if address is correct ( if acpi is available on this pc ) - if (ptr && check_header(ptr, "RSDT") == 0){ - // the RSDT contains an unknown number of pointers to acpi tables - int entrys = *(ptr + 1); - entrys = (entrys-36) /4; - ptr += 36/4; // skip header information - - while (0(*ptr), "FACP") == 0){ - entrys = -2; - - struct FACP* facp = reinterpret_cast(*ptr); - - if (check_header(reinterpret_cast(facp->DSDT), "DSDT") == 0){ - // search the \_S5 package in the DSDT - char *S5Addr = reinterpret_cast(facp->DSDT + 36); // skip header - int dsdtLength = *(reinterpret_cast(static_cast(facp->DSDT)+1)) - 36; - while (0 < dsdtLength--){ - if (std::equal_n(S5Addr, "_S5_", 4)){ - break; - } - - S5Addr++; - } - - // check if \_S5 was found - if (dsdtLength > 0){ - // check for valid AML structure - if ( ( *(S5Addr-1) == 0x08 || ( *(S5Addr-2) == 0x08 && *(S5Addr-1) == '\\') ) && *(S5Addr+4) == 0x12 ){ - S5Addr += 5; - S5Addr += ((*S5Addr &0xC0)>>6) +2; // calculate PkgLength size - - if (*S5Addr == 0x0A){ - S5Addr++; // skip byteprefix - } - - SLP_TYPa = *(S5Addr)<<10; - S5Addr++; - - if (*S5Addr == 0x0A){ - S5Addr++; // skip byteprefix - } - - SLP_TYPb = *(S5Addr)<<10; - - SMI_CMD = facp->SMI_CMD; - - ACPI_ENABLE = facp->ACPI_ENABLE; - ACPI_DISABLE = facp->ACPI_DISABLE; - - PM1a_CNT = facp->PM1a_CNT_BLK; - PM1b_CNT = facp->PM1b_CNT_BLK; - - PM1_CNT_LEN = facp->PM1_CNT_LEN; - - SLP_EN = 1<<13; - SCI_EN = 1; - - return 0; - } else { - k_print_line("\\_S5 parse error."); - } - } else { - k_print_line("\\_S5 not present."); - } - } else { - k_print_line("DSDT invalid."); - } - } - ptr++; - } - k_print_line("no valid FACP present."); - } else { - k_print_line("no acpi."); - } - - return -1; -} - void initialize_acpica(){ logging::logf(logging::log_level::DEBUG, "acpi:: Started initialization of ACPICA\n"); @@ -280,7 +64,7 @@ void initialize_acpica(){ auto status = AcpiInitializeSubsystem(); if(ACPI_FAILURE(status)){ - logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize subsystem: error: %u\n", size_t(status)); + logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); return; } @@ -288,7 +72,7 @@ void initialize_acpica(){ status = AcpiInitializeTables(nullptr, 16, FALSE); if (ACPI_FAILURE (status)){ - logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize tables: error: %u\n", size_t(status)); + logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); return; } @@ -296,7 +80,7 @@ void initialize_acpica(){ status = AcpiLoadTables (); if (ACPI_FAILURE (status)){ - logging::logf(logging::log_level::ERROR, "acpica: Impossible to load tables: error: %u\n", size_t(status)); + logging::logf(logging::log_level::ERROR, "acpica: Impossible to load tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); return; } @@ -304,7 +88,7 @@ void initialize_acpica(){ status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE (status)){ - logging::logf(logging::log_level::ERROR, "acpica: Impossible to enable subsystem: error: %u\n", size_t(status)); + logging::logf(logging::log_level::ERROR, "acpica: Impossible to enable subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); return; } @@ -312,7 +96,7 @@ void initialize_acpica(){ status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE (status)){ - logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize objects: error: %u\n", size_t(status)); + logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize objects: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); return; } @@ -329,20 +113,24 @@ void acpi::init(){ } void acpi::shutdown(){ - // SCI_EN is set to 1 if acpi shutdown is possible - if (SCI_EN == 0){ - return; - } + auto status = AcpiEnterSleepStatePrep(5); - acpiEnable(); + if(ACPI_FAILURE(status)){ + logging::logf(logging::log_level::ERROR, "acpica: Impossible to prepare sleep state: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); + return; + } - // send the shutdown command - out_word(PM1a_CNT, SLP_TYPa | SLP_EN ); - if ( PM1b_CNT != 0 ){ - out_word(PM1b_CNT, SLP_TYPb | SLP_EN ); - } + size_t rflags; + arch::disable_hwint(rflags); + status = AcpiEnterSleepState(5); - k_print_line("acpi poweroff failed."); + if(ACPI_FAILURE(status)){ + logging::logf(logging::log_level::ERROR, "acpica: Impossible to enter sleep state: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); + return; + } + + k_print_line("acpi poweroff failed."); + arch::enable_hwint(rflags); } bool acpi::initialized(){