mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-23 11:46:27 -04:00
Use ACPICA directly for shutdown
This commit is contained in:
parent
b5a6966b7f
commit
b762345c49
@ -13,266 +13,50 @@
|
|||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "logging.hpp"
|
#include "logging.hpp"
|
||||||
#include "scheduler.hpp"
|
#include "scheduler.hpp"
|
||||||
|
#include "arch.hpp"
|
||||||
|
|
||||||
namespace {
|
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;
|
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<RSDPtr*>(ptr);
|
|
||||||
|
|
||||||
if (std::equal_n(sig, reinterpret_cast<const char*>(rsdp), 8)){
|
|
||||||
uint8_t check = 0;
|
|
||||||
|
|
||||||
// check checksum rsdpd
|
|
||||||
auto bptr = reinterpret_cast<uint8_t*>(ptr);
|
|
||||||
for (size_t i=0; i<sizeof(struct RSDPtr); i++){
|
|
||||||
check += *bptr;
|
|
||||||
bptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// found valid rsdpd
|
|
||||||
if (check == 0) {
|
|
||||||
version_2 = rsdp->Revision != 0;
|
|
||||||
|
|
||||||
return reinterpret_cast<unsigned int *>(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<unsigned int*>(0x000E0000); reinterpret_cast<uintptr_t>(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<short *>(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<unsigned int*>(ebda); reinterpret_cast<uintptr_t>(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<const char*>(ptr), sig, 4)){
|
|
||||||
char *checkPtr = reinterpret_cast<char *>(ptr);
|
|
||||||
int len = *(ptr + 1);
|
|
||||||
char check = 0;
|
|
||||||
|
|
||||||
while (0<len--){
|
|
||||||
check += *checkPtr;
|
|
||||||
checkPtr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check == 0){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int acpiEnable(void){
|
|
||||||
// check if acpi is enabled
|
|
||||||
if ( (in_word(PM1a_CNT) &SCI_EN) == 0 ){
|
|
||||||
// check if acpi can be enabled
|
|
||||||
if (SMI_CMD != 0 && ACPI_ENABLE != 0){
|
|
||||||
out_byte(SMI_CMD, ACPI_ENABLE); // send acpi enable command
|
|
||||||
// give 3 seconds time to enable acpi
|
|
||||||
int i;
|
|
||||||
for (i=0; i<300; i++ ){
|
|
||||||
if ( (in_word(PM1a_CNT) & SCI_EN) == 1 )
|
|
||||||
break;
|
|
||||||
timer::sleep_ms(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PM1b_CNT != 0)
|
|
||||||
for (; i<300; i++ )
|
|
||||||
{
|
|
||||||
if ( (in_word(PM1b_CNT) & SCI_EN) == 1 )
|
|
||||||
break;
|
|
||||||
timer::sleep_ms(10);
|
|
||||||
}
|
|
||||||
if (i<300) {
|
|
||||||
k_print_line("ACPI enabled");
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
k_print_line("Couldn't enable ACPI");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
k_print_line("No known way to enable ACPI");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
k_print_line("ACPI was already enabled");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// bytecode of the \_S5 object
|
|
||||||
// -----------------------------------------
|
|
||||||
// | (optional) | | | |
|
|
||||||
// NameOP | \ | _ | S | 5 | _
|
|
||||||
// 08 | 5A | 5F | 53 | 35 | 5F
|
|
||||||
//
|
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
|
||||||
// | | | ( SLP_TYPa ) | ( SLP_TYPb ) | ( Reserved ) | (Reserved )
|
|
||||||
// PackageOP | PkgLength | NumElements | byteprefix Num | byteprefix Num | byteprefix Num | byteprefix Num
|
|
||||||
// 12 | 0A | 04 | 0A 05 | 0A 05 | 0A 05 | 0A 05
|
|
||||||
//
|
|
||||||
//----this-structure-was-also-seen----------------------
|
|
||||||
// PackageOP | PkgLength | NumElements |
|
|
||||||
// 12 | 06 | 04 | 00 00 00 00
|
|
||||||
//
|
|
||||||
// (Pkglength bit 6-7 encode additional PkgLength bytes [shouldn't be the case here])
|
|
||||||
//
|
|
||||||
int init_acpi(){
|
|
||||||
unsigned int *ptr = get_rsd_ptr();
|
|
||||||
|
|
||||||
auto aligned_ptr = paging::page_align(reinterpret_cast<uintptr_t>(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<entrys--){
|
|
||||||
// check if the desired table is reached
|
|
||||||
if (check_header(reinterpret_cast<unsigned int*>(*ptr), "FACP") == 0){
|
|
||||||
entrys = -2;
|
|
||||||
|
|
||||||
struct FACP* facp = reinterpret_cast<FACP*>(*ptr);
|
|
||||||
|
|
||||||
if (check_header(reinterpret_cast<unsigned int*>(facp->DSDT), "DSDT") == 0){
|
|
||||||
// search the \_S5 package in the DSDT
|
|
||||||
char *S5Addr = reinterpret_cast<char *>(facp->DSDT + 36); // skip header
|
|
||||||
int dsdtLength = *(reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(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(){
|
void initialize_acpica(){
|
||||||
logging::logf(logging::log_level::DEBUG, "acpi:: Started initialization of ACPICA\n");
|
logging::logf(logging::log_level::DEBUG, "acpi:: Started initialization of ACPICA\n");
|
||||||
|
|
||||||
@ -280,7 +64,7 @@ void initialize_acpica(){
|
|||||||
|
|
||||||
auto status = AcpiInitializeSubsystem();
|
auto status = AcpiInitializeSubsystem();
|
||||||
if(ACPI_FAILURE(status)){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +72,7 @@ void initialize_acpica(){
|
|||||||
|
|
||||||
status = AcpiInitializeTables(nullptr, 16, FALSE);
|
status = AcpiInitializeTables(nullptr, 16, FALSE);
|
||||||
if (ACPI_FAILURE (status)){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +80,7 @@ void initialize_acpica(){
|
|||||||
|
|
||||||
status = AcpiLoadTables ();
|
status = AcpiLoadTables ();
|
||||||
if (ACPI_FAILURE (status)){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +88,7 @@ void initialize_acpica(){
|
|||||||
|
|
||||||
status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
|
status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
|
||||||
if (ACPI_FAILURE (status)){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +96,7 @@ void initialize_acpica(){
|
|||||||
|
|
||||||
status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
|
status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
|
||||||
if (ACPI_FAILURE (status)){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,20 +113,24 @@ void acpi::init(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void acpi::shutdown(){
|
void acpi::shutdown(){
|
||||||
// SCI_EN is set to 1 if acpi shutdown is possible
|
auto status = AcpiEnterSleepStatePrep(5);
|
||||||
if (SCI_EN == 0){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
size_t rflags;
|
||||||
out_word(PM1a_CNT, SLP_TYPa | SLP_EN );
|
arch::disable_hwint(rflags);
|
||||||
if ( PM1b_CNT != 0 ){
|
status = AcpiEnterSleepState(5);
|
||||||
out_word(PM1b_CNT, SLP_TYPb | SLP_EN );
|
|
||||||
}
|
|
||||||
|
|
||||||
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(){
|
bool acpi::initialized(){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user