diff --git a/kernel/include/acpi.hpp b/kernel/include/acpi.hpp index 9bd7127b..a4a895d5 100644 --- a/kernel/include/acpi.hpp +++ b/kernel/include/acpi.hpp @@ -11,10 +11,11 @@ namespace acpi { void init(); -void shutdown(); - bool initialized(); +void shutdown(); +bool reboot(); + } //end of acpi namespace #endif diff --git a/kernel/include/acpica.hpp b/kernel/include/acpica.hpp index 6c3fec1f..273495c1 100644 --- a/kernel/include/acpica.hpp +++ b/kernel/include/acpica.hpp @@ -18,10 +18,13 @@ extern "C" { #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-function" //TODO Does not work #include "acpi.h" +#include "accommon.h" #pragma GCC diagnostic pop } //end of extern "C" #include +constexpr const size_t FADT2_REVISION_ID = 3; + #endif diff --git a/kernel/src/acpi.cpp b/kernel/src/acpi.cpp index 936aa00e..f1153241 100644 --- a/kernel/src/acpi.cpp +++ b/kernel/src/acpi.cpp @@ -14,6 +14,7 @@ #include "logging.hpp" #include "scheduler.hpp" #include "arch.hpp" +#include "assert.hpp" namespace { @@ -105,6 +106,43 @@ void initialize_acpica(){ logging::logf(logging::log_level::DEBUG, "acpi:: Finished initialization of ACPICA\n"); } +uint64_t acpi_read(const ACPI_GENERIC_ADDRESS& address){ + if(address.SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY){ + UINT64 value = 0; + auto status = AcpiOsReadMemory(address.Address, &value, address.BitWidth); + if(ACPI_FAILURE(status)){ + logging::logf(logging::log_level::ERROR, "acpica: Unable to read from memory: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); + } + return value; + } else if(address.SpaceId == ACPI_ADR_SPACE_SYSTEM_IO){ + UINT32 value = 0; + auto status = AcpiHwReadPort(address.Address, &value, address.BitWidth); + if(ACPI_FAILURE(status)){ + logging::logf(logging::log_level::ERROR, "acpica: Unable to read from hardware port: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); + } + return value; + } else { + logging::logf(logging::log_level::ERROR, "acpica: Unimplemented read generic address space id\n"); + return 0; + } +} + +void acpi_write(const ACPI_GENERIC_ADDRESS& address, uint64_t value){ + if(address.SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY){ + auto status = AcpiOsWriteMemory(address.Address, value, address.BitWidth); + if(ACPI_FAILURE(status)){ + logging::logf(logging::log_level::ERROR, "acpica: Unable to write to memory: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); + } + } else if(address.SpaceId == ACPI_ADR_SPACE_SYSTEM_IO){ + auto status = AcpiHwWritePort(address.Address, value, address.BitWidth); + if(ACPI_FAILURE(status)){ + logging::logf(logging::log_level::ERROR, "acpica: Unable to write to hardware port: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name); + } + } else { + logging::logf(logging::log_level::ERROR, "acpica: Unimplemented write generic address space id\n"); + } +} + } //end of anonymous namespace void acpi::init(){ @@ -112,7 +150,13 @@ void acpi::init(){ scheduler::queue_async_init_task(initialize_acpica); } +bool acpi::initialized(){ + return acpi_initialized; +} + void acpi::shutdown(){ + thor_assert(acpi::initialized(), "ACPI must be initialized for acpi::shutdown()"); + auto status = AcpiEnterSleepStatePrep(5); if(ACPI_FAILURE(status)){ @@ -133,6 +177,19 @@ void acpi::shutdown(){ arch::enable_hwint(rflags); } -bool acpi::initialized(){ - return acpi_initialized; +bool acpi::reboot(){ + thor_assert(acpi::initialized(), "ACPI must be initialized for acpi::reboot()"); + + if (AcpiGbl_FADT.Header.Revision < FADT2_REVISION_ID){ + return false; + } + + if(!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER)){ + return false; + } + + auto reset_register = AcpiGbl_FADT.ResetRegister; + auto reset_value = AcpiGbl_FADT.ResetValue; + + acpi_write(reset_register, reset_value); } diff --git a/kernel/src/rtc.cpp b/kernel/src/rtc.cpp index 2b3abf6c..371898c2 100644 --- a/kernel/src/rtc.cpp +++ b/kernel/src/rtc.cpp @@ -13,8 +13,6 @@ namespace { -constexpr const size_t FADT2_REVISION_ID = 3; - #define CURRENT_YEAR 2013 #define cmos_address 0x70 #define cmos_data 0x71 diff --git a/kernel/src/system_calls.cpp b/kernel/src/system_calls.cpp index 865748f7..5d77237b 100644 --- a/kernel/src/system_calls.cpp +++ b/kernel/src/system_calls.cpp @@ -91,8 +91,10 @@ void sc_clear(interrupt::syscall_regs*){ } void sc_reboot(interrupt::syscall_regs*){ - //TODO Reboot should be done more properly - asm volatile("mov al, 0x64; or al, 0xFE; out 0x64, al; mov al, 0xFE; out 0x64, al; " : : ); + if(!acpi::initialized() || !acpi::reboot()){ + logging::logf(logging::log_level::ERROR, "ACPI reset not possible, fallback to 8042 reboot\n"); + asm volatile("mov al, 0x64; or al, 0xFE; out 0x64, al; mov al, 0xFE; out 0x64, al; " : : ); + } __builtin_unreachable(); }