forked from Bananymous/banan-os
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:
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user