ACPI Initialization in Loader with Lua Bindings
Student: KaylaPowell (kpowkitty@FreeBSD.org)
Mentor: WarnerLosh (imp@FreeBSD.org)
Project Description
Intel™’s Advanced Configuration and Power Interface (ACPI) is an industry standard specification that revolutionized power management in computers by putting it in the hands of the operating system, rather than the BIOS. As it currently stands, it is widely available across 32-bit and 64-bit architectures, with specially tailored manuals towards Windows™ and UNIX™.
FreeBSD has implemented ACPI, utilizing Intel™’s ACPI Computer Architecture (ACPICA). To make it more manipulable, the goal of this project is to enumerate the ACPI namespace into Lua bindings. But, in order to have that, the namespace needs to be initialized in the loader, before the kernel. Therefore, the first major milestone of this project is to refactor ACPI’s initialization routines into the loader. The finality of this project is to have the ACPI namespace enumerated into a human readable api layer in Lua.
While the major benefit of this project is the scriptability of ACPI, the loader will benefit in other ways, such as reduced ACPI guesswork. Future goals of this project are to continue fleshing out ACPI branches into Lua until it is as scriptable as possible.
Approach to Solving the Problem
DESIGN CONTINGENCIES
Loader should remain as lightweight as possible
- Since we are only using EFI, it is able to handle the ACPI initialization routines.
- ACPICA does not need to be fully integrated into the loader, as the kernel can handle the rest. We just need the ACPI namespace and the AML interpreter, so we can pass the namespace to Lua and then use the AML to interpret changes.
SOLUTION:
Supply the loader with only the necessary ACPI initialization functions so we can:
- Walk the ACPI namespace
- Have the AML interpreter
ACPI is not required for all FreeBSD use cases, nor is it generic for all architectures
- The ACPI tables will need to be mapped conditionally for amd64 and arm64.
- FreeBSD provides loader scripting routines that should not include ACPI (i.e., should not be affected by this project).
SOLUTION:
Conditional compilation with preprocessor macros will guide mapping memory tables per architecture:
- amd64 —→ x86 64bit
- aarch64 —→ arm 64bit
ACPI will not be included in Simple or Forth
Lua Bindings
In order to script ACPI, we will need to pass the ACPI namespace to Lua.
SOLUTION:
Walk the ACPI namespace and generate Lua bindings with user-friendly API layer
ACPI INITIALIZATION FUNCTIONS
- ACPI_STATUS acpi_startup (void)
- int acpi_identify (void)
- ACPI_STATUS ACPI_INIT_FUNCTION
AcpiInitializeTables (ACPI_TABLE_DESC *InitialTableArray, UINT32 InitialTableCount, BOOLEAN AllowResize)
ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeSubsystem (void)
ACPI_STATUS ACPI_INIT FUNCTION AcpiEnableSubsystem (UINT32
- Flags)
ACPI_STATUS ACPI_INIT_FUNCTION AcpiInitializeObjects (UINT32
- Flags)
ACPI_STATUS ACPI_INIT_FUNCTION AcpiTbParseRootTable (void)
FINAL IMPLEMENTATION
stand/efi/acpica/Osd/OsdMemory.c (split off from kernel/refactored)
stand/efi/loader/arch/amd64
stand/efi/loader/arch/arm64
stand/liblua/lutils.c (ACPI namespace/bindings included)
C FUNCTIONS PUSHED TO LUA STACK
- walk_ACPI_namespace()
- ACPI_callback()
- display_ACPI_namespace()
- ACPI_evaluate_object()
LUA BINDINGS AND WRAPPERS FOR TESTING/DEMONSTRATION
- get_device_ID()
- disable_device()
- eject_device()
- lock_device()
- device_status()
- set_brightness()
- increase_brightness()
- query_brightness()
- turn_display_off()
- decrease_brightness()
Deliverables
ACPICA Osd functions selectively provided to the bootloader in /stand/efi/acpica/Osd/
- acpi_Startup() and acpi_identify() need:
AcpiInitializeSubsystem()
AcpiIntializeTables()
AcpiOsGetRootPointer()
AcpiEnableSubsystem()
AcpiInitializeObjects()
AcpiOsMapMemory()
AcpiOsUnmapMemory()
- acpi_Startup() and acpi_identify() need:
Initialization of ACPI per /stand/efi/loader/arch/$ARCH
- Parse the ACPI namespace into a human-readable API Layer
- ACPI API layer in Lua interpreter
- Lua bindings
- Updated FreeBSD ACPI man page and handbook with new Lua ACPI API documentation
Milestones
Week 1: June 2nd - 6th
MILESTONE 1:
- stand/efi/acpica/Osd/
Week 3: June 16th - 20th
MILESTONE 2:
- stand/efi/loader/arch/amd64
Week 5: June 30th - July 4th
MILESTONE 3:
- stand/efi/loader/arch/arm64
Week 6: July 7th - 11th
MILESTONE 4:
- ACPI Initialization Integration
Week 7: July 14th - 18th
GSOC MIDTERM EVALUATION: ACPI initialized in the loader
Week 9: Planned Absence for Plant Biology 2025
Week 10: Aug 4th - 8th
MILESTONE 5:
- ACPI Enumerated in C
Week 11: Aug 11th - 15th
MILESTONE 6:
- ACPI API layer
Week 13: Aug 25th - 29th
MILESTONE 7:
- Lua bindings
Week 14: Sept 1st - 5th
GSOC FINAL EVALUATION: ACPI Lua bindings
Test Plan
The first major milestone is getting ACPI initialized in the loader rather than the kernel. In order to do this, I will need to implement the necessary ACPI startup routines. sys/dev/acpica/acpi.c,where the current ACPI startup routines live, will be refactored for this purpose, and a useful reference. Once we have them in the loader, we need to test to confirm that the tables are (1) loaded and (2) accessible to the kernel later.
ACPI in Loader - Architecture Specific Testing
This will be piecemeal. I will implement ACPI initialization for each architecture, each on different branches. This way, I can test each implementation on each architecture with VMs. Also, when I go to integrate them together, I will know it is an integration problem.
Lua Routines
This battle will be getting the namespace enumerated into Lua table(s). AcpiWalkNamespace() allows traversing the ACPI namespace, whereby it can populate our table using a callback function.
- The first test will be making sure our callback function is parsing the nodes correctly.
- The second test will be making sure the Lua stack is receiving the nodes correctly.
- The last test is sending information back to ACPI through the C API.
Unit testing will confirm…
C
- That ACPI is initialized in the loader
- That both architectures work independently of each other
- That we can walk the ACPI namespace
- That we can alter ACPI’s state (without Lua and with Lua)
Lua
- That we have successfully passed information to Lua through the stack
- That we have successfully passed information back to C through the stack
Regression testing will occur…
C
- Once amd64’s ACPI is initialized in the loader.
- Once arm64’s ACPI is initialized in the loader.
- Once both architecture specifications are integrated into the system.
Lua
- Once we are fully communicating ACPI namespace through the Lua stack, we can perform regression tests to ensure that the Lua scripts are properly altering ACPI in comparison to previous ACPI alterations when it was in the kernel.
The Code
Code |
Notes
Write-up |
Useful Links
ACPI
Using and Debugging FreeBSD ACPI
Linux’s ACPI Device Tree - Representation of ACPI Namespace
STYLE
LUA