diff --git a/kernel/include/kernel/ACPI/ACPI.h b/kernel/include/kernel/ACPI/ACPI.h index 06fc2811..1fd2f76e 100644 --- a/kernel/include/kernel/ACPI/ACPI.h +++ b/kernel/include/kernel/ACPI/ACPI.h @@ -22,6 +22,10 @@ namespace Kernel::ACPI // 2: SAPIC BAN::ErrorOr enter_acpi_mode(uint8_t mode); + // This function will power off the system + // This function will return only if there was an error + void poweroff(); + private: ACPI() = default; BAN::ErrorOr initialize_impl(); diff --git a/kernel/include/kernel/ACPI/AML/NamedObject.h b/kernel/include/kernel/ACPI/AML/NamedObject.h index 817ca152..a5de7e2f 100644 --- a/kernel/include/kernel/ACPI/AML/NamedObject.h +++ b/kernel/include/kernel/ACPI/AML/NamedObject.h @@ -22,6 +22,13 @@ namespace Kernel::ACPI::AML : NamedObject(Node::Type::Name, name), object(BAN::move(object)) {} + BAN::RefPtr evaluate() override + { + if (!object) + return {}; + return object->evaluate(); + } + static ParseResult parse(ParseContext& context); virtual void debug_print(int indent) const override; }; diff --git a/kernel/include/kernel/ACPI/AML/Package.h b/kernel/include/kernel/ACPI/AML/Package.h index 3aa1d2c4..6a10f577 100644 --- a/kernel/include/kernel/ACPI/AML/Package.h +++ b/kernel/include/kernel/ACPI/AML/Package.h @@ -14,6 +14,25 @@ namespace Kernel::ACPI::AML Package() : Node(Node::Type::Package) {} + BAN::RefPtr evaluate() override + { + BAN::Vector> evaluated_elements; + for (auto& element : elements) + { + auto evaluated = element->evaluate(); + if (!evaluated) + { + AML_ERROR("Failed to evaluate element in package"); + return {}; + } + evaluated_elements.push_back(evaluated); + } + + auto package = MUST(BAN::RefPtr::create()); + package->elements = BAN::move(evaluated_elements); + return package; + } + static ParseResult parse(AML::ParseContext& context) { ASSERT(context.aml_data.size() >= 1); diff --git a/kernel/kernel/ACPI/ACPI.cpp b/kernel/kernel/ACPI/ACPI.cpp index 86bf9d64..5ef6d6fc 100644 --- a/kernel/kernel/ACPI/ACPI.cpp +++ b/kernel/kernel/ACPI/ACPI.cpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #include #include @@ -252,6 +254,75 @@ namespace Kernel::ACPI return nullptr; } + void ACPI::poweroff() + { + if (!m_namespace) + { + dwarnln("ACPI namespace not initialized"); + return; + } + + auto s5_object = m_namespace->find_object({}, AML::NameString("\\_S5")); + if (!s5_object) + { + dwarnln("\\_S5 not found"); + return; + } + auto s5_evaluated = s5_object->evaluate(); + if (!s5_evaluated) + { + dwarnln("Failed to evaluate \\_S5"); + return; + } + if (s5_evaluated->type != AML::Node::Type::Package) + { + dwarnln("\\_S5 is not a package"); + return; + } + auto* s5_package = static_cast(s5_evaluated.ptr()); + if (s5_package->elements.size() != 4) + { + dwarnln("\\_S5 package has {} elements, expected 4", s5_package->elements.size()); + return; + } + + auto pts_object = m_namespace->find_object({}, AML::NameString("\\_PTS")); + if (pts_object && pts_object->type == AML::Node::Type::Method) + { + auto* method = static_cast(pts_object.ptr()); + if (method->arg_count != 1) + { + dwarnln("Method \\_PTS has {} arguments, expected 1", method->arg_count); + return; + } + + AML::Method::Arguments args; + args[0] = MUST(BAN::RefPtr::create(MUST(BAN::RefPtr::create(5)))); + if (!method->evaluate(args).has_value()) + { + dwarnln("Failed to evaluate \\_PTS"); + return; + } + + dprintln("Executed \\_PTS"); + } + + auto* fadt = static_cast(get_header("FACP", 0)); + + uint16_t SLP_EN = 1 << 13; + uint16_t PM1a_CNT = fadt->pm1a_cnt_blk; + uint16_t PM1b_CNT = fadt->pm1b_cnt_blk; + + uint32_t SLP_TYPa = s5_package->elements[0]; + uint32_t SLP_TYPb = s5_package->elements[1]; + + dprintln("Entering sleep state S5"); + + IO::outw(PM1a_CNT, SLP_TYPa | SLP_EN); + if (PM1b_CNT != 0) + IO::outw(PM1b_CNT, SLP_TYPb | SLP_EN); + } + BAN::ErrorOr ACPI::enter_acpi_mode(uint8_t mode) { if (!m_namespace)