Kernel: Implement locking for AML

Now global lock uses the actual global lock. Currenly if no lock
can be acquired, we just panic the kernel so that I remember to
implement it properly once AML is running concurrently.
This commit is contained in:
2024-04-11 00:19:14 +03:00
parent 0184e5beb5
commit 93ddee5956
10 changed files with 240 additions and 24 deletions

View File

@@ -14,6 +14,9 @@ namespace Kernel::ACPI
static BAN::ErrorOr<void> initialize();
static ACPI& get();
static void acquire_global_lock();
static void release_global_lock();
const SDTHeader* get_header(BAN::StringView signature, uint32_t index);
// mode

View File

@@ -69,20 +69,26 @@ namespace Kernel::ACPI::AML
return ParseResult::Success;
}
BAN::Optional<BAN::RefPtr<AML::Node>> evaluate(Arguments args, uint8_t old_sync_level = 0)
BAN::Optional<BAN::RefPtr<AML::Node>> evaluate(Arguments args, BAN::Vector<uint8_t>& current_sync_stack)
{
if (serialized && !current_sync_stack.empty() && sync_level < current_sync_stack.back())
{
AML_ERROR("Trying to evaluate method {} with lower sync level than current sync level", scope);
return {};
}
ParseContext context;
context.aml_data = term_list;
context.scope = scope;
context.method_args = args;
context.sync_level = old_sync_level;
context.sync_stack = BAN::move(current_sync_stack);
for (auto& local : context.method_locals)
local = MUST(BAN::RefPtr<AML::Register>::create());
if (serialized)
{
mutex.lock();
context.sync_level = BAN::Math::max(sync_level, old_sync_level);
MUST(context.sync_stack.push_back(sync_level));
}
BAN::Optional<BAN::RefPtr<AML::Node>> return_value;
@@ -108,7 +114,12 @@ namespace Kernel::ACPI::AML
}
if (serialized)
{
context.sync_stack.pop_back();
mutex.unlock();
}
current_sync_stack = BAN::move(context.sync_stack);
return return_value;
}

View File

@@ -1,14 +1,18 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Timer/Timer.h>
namespace Kernel::ACPI::AML
{
struct Mutex : public AML::NamedObject
{
Kernel::Mutex mutex;
uint8_t sync_level;
Mutex(NameSeg name, uint8_t sync_level)
@@ -17,6 +21,33 @@ namespace Kernel::ACPI::AML
{}
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
switch (static_cast<AML::ExtOp>(context.aml_data[1]))
{
case AML::ExtOp::MutexOp:
return parse_mutex(context);
case AML::ExtOp::AcquireOp:
return parse_acquire(context);
case AML::ExtOp::ReleaseOp:
return parse_release(context);
default:
ASSERT_NOT_REACHED();
}
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("Mutex ");
name.debug_print();
AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level);
}
private:
static ParseResult parse_mutex(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
@@ -50,13 +81,86 @@ namespace Kernel::ACPI::AML
return ParseResult::Success;
}
virtual void debug_print(int indent) const override
static ParseResult parse_acquire(ParseContext& context)
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("Mutex ");
name.debug_print();
AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level);
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::AcquireOp);
context.aml_data = context.aml_data.slice(2);
auto mutex_result = AML::parse_object(context);
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
{
AML_ERROR("Acquire does not name a valid mutex");
return ParseResult::Failure;
}
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
if (mutex->sync_level < context.sync_level())
{
AML_ERROR("Trying to acquire mutex with lower sync level than current sync level");
return ParseResult::Failure;
}
if (context.aml_data.size() < 2)
{
AML_ERROR("Missing timeout value");
return ParseResult::Failure;
}
uint16_t timeout = context.aml_data[0] | (context.aml_data[1] << 8);
context.aml_data = context.aml_data.slice(2);
if (timeout >= 0xFFFF)
mutex->mutex.lock();
else
{
// FIXME: This is a very inefficient way to wait for a mutex
uint64_t wake_time = SystemTimer::get().ms_since_boot() + timeout;
while (!mutex->mutex.try_lock())
{
if (SystemTimer::get().ms_since_boot() >= wake_time)
return ParseResult(MUST(BAN::RefPtr<AML::Integer>::create(AML::Integer::Ones)));
SystemTimer::get().sleep(1);
}
}
MUST(context.sync_stack.push_back(mutex->sync_level));
return ParseResult(MUST(BAN::RefPtr<AML::Integer>::create(0)));
}
static ParseResult parse_release(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ReleaseOp);
context.aml_data = context.aml_data.slice(2);
auto mutex_result = AML::parse_object(context);
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
{
AML_ERROR("Release does not name a valid mutex");
return ParseResult::Failure;
}
if (context.sync_stack.empty())
{
AML_ERROR("Trying to release mutex without having acquired it");
return ParseResult::Failure;
}
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
if (mutex->sync_level != context.sync_level())
{
AML_ERROR("Trying to release mutex with different sync level than current sync level");
return ParseResult::Failure;
}
mutex->mutex.unlock();
context.sync_stack.pop_back();
return ParseResult::Success;
}
};
}

View File

@@ -9,8 +9,6 @@ namespace Kernel::ACPI::AML
struct Namespace : public AML::Scope
{
Mutex global_lock;
static BAN::RefPtr<AML::Namespace> root_namespace();
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}

View File

@@ -20,7 +20,9 @@ namespace Kernel::ACPI::AML
// we don't really need large contiguous memory
BAN::LinkedList<AML::NameString> created_objects;
uint8_t sync_level { 0 };
uint8_t sync_level() const { return !sync_stack.empty() ? sync_stack.back() : 0; }
BAN::Vector<uint8_t> sync_stack;
BAN::Array<BAN::RefPtr<Register>, 7> method_args;
BAN::Array<BAN::RefPtr<Register>, 8> method_locals;
};

View File

@@ -71,7 +71,7 @@ namespace Kernel::ACPI
uint8_t reset_value;
uint16_t arm_boot_arch;
uint8_t fadt_minor_version;
uint64_t x_firmware_version;
uint64_t x_firmware_ctrl;
uint64_t x_dsdt;
uint8_t x_pm1a_evt_blk[12];
uint8_t x_pm1b_evt_blk[12];
@@ -100,6 +100,22 @@ namespace Kernel::ACPI
uint8_t page_protection_and_oem_attribute;
} __attribute__((packed));
struct FACS
{
uint8_t signature[4];
uint32_t length;
uint32_t hardware_signature;
uint32_t firmware_waking_vector;
uint32_t global_lock;
uint32_t flags;
uint64_t x_firmware_waking_vector;
uint8_t version;
uint8_t reserved[3];
uint32_t ospm_flags;
uint8_t reserved2[24];
};
static_assert(sizeof(FACS) == 64);
}
namespace BAN::Formatter