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

@@ -17,6 +17,64 @@
namespace Kernel::ACPI
{
static uint32_t* s_global_lock { nullptr };
// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#global-lock
asm(R"(
.global acpi_acquire_global_lock
acpi_acquire_global_lock:
movl (%rdi), %edx
andl $(~1), %edx
btsl $1, %edx
adcl $0, %edx
lock cmpxchgl %edx, (%rdi)
jnz acpi_acquire_global_lock
cmpb $3, %dl
sbbq %rax, %rax
negq %rax
ret
.global acpi_release_global_lock
acpi_release_global_lock:
movl (%rdi), %eax
movl %eax, %edx
andl $(~3), %edx
lock cmpxchgl %edx, (%rdi)
jnz acpi_release_global_lock
andq $1, %rax
ret
)");
// returns true if lock was acquired successfully
extern "C" bool acpi_acquire_global_lock(uint32_t* lock);
// returns true if lock was pending
extern "C" bool acpi_release_global_lock(uint32_t* lock);
void ACPI::acquire_global_lock()
{
if (!s_global_lock)
return;
derrorln("Acquiring ACPI global lock");
ASSERT(acpi_acquire_global_lock(s_global_lock));
}
void ACPI::release_global_lock()
{
if (!s_global_lock)
return;
derrorln("Releasing ACPI global lock");
ASSERT(!acpi_release_global_lock(s_global_lock));
}
enum PM1Event : uint16_t
{
PM1_EVN_TMR_EN = 1 << 0,
@@ -58,6 +116,22 @@ namespace Kernel::ACPI
return BAN::Error::from_errno(ENOMEM);
TRY(s_instance->initialize_impl());
{
ASSERT(!s_global_lock);
const auto* fadt = static_cast<const FADT*>(ACPI::get().get_header("FACP"sv, 0));
ASSERT(fadt);
uintptr_t facs_addr = fadt->firmware_ctrl;
if (fadt->length >= sizeof(FADT) && fadt->x_firmware_ctrl)
facs_addr = fadt->x_firmware_ctrl;
if (facs_addr)
{
auto* facs = reinterpret_cast<FACS*>(facs_addr);
s_global_lock = &facs->global_lock;
}
}
s_instance->m_namespace = AML::initialize_namespace();
return {};
@@ -318,7 +392,8 @@ namespace Kernel::ACPI
AML::Method::Arguments args;
args[0] = MUST(BAN::RefPtr<AML::Register>::create(MUST(BAN::RefPtr<AML::Integer>::create(5))));
if (!method->evaluate(args).has_value())
BAN::Vector<uint8_t> sync_stack;
if (!method->evaluate(args, sync_stack).has_value())
{
dwarnln("Failed to evaluate \\_PTS");
return;
@@ -397,7 +472,8 @@ namespace Kernel::ACPI
dwarnln("Method \\_SB._INI has {} arguments, expected 0", method->arg_count);
return BAN::Error::from_errno(EINVAL);
}
method->evaluate({});
BAN::Vector<uint8_t> sync_stack;
method->evaluate({}, sync_stack);
}
// Initialize devices
@@ -423,7 +499,8 @@ namespace Kernel::ACPI
AML::Method::Arguments args;
args[0] = MUST(BAN::RefPtr<AML::Register>::create(MUST(BAN::RefPtr<AML::Integer>::create(mode))));
method->evaluate(args);
BAN::Vector<uint8_t> sync_stack;
method->evaluate(args, sync_stack);
}
dprintln("Devices are initialized");

View File

@@ -21,7 +21,8 @@ namespace Kernel::ACPI
AML_ERROR("Method {}._STA has {} arguments, expected 0", scope, method->arg_count);
return false;
}
auto result = method->evaluate({});
BAN::Vector<uint8_t> sync_stack;
auto result = method->evaluate({}, sync_stack);
if (!result.has_value())
{
AML_ERROR("Failed to evaluate {}._STA", scope);
@@ -55,7 +56,8 @@ namespace Kernel::ACPI
AML_ERROR("Method {}._INI has {} arguments, expected 0", scope, method->arg_count);
return false;
}
method->evaluate({});
BAN::Vector<uint8_t> sync_stack;
method->evaluate({}, sync_stack);
}
}

View File

@@ -1,4 +1,5 @@
#include <BAN/ScopeGuard.h>
#include <kernel/ACPI/ACPI.h>
#include <kernel/ACPI/AML/Field.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/IO.h>
@@ -436,10 +437,10 @@ namespace Kernel::ACPI
}
if (access_rules.lock_rule == FieldRules::LockRule::Lock)
Namespace::root_namespace()->global_lock.lock();
ACPI::acquire_global_lock();
BAN::ScopeGuard unlock_guard([&] {
if (access_rules.lock_rule == FieldRules::LockRule::Lock)
Namespace::root_namespace()->global_lock.unlock();
ACPI::release_global_lock();
});
return store_internal(source_integer.value());
@@ -539,10 +540,10 @@ namespace Kernel::ACPI
};
if (access_rules.lock_rule == FieldRules::LockRule::Lock)
Namespace::root_namespace()->global_lock.lock();
ACPI::acquire_global_lock();
BAN::ScopeGuard unlock_guard([&] {
if (access_rules.lock_rule == FieldRules::LockRule::Lock)
Namespace::root_namespace()->global_lock.unlock();
ACPI::release_global_lock();
});
auto result = perform_read_general(0, bit_count, bit_offset, access_size.value(), read_func);
@@ -582,10 +583,10 @@ namespace Kernel::ACPI
};
if (access_rules.lock_rule == FieldRules::LockRule::Lock)
Namespace::root_namespace()->global_lock.lock();
ACPI::acquire_global_lock();
BAN::ScopeGuard unlock_guard([&] {
if (access_rules.lock_rule == FieldRules::LockRule::Lock)
Namespace::root_namespace()->global_lock.unlock();
ACPI::release_global_lock();
});
if (!perform_write_general(0, bit_count, bit_offset, access_size.value(), source_integer.value(), access_rules.update_rule, read_func, write_func))

View File

@@ -56,6 +56,8 @@ namespace Kernel::ACPI
case AML::ExtOp::DeviceOp:
return AML::Device::parse(context);
case AML::ExtOp::MutexOp:
case AML::ExtOp::AcquireOp:
case AML::ExtOp::ReleaseOp:
return AML::Mutex::parse(context);
case AML::ExtOp::ProcessorOp:
return AML::Processor::parse(context);
@@ -183,7 +185,7 @@ namespace Kernel::ACPI
args[i] = MUST(BAN::RefPtr<AML::Register>::create(arg.node()));
}
auto result = method->evaluate(args, context.sync_level);
auto result = method->evaluate(args, context.sync_stack);
if (!result.has_value())
{
AML_ERROR("Failed to evaluate {}", name_string.value());