From b5d71ae63f66c89022781d01b9aeebc1a5746798 Mon Sep 17 00:00:00 2001 From: kpowkitty Date: Sun, 31 Aug 2025 15:27:50 -0700 Subject: [PATCH 1/5] efi: create libacpi Description: Refactored ACPICA for partial initialization in the loader. This work is the final preface for Lua bindings. Work on this commit involves: Subset ACPICA for loader land: For our Lua bindings, we need to be able to walk the ACPI namespace and evaluate objects. To do so, we need AcpiInitializeSubsystem, AcpiInitializeTables, AcpiEnableSubsystem, and AcpiLoadTables. Notes: -acpi_detect() moved into libacpi. -Libacpi conditionally compiles ACPICA and glue code on amd64. (arm64 will be addressed in a future update) -AcpiEnableSubsystem is initialized in reduced hardware mode, but with events enabled. This is so that we do not need to pull in all of ACPI_HARDWARE, but can evaluate objects. -Stubbed out Osd functions required for this limited initialization. -Conditionally exclude functions to make a minimal subset designed around loader's/lua binding's needs: --Exclude AcpiInitializeObjects, as we do not need this for walking the namespace and evaluating objects. (utxfinit.c) --Exclude notify handlers or fixed event handlers. (evxface.c) --Stub out print functions, as the loader does not have standard output. (osunixxf.c) --Stub out AcpiOsSleep and AcpiOsGetTimer, as the loader is not multi-threaded and does not implement timers. (osunixxf.c) --- stand/efi/Makefile | 2 + .../os_specific/service_layers/osunixxf.c | 1526 +++++++++++++++++ stand/efi/libacpi/Makefile | 60 + stand/efi/libacpi/acpi/amd64/Osd/OsdMemory.c | 64 + stand/efi/libacpi/acpi/include/init_acpi.h | 40 + stand/efi/libacpi/acpi/init_acpi.c | 132 ++ stand/efi/libacpi/acpi_detect.c | 69 + stand/efi/libacpi/acpi_detect.h | 41 + stand/efi/libacpi32/Makefile | 4 + stand/efi/loader/Makefile | 17 +- stand/efi/loader/main.c | 55 +- .../dev/acpica/components/events/evxface.c | 6 +- .../dev/acpica/components/hardware/hwxface.c | 4 +- .../acpica/components/utilities/utdelete.c | 2 + .../dev/acpica/components/utilities/utinit.c | 2 +- .../acpica/components/utilities/utxfinit.c | 3 + sys/contrib/dev/acpica/include/accommon.h | 3 + 17 files changed, 1982 insertions(+), 48 deletions(-) create mode 100644 stand/efi/contrib/dev/acpica/os_specific/service_layers/osunixxf.c create mode 100644 stand/efi/libacpi/Makefile create mode 100644 stand/efi/libacpi/acpi/amd64/Osd/OsdMemory.c create mode 100644 stand/efi/libacpi/acpi/include/init_acpi.h create mode 100644 stand/efi/libacpi/acpi/init_acpi.c create mode 100644 stand/efi/libacpi/acpi_detect.c create mode 100644 stand/efi/libacpi/acpi_detect.h create mode 100644 stand/efi/libacpi32/Makefile diff --git a/stand/efi/Makefile b/stand/efi/Makefile index 1887b9536a5b5f..6147d2d7734bcb 100644 --- a/stand/efi/Makefile +++ b/stand/efi/Makefile @@ -5,6 +5,8 @@ NO_OBJ=t SUBDIR.yes+= libefi SUBDIR.${MK_LOADER_IA32}+= libefi32 SUBDIR.${MK_FDT}+= fdt +SUBDIR.yes+= libacpi +SUBDIR.${MK_LOADER_IA32}+= libacpi32 SUBDIR.yes+= .WAIT SUBDIR.yes+= boot1 gptboot diff --git a/stand/efi/contrib/dev/acpica/os_specific/service_layers/osunixxf.c b/stand/efi/contrib/dev/acpica/os_specific/service_layers/osunixxf.c new file mode 100644 index 00000000000000..ec32a29064ff26 --- /dev/null +++ b/stand/efi/contrib/dev/acpica/os_specific/service_layers/osunixxf.c @@ -0,0 +1,1526 @@ +/****************************************************************************** + * + * Module Name: osunixxf - UNIX OSL interfaces + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#include +#include + +/* + * These interfaces are required in order to compile the ASL compiler and the + * various ACPICA tools under Linux or other Unix-like system. + */ +#include +#include +#include +#include +#include + +#define _COMPONENT ACPI_OS_SERVICES + ACPI_MODULE_NAME ("osunixxf") + +/* Upcalls to AcpiExec */ + +void +AeTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable); + +typedef void* (*PTHREAD_CALLBACK) (void *); + +/* Buffer used by AcpiOsVprintf */ + +#define ACPI_VPRINTF_BUFFER_SIZE 512 +#define _ASCII_NEWLINE '\n' + +/* Terminal support for AcpiExec only */ + +#ifdef ACPI_EXEC_APP +#include + +struct termios OriginalTermAttributes; +int TermAttributesWereSet = 0; + +ACPI_STATUS +AcpiUtReadLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead); + +static void +OsEnterLineEditMode ( + void); + +static void +OsExitLineEditMode ( + void); + + +/****************************************************************************** + * + * FUNCTION: OsEnterLineEditMode, OsExitLineEditMode + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Enter/Exit the raw character input mode for the terminal. + * + * Interactive line-editing support for the AML debugger. Used with the + * common/acgetline module. + * + * readline() is not used because of non-portability. It is not available + * on all systems, and if it is, often the package must be manually installed. + * + * Therefore, we use the POSIX tcgetattr/tcsetattr and do the minimal line + * editing that we need in AcpiOsGetLine. + * + * If the POSIX tcgetattr/tcsetattr interfaces are unavailable, these + * calls will also work: + * For OsEnterLineEditMode: system ("stty cbreak -echo") + * For OsExitLineEditMode: system ("stty cooked echo") + * + *****************************************************************************/ + +static void +OsEnterLineEditMode ( + void) +{ + struct termios LocalTermAttributes; + + + TermAttributesWereSet = 0; + + /* STDIN must be a terminal */ + + if (!isatty (STDIN_FILENO)) + { + return; + } + + /* Get and keep the original attributes */ + + if (tcgetattr (STDIN_FILENO, &OriginalTermAttributes)) + { + fprintf (stderr, "Could not get terminal attributes!\n"); + return; + } + + /* Set the new attributes to enable raw character input */ + + memcpy (&LocalTermAttributes, &OriginalTermAttributes, + sizeof (struct termios)); + + LocalTermAttributes.c_lflag &= ~(ICANON | ECHO); + LocalTermAttributes.c_cc[VMIN] = 1; + LocalTermAttributes.c_cc[VTIME] = 0; + + if (tcsetattr (STDIN_FILENO, TCSANOW, &LocalTermAttributes)) + { + fprintf (stderr, "Could not set terminal attributes!\n"); + return; + } + + TermAttributesWereSet = 1; +} + + +static void +OsExitLineEditMode ( + void) +{ + + if (!TermAttributesWereSet) + { + return; + } + + /* Set terminal attributes back to the original values */ + + if (tcsetattr (STDIN_FILENO, TCSANOW, &OriginalTermAttributes)) + { + fprintf (stderr, "Could not restore terminal attributes!\n"); + } +} + + +#else + +/* These functions are not needed for other ACPICA utilities */ + +#define OsEnterLineEditMode() +#define OsExitLineEditMode() +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInitialize, AcpiOsTerminate + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize and terminate this module. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsInitialize ( + void) +{ + OsEnterLineEditMode (); + + return (AE_OK); +} + +ACPI_STATUS +AcpiOsTerminate ( + void) +{ + + OsExitLineEditMode (); + return (AE_OK); +} + + +#ifndef ACPI_USE_NATIVE_RSDP_POINTER +/****************************************************************************** + * + * FUNCTION: AcpiOsGetRootPointer + * + * PARAMETERS: None + * + * RETURN: RSDP physical address + * + * DESCRIPTION: Gets the ACPI root pointer (RSDP) + * + *****************************************************************************/ + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + + return (0); +} +#endif + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPredefinedOverride + * + * PARAMETERS: InitVal - Initial value of the predefined object + * NewVal - The new value for the object + * + * RETURN: Status, pointer to value. Null pointer returned if not + * overriding. + * + * DESCRIPTION: Allow the OS to override predefined names + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsPredefinedOverride ( + const ACPI_PREDEFINED_NAMES *InitVal, + ACPI_STRING *NewVal) +{ + + if (!InitVal || !NewVal) + { + return (AE_BAD_PARAMETER); + } + + *NewVal = NULL; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsTableOverride + * + * PARAMETERS: ExistingTable - Header of current table (probably + * firmware) + * NewTable - Where an entire new table is returned. + * + * RETURN: Status, pointer to new table. Null pointer returned if no + * table is available to override + * + * DESCRIPTION: Return a different version of a table if one is available + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_TABLE_HEADER **NewTable) +{ + + if (!ExistingTable || !NewTable) + { + return (AE_BAD_PARAMETER); + } + + *NewTable = NULL; + +#ifdef ACPI_EXEC_APP + + AeTableOverride (ExistingTable, NewTable); + return (AE_OK); +#else + + return (AE_NO_ACPI_TABLES); +#endif +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPhysicalTableOverride + * + * PARAMETERS: ExistingTable - Header of current table (probably firmware) + * NewAddress - Where new table address is returned + * (Physical address) + * NewTableLength - Where new table length is returned + * + * RETURN: Status, address/length of new table. Null pointer returned + * if no table is available to override. + * + * DESCRIPTION: Returns AE_SUPPORT, function not used in user space. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsPhysicalTableOverride ( + ACPI_TABLE_HEADER *ExistingTable, + ACPI_PHYSICAL_ADDRESS *NewAddress, + UINT32 *NewTableLength) +{ + + return (AE_SUPPORT); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsEnterSleep + * + * PARAMETERS: SleepState - Which sleep state to enter + * RegaValue - Register A value + * RegbValue - Register B value + * + * RETURN: Status + * + * DESCRIPTION: A hook before writing sleep registers to enter the sleep + * state. Return AE_CTRL_TERMINATE to skip further sleep register + * writes. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsEnterSleep ( + UINT8 SleepState, + UINT32 RegaValue, + UINT32 RegbValue) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsPrintf + * + * PARAMETERS: fmt, ... - Standard printf format + * + * RETURN: None + * + * DESCRIPTION: Formatted output. Note: very similar to AcpiOsVprintf + * (performance), changes should be tracked in both functions. + * + *****************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiOsPrintf ( + const char *Fmt, + ...) +{ + /* No-op */ +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsVprintf + * + * PARAMETERS: fmt - Standard printf format + * args - Argument list + * + * RETURN: None + * + * DESCRIPTION: Formatted output with argument list pointer. Note: very + * similar to AcpiOsPrintf, changes should be tracked in both + * functions. + * + *****************************************************************************/ + +void +AcpiOsVprintf ( + const char *Fmt, + va_list Args) +{ + /* No-op */ +} + + +#ifndef ACPI_EXEC_APP +/****************************************************************************** + * + * FUNCTION: AcpiOsGetLine + * + * PARAMETERS: Buffer - Where to return the command line + * BufferLength - Maximum length of Buffer + * BytesRead - Where the actual byte count is returned + * + * RETURN: Status and actual bytes read + * + * DESCRIPTION: Get the next input line from the terminal. NOTE: For the + * AcpiExec utility, we use the acgetline module instead to + * provide line-editing and history support. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsGetLine ( + char *Buffer, + UINT32 BufferLength, + UINT32 *BytesRead) +{ + int InputChar; + UINT32 EndOfLine; + + + /* Standard AcpiOsGetLine for all utilities except AcpiExec */ + + for (EndOfLine = 0; ; EndOfLine++) + { + if (EndOfLine >= BufferLength) + { + return (AE_BUFFER_OVERFLOW); + } + + /* EOF DNE - XXX + if ((InputChar = getchar ()) == EOF) + { + return (AE_ERROR); + } + */ + + if (!InputChar || InputChar == _ASCII_NEWLINE) + { + break; + } + + Buffer[EndOfLine] = (char) InputChar; + } + + /* Null terminate the buffer */ + + Buffer[EndOfLine] = 0; + + /* Return the number of bytes in the string */ + + if (BytesRead) + { + *BytesRead = EndOfLine; + } + + return (AE_OK); +} +#endif + + +#ifndef ACPI_USE_NATIVE_MEMORY_MAPPING +/****************************************************************************** + * + * FUNCTION: AcpiOsMapMemory + * + * PARAMETERS: where - Physical address of memory to be mapped + * length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into caller's address space + * + *****************************************************************************/ + +void * +AcpiOsMapMemory ( + ACPI_PHYSICAL_ADDRESS where, + ACPI_SIZE length) +{ + + return (ACPI_TO_POINTER ((ACPI_SIZE) where)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsUnmapMemory + * + * PARAMETERS: where - Logical address of memory to be unmapped + * length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void +AcpiOsUnmapMemory ( + void *where, + ACPI_SIZE length) +{ + + return; +} +#endif + + +#ifdef USE_NATIVE_ALLOCATE_ZEROED +/****************************************************************************** + * + * FUNCTION: AcpiOsAllocateZeroed + * + * PARAMETERS: Size - Amount to allocate, in bytes + * + * RETURN: Pointer to the new allocation. Null on error. + * + * DESCRIPTION: Allocate and zero memory. Algorithm is dependent on the OS. + * + *****************************************************************************/ + +void * +AcpiOsAllocateZeroed ( + ACPI_SIZE size) +{ + void *Mem; + + + Mem = (void *) calloc (1, (size_t) size); + return (Mem); +} +#endif + + +#ifdef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: Semaphore stub functions + * + * DESCRIPTION: Stub functions used for single-thread applications that do + * not require semaphore synchronization. Full implementations + * of these functions appear after the stubs. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_HANDLE *OutHandle) +{ + *OutHandle = (ACPI_HANDLE) 1; + return (AE_OK); +} + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_HANDLE Handle) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units, + UINT16 Timeout) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units) +{ + return (AE_OK); +} + +#else +/****************************************************************************** + * + * FUNCTION: AcpiOsCreateSemaphore + * + * PARAMETERS: InitialUnits - Units to be assigned to the new semaphore + * OutHandle - Where a handle will be returned + * + * RETURN: Status + * + * DESCRIPTION: Create an OS semaphore + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_HANDLE *OutHandle) +{ + sem_t *Sem; + + + if (!OutHandle) + { + return (AE_BAD_PARAMETER); + } + +#ifdef __APPLE__ + { + static int SemaphoreCount = 0; + char SemaphoreName[32]; + + snprintf (SemaphoreName, sizeof (SemaphoreName), "acpi_sem_%d", + SemaphoreCount++); + printf ("%s\n", SemaphoreName); + Sem = sem_open (SemaphoreName, O_EXCL|O_CREAT, 0755, InitialUnits); + if (!Sem) + { + return (AE_NO_MEMORY); + } + sem_unlink (SemaphoreName); /* This just deletes the name */ + } + +#else + Sem = AcpiOsAllocate (sizeof (sem_t)); + if (!Sem) + { + return (AE_NO_MEMORY); + } + + if (sem_init (Sem, 0, InitialUnits) == -1) + { + AcpiOsFree (Sem); + return (AE_BAD_PARAMETER); + } +#endif + + *OutHandle = (ACPI_HANDLE) Sem; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsDeleteSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * + * RETURN: Status + * + * DESCRIPTION: Delete an OS semaphore + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_HANDLE Handle) +{ + sem_t *Sem = (sem_t *) Handle; + + + if (!Sem) + { + return (AE_BAD_PARAMETER); + } + +#ifdef __APPLE__ + if (sem_close (Sem) == -1) + { + return (AE_BAD_PARAMETER); + } +#else + if (sem_destroy (Sem) == -1) + { + return (AE_BAD_PARAMETER); + } +#endif + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWaitSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * Units - How many units to wait for + * MsecTimeout - How long to wait (milliseconds) + * + * RETURN: Status + * + * DESCRIPTION: Wait for units + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units, + UINT16 MsecTimeout) +{ + ACPI_STATUS Status = AE_OK; + sem_t *Sem = (sem_t *) Handle; + int RetVal; +#ifndef ACPI_USE_ALTERNATE_TIMEOUT + struct timespec Time; +#endif + + + if (!Sem) + { + return (AE_BAD_PARAMETER); + } + + switch (MsecTimeout) + { + /* + * No Wait: + * -------- + * A zero timeout value indicates that we shouldn't wait - just + * acquire the semaphore if available otherwise return AE_TIME + * (a.k.a. 'would block'). + */ + case 0: + + if (sem_trywait(Sem) == -1) + { + Status = (AE_TIME); + } + break; + + /* Wait Indefinitely */ + + case ACPI_WAIT_FOREVER: + + while (((RetVal = sem_wait (Sem)) == -1) && (errno == EINTR)) + { + continue; /* Restart if interrupted */ + } + if (RetVal != 0) + { + Status = (AE_TIME); + } + break; + + + /* Wait with MsecTimeout */ + + default: + +#ifdef ACPI_USE_ALTERNATE_TIMEOUT + /* + * Alternate timeout mechanism for environments where + * sem_timedwait is not available or does not work properly. + */ + while (MsecTimeout) + { + if (sem_trywait (Sem) == 0) + { + /* Got the semaphore */ + return (AE_OK); + } + + if (MsecTimeout >= 10) + { + MsecTimeout -= 10; + usleep (10 * ACPI_USEC_PER_MSEC); /* ten milliseconds */ + } + else + { + MsecTimeout--; + usleep (ACPI_USEC_PER_MSEC); /* one millisecond */ + } + } + Status = (AE_TIME); +#else + /* + * The interface to sem_timedwait is an absolute time, so we need to + * get the current time, then add in the millisecond Timeout value. + */ + if (clock_gettime (CLOCK_REALTIME, &Time) == -1) + { + perror ("clock_gettime"); + return (AE_TIME); + } + + Time.tv_sec += (MsecTimeout / ACPI_MSEC_PER_SEC); + Time.tv_nsec += ((MsecTimeout % ACPI_MSEC_PER_SEC) * ACPI_NSEC_PER_MSEC); + + /* Handle nanosecond overflow (field must be less than one second) */ + + if (Time.tv_nsec >= ACPI_NSEC_PER_SEC) + { + Time.tv_sec += (Time.tv_nsec / ACPI_NSEC_PER_SEC); + Time.tv_nsec = (Time.tv_nsec % ACPI_NSEC_PER_SEC); + } + + while (((RetVal = sem_timedwait (Sem, &Time)) == -1) && (errno == EINTR)) + { + continue; /* Restart if interrupted */ + + } + + if (RetVal != 0) + { + if (errno != ETIMEDOUT) + { + perror ("sem_timedwait"); + } + Status = (AE_TIME); + } +#endif + break; + } + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSignalSemaphore + * + * PARAMETERS: Handle - Handle returned by AcpiOsCreateSemaphore + * Units - Number of units to send + * + * RETURN: Status + * + * DESCRIPTION: Send units + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units) +{ + sem_t *Sem = (sem_t *)Handle; + + + if (!Sem) + { + return (AE_BAD_PARAMETER); + } + + if (sem_post (Sem) == -1) + { + return (AE_LIMIT); + } + + return (AE_OK); +} + +#endif /* ACPI_SINGLE_THREADED */ + + +/****************************************************************************** + * + * FUNCTION: Spinlock interfaces + * + * DESCRIPTION: Map these interfaces to semaphore interfaces + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateLock ( + ACPI_SPINLOCK *OutHandle) +{ + + return (AcpiOsCreateSemaphore (1, 1, OutHandle)); +} + + +void +AcpiOsDeleteLock ( + ACPI_SPINLOCK Handle) +{ + AcpiOsDeleteSemaphore (Handle); +} + + +ACPI_CPU_FLAGS +AcpiOsAcquireLock ( + ACPI_HANDLE Handle) +{ + AcpiOsWaitSemaphore (Handle, 1, 0xFFFF); + return (0); +} + + +void +AcpiOsReleaseLock ( + ACPI_SPINLOCK Handle, + ACPI_CPU_FLAGS Flags) +{ + AcpiOsSignalSemaphore (Handle, 1); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsInstallInterruptHandler + * + * PARAMETERS: InterruptNumber - Level handler should respond to. + * Isr - Address of the ACPI interrupt handler + * ExceptPtr - Where status is returned + * + * RETURN: Handle to the newly installed handler. + * + * DESCRIPTION: Install an interrupt handler. Used to install the ACPI + * OS-independent handler. + * + *****************************************************************************/ + +UINT32 +AcpiOsInstallInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine, + void *Context) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsRemoveInterruptHandler + * + * PARAMETERS: Handle - Returned when handler was installed + * + * RETURN: Status + * + * DESCRIPTION: Uninstalls an interrupt handler. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsRemoveInterruptHandler ( + UINT32 InterruptNumber, + ACPI_OSD_HANDLER ServiceRoutine) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsStall + * + * PARAMETERS: microseconds - Time to sleep + * + * RETURN: Blocks until sleep is completed. + * + * DESCRIPTION: Sleep at microsecond granularity + * + *****************************************************************************/ + +void +AcpiOsStall ( + UINT32 microseconds) +{ + /* No-op */ +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSleep + * + * PARAMETERS: milliseconds - Time to sleep + * + * RETURN: Blocks until sleep is completed. + * + * DESCRIPTION: Sleep at millisecond granularity + * + *****************************************************************************/ + +void +AcpiOsSleep ( + UINT64 milliseconds) +{ + /* No-op */ +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsGetTimer + * + * PARAMETERS: None + * + * RETURN: Current time in 100 nanosecond units + * + * DESCRIPTION: Get the current system time + * + *****************************************************************************/ + +UINT64 +AcpiOsGetTimer ( + void) +{ + + EFI_STATUS status; + EFI_TIME time; + + if ((status = RS->GetTime(&time, NULL)), EFI_ERROR(status)) { + return 0; + } + + return (((UINT64) time.Hour * 3600ULL + + (UINT64) time.Minute * 60ULL + + (UINT64) time.Second * ACPI_100NSEC_PER_SEC) + + ((UINT64) time.Nanosecond / 100)); +} + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadPciConfiguration + * + * PARAMETERS: PciId - Seg/Bus/Dev + * PciRegister - Device Register + * Value - Buffer where value is placed + * Width - Number of bits + * + * RETURN: Status + * + * DESCRIPTION: Read data from PCI configuration space + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadPciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 PciRegister, + UINT64 *Value, + UINT32 Width) +{ + + *Value = 0; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritePciConfiguration + * + * PARAMETERS: PciId - Seg/Bus/Dev + * PciRegister - Device Register + * Value - Value to be written + * Width - Number of bits + * + * RETURN: Status. + * + * DESCRIPTION: Write data to PCI configuration space + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWritePciConfiguration ( + ACPI_PCI_ID *PciId, + UINT32 PciRegister, + UINT64 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadPort + * + * PARAMETERS: Address - Address of I/O port/register to read + * Value - Where value is placed + * Width - Number of bits + * + * RETURN: Value read from port + * + * DESCRIPTION: Read data from an I/O port or register + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + + switch (Width) + { + case 8: + + *Value = 0xFF; + break; + + case 16: + + *Value = 0xFFFF; + break; + + case 32: + + *Value = 0xFFFFFFFF; + break; + + default: + + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritePort + * + * PARAMETERS: Address - Address of I/O port/register to write + * Value - Value to write + * Width - Number of bits + * + * RETURN: None + * + * DESCRIPTION: Write data to an I/O port or register + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadMemory + * + * PARAMETERS: Address - Physical Memory Address to read + * Value - Where value is placed + * Width - Number of bits (8,16,32, or 64) + * + * RETURN: Value read from physical memory address. Always returned + * as a 64-bit integer, regardless of the read width. + * + * DESCRIPTION: Read data from a physical memory address + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsReadMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 *Value, + UINT32 Width) +{ + + switch (Width) + { + case 8: + case 16: + case 32: + case 64: + + *Value = 0; + break; + + default: + + return (AE_BAD_PARAMETER); + } + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWriteMemory + * + * PARAMETERS: Address - Physical Memory Address to write + * Value - Value to write + * Width - Number of bits (8,16,32, or 64) + * + * RETURN: None + * + * DESCRIPTION: Write data to a physical memory address + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsWriteMemory ( + ACPI_PHYSICAL_ADDRESS Address, + UINT64 Value, + UINT32 Width) +{ + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsReadable + * + * PARAMETERS: Pointer - Area to be verified + * Length - Size of area + * + * RETURN: TRUE if readable for entire length + * + * DESCRIPTION: Verify that a pointer is valid for reading + * + *****************************************************************************/ + +BOOLEAN +AcpiOsReadable ( + void *Pointer, + ACPI_SIZE Length) +{ + + return (TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWritable + * + * PARAMETERS: Pointer - Area to be verified + * Length - Size of area + * + * RETURN: TRUE if writable for entire length + * + * DESCRIPTION: Verify that a pointer is valid for writing + * + *****************************************************************************/ + +BOOLEAN +AcpiOsWritable ( + void *Pointer, + ACPI_SIZE Length) +{ + + return (TRUE); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsSignal + * + * PARAMETERS: Function - ACPI A signal function code + * Info - Pointer to function-dependent structure + * + * RETURN: Status + * + * DESCRIPTION: Miscellaneous functions. Example implementation only. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsSignal ( + UINT32 Function, + void *Info) +{ + + switch (Function) + { + case ACPI_SIGNAL_FATAL: + + break; + + case ACPI_SIGNAL_BREAKPOINT: + + break; + + default: + + break; + } + + return (AE_OK); +} + +/* Optional multi-thread support */ + +#ifndef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: AcpiOsGetThreadId + * + * PARAMETERS: None + * + * RETURN: Id of the running thread + * + * DESCRIPTION: Get the ID of the current (running) thread + * + *****************************************************************************/ + +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + pthread_t thread; + + + thread = pthread_self(); + return (ACPI_CAST_PTHREAD_T (thread)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiOsExecute + * + * PARAMETERS: Type - Type of execution + * Function - Address of the function to execute + * Context - Passed as a parameter to the function + * + * RETURN: Status. + * + * DESCRIPTION: Execute a new thread + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) +{ + pthread_t thread; + int ret; + + + ret = pthread_create (&thread, NULL, (PTHREAD_CALLBACK) Function, Context); + if (ret) + { + AcpiOsPrintf("Create thread failed"); + } + return (0); +} + +#else /* ACPI_SINGLE_THREADED */ +ACPI_THREAD_ID +AcpiOsGetThreadId ( + void) +{ + return (1); +} + +ACPI_STATUS +AcpiOsExecute ( + ACPI_EXECUTE_TYPE Type, + ACPI_OSD_EXEC_CALLBACK Function, + void *Context) +{ + + Function (Context); + + return (AE_OK); +} + +#endif /* ACPI_SINGLE_THREADED */ + + +/****************************************************************************** + * + * FUNCTION: AcpiOsWaitEventsComplete + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Wait for all asynchronous events to complete. This + * implementation does nothing. + * + *****************************************************************************/ + +void +AcpiOsWaitEventsComplete ( + void) +{ + return; +} diff --git a/stand/efi/libacpi/Makefile b/stand/efi/libacpi/Makefile new file mode 100644 index 00000000000000..c74c9126296dcc --- /dev/null +++ b/stand/efi/libacpi/Makefile @@ -0,0 +1,60 @@ +.include + +LIB= acpi + +SRCS+= acpi_detect.c + +CFLAGS+= -I${EFISRC}/include +CFLAGS+= -I${EFISRC}/include/${MACHINE} +CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include +CFLAGS+= -I${EFISRC}/libacpi + +.if ${MACHINE} == "amd64" && ${DO32:U0} == 0 +CFLAGS+= -DACPI_SINGLE_THREADED \ + -DACPI_USE_NATIVE_RSDP_POINTER \ + -DACPI_USE_NATIVE_MEMORY_MAPPING \ + -DACPI_REDUCED_HARDWARE \ + -DACPI_DEBUG_OUTPUT + +.PATH: ${.CURDIR}/../libefi +.PATH: ${.CURDIR}/acpi +.PATH: ${.CURDIR}/acpi/amd64/Osd +.PATH: ${.CURDIR}/../contrib/dev/acpica/os_specific/service_layers +.PATH: ${SYSDIR}/contrib/dev/acpica/os_specific/service_layers +.PATH: ${SYSDIR}/contrib/dev/acpica/components/tables +.PATH: ${SYSDIR}/contrib/dev/acpica/components/namespace +.PATH: ${SYSDIR}/contrib/dev/acpica/components/utilities +.PATH: ${SYSDIR}/contrib/dev/acpica/components/dispatcher +.PATH: ${SYSDIR}/contrib/dev/acpica/components/executer +.PATH: ${SYSDIR}/contrib/dev/acpica/components/hardware +.PATH: ${SYSDIR}/contrib/dev/acpica/components/events +.PATH: ${SYSDIR}/contrib/dev/acpica/components/parser + +SRCS+= libefi.c OsdMemory.c osunixxf.c utinit.c utglobal.c utresrc.c utlock.c \ + utownerid.c utcopy.c uthex.c utmath.c utstrsuppt.c utstrtoul64.c \ + utpredef.c uterror.c uteval.c utids.c utbuffer.c utmisc.c utalloc.c \ + utxferror.c utexcep.c utaddress.c utascii.c utcache.c utcksum.c \ + utdebug.c utdecode.c utdelete.c utmutex.c utobject.c utosi.c \ + utstring.c utxfinit.c utnonansi.c utstate.c tbdata.c tbxfload.c \ + tbfadt.c tbinstal.c tbprint.c tbutils.c tbxface.c tbxfroot.c \ + tbfind.c nsxfobj.c nsxfeval.c nsinit.c nsparse.c nsload.c \ + nsrepair2.c nsconvert.c nsrepair.c nsprepkg.c nsarguments.c nseval.c \ + nsxfname.c nsdump.c nswalk.c nssearch.c nsnames.c nsutils.c \ + nsaccess.c nsalloc.c nsobject.c nspredef.c dsinit.c dsfield.c \ + dspkginit.c dsopcode.c dsdebug.c dsmethod.c dscontrol.c dsobject.c \ + dsutils.c dswexec.c dswload2.c dswload.c dsmthdat.c dswstate.c \ + dsargs.c dswscope.c exregion.c exfldio.c exserial.c exstorob.c \ + exstoren.c exdebug.c exmutex.c exconcat.c exmisc.c exconfig.c \ + excreate.c exoparg6.c exoparg3.c exoparg2.c exoparg1.c exdump.c \ + exprep.c exresop.c exsystem.c exnames.c exresolv.c exstore.c \ + exfield.c exconvrt.c exresnte.c exutils.c extrace.c hwpci.c \ + hwregs.c hwxface.c hwvalid.c hwacpi.c evmisc.c evregion.c evrgnini.c \ + evxface.c evevent.c evxfevnt.c evhandler.c evxfregn.c psobject.c \ + psloop.c pstree.c pswalk.c psopinfo.c psscope.c psutils.c psargs.c \ + psparse.c psxface.c psopcode.c init_acpi.c + +CFLAGS+= -I${EFISRC}/libacpi/acpi/include + +.endif # amd64 + +.include diff --git a/stand/efi/libacpi/acpi/amd64/Osd/OsdMemory.c b/stand/efi/libacpi/acpi/amd64/Osd/OsdMemory.c new file mode 100644 index 00000000000000..646e518cf9bebc --- /dev/null +++ b/stand/efi/libacpi/acpi/amd64/Osd/OsdMemory.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2025 Kayla Powell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +void * +AcpiOsAllocate(ACPI_SIZE Size) +{ + return (malloc(Size)); +} + +void +AcpiOsFree(void *Memory) +{ + free(Memory); +} + +void * +AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, ACPI_SIZE Length) +{ + return (void *)(PhysicalAddress); +} + +void +AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length) +{ + /* No-op as we never mapped any memory. */ +} + +ACPI_PHYSICAL_ADDRESS +AcpiOsGetRootPointer ( + void) +{ + if (!rsdp) { + return (0); + } + + return (ACPI_PHYSICAL_ADDRESS)(uintptr_t)(rsdp); +} diff --git a/stand/efi/libacpi/acpi/include/init_acpi.h b/stand/efi/libacpi/acpi/include/init_acpi.h new file mode 100644 index 00000000000000..3c65e5cd364041 --- /dev/null +++ b/stand/efi/libacpi/acpi/include/init_acpi.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2025 Kayla Powell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef INIT_ACPI_H +#define INIT_ACPI_H + +#include +#include +#include + +#define ACPI_LOADER 0x00020000 + +ACPI_STATUS acpi_Startup(void); +int init_acpi(void); +int acpi_is_initialized(void); + +#endif /* ACPI_H */ diff --git a/stand/efi/libacpi/acpi/init_acpi.c b/stand/efi/libacpi/acpi/init_acpi.c new file mode 100644 index 00000000000000..f18681f0588036 --- /dev/null +++ b/stand/efi/libacpi/acpi/init_acpi.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2025 Kayla Powell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define _COMPONENT ACPI_LOADER +ACPI_MODULE_NAME("init_acpi"); + +/* Singleton protection. */ +static int acpi_inited = 0; + +/* + * Initialize a smaller subset of the ACPI subsystem in the + * loader. This subset is enough for users to evaluate + * objects on the namespace, and includes event management. + * + * This function brings up the ACPICA core in four stages: + * 1. Initialize the ACPICA subsystem. + * 2. Initialize and validate ACPI root tables. + * 3. Enable the subsystem (without full hardware mode, but events + * enabled). + * 4. Load ACPI tables into the namespace. + * + * Returns ACPI_STATUS; failure indicates issue reading RSDT/XSDT. + * Please refer to your motherboard manual to verify ACPI support. + */ +ACPI_STATUS +acpi_Startup(void) +{ + ACPI_STATUS status; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + /* Initialize the ACPICA subsystem. */ + if (ACPI_FAILURE(status = AcpiInitializeSubsystem())) { + printf("ACPI: Could not initialize Subsystem: %s\n", + AcpiFormatException(status)); + return_VALUE(status); + } + + /* Initialize the ACPICA tables. */ + if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 2, TRUE))) { + printf("ACPI: Table initialisation failed: %s\n", + AcpiFormatException(status)); + return_VALUE(status); + } + + /* Enable the ACPI subsystem. */ + uint32_t flags = ACPI_REDUCED_HARDWARE | ACPI_NO_ACPI_ENABLE; + if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) { + printf("ACPI: Enable subsystem failed: %s\n", + AcpiFormatException(status)); + return_VALUE(status); + } + + /* Create the ACPI namespace from ACPI tables. */ + if (ACPI_FAILURE(status = AcpiLoadTables())) { + printf("ACPI: Load tables failed: %s\n", + AcpiFormatException(status)); + return_VALUE(status); + } + + return_VALUE(status); +} + +/* + * Initialize ACPI once for the loader. + * + * This is a singleton entry point. Safe to call multiple times; + * subsequent calls will return success immediately. + * + * Returns 0 on success, ENXIO if ACPI could not be initialized. + */ +int +init_acpi(void) +{ + ACPI_STATUS status; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + if (acpi_inited) { + return (0); + } + + if (ACPI_FAILURE(status = acpi_Startup())) { + printf("ACPI: Loader initialization failed with status %s\n", + AcpiFormatException(status)); + return (ENXIO); + } + + acpi_inited = 1; + + return (0); +} + +/* + * Confirm ACPI initialization. + */ +int +acpi_is_initialized(void) +{ + return (acpi_inited); +} diff --git a/stand/efi/libacpi/acpi_detect.c b/stand/efi/libacpi/acpi_detect.c new file mode 100644 index 00000000000000..7895636b4d68ae --- /dev/null +++ b/stand/efi/libacpi/acpi_detect.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2014 Ed Maste + * Copyright (c) 2025 Kayla Powell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include "acpi_detect.h" + +/* For ACPI rsdp discovery. */ +EFI_GUID acpi = ACPI_TABLE_GUID; +EFI_GUID acpi20 = ACPI_20_TABLE_GUID; +ACPI_TABLE_RSDP *rsdp; + +void +acpi_detect(void) +{ + char buf[24]; + int revision; + + feature_enable(FEATURE_EARLY_ACPI); + if ((rsdp = efi_get_table(&acpi20)) == NULL) + if ((rsdp = efi_get_table(&acpi)) == NULL) + return; + + sprintf(buf, "0x%016"PRIxPTR, (uintptr_t)rsdp); + setenv("acpi.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + sprintf(buf, "%d", revision); + setenv("acpi.revision", buf, 1); + strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); + buf[sizeof(rsdp->OemId)] = '\0'; + setenv("acpi.oem", buf, 1); + sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); + setenv("acpi.rsdt", buf, 1); + if (revision >= 2) { + /* XXX extended checksum? */ + sprintf(buf, "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("acpi.xsdt", buf, 1); + sprintf(buf, "%d", rsdp->Length); + setenv("acpi.xsdt_length", buf, 1); + } +} diff --git a/stand/efi/libacpi/acpi_detect.h b/stand/efi/libacpi/acpi_detect.h new file mode 100644 index 00000000000000..246e790be9fbdf --- /dev/null +++ b/stand/efi/libacpi/acpi_detect.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Kayla Powell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ACPI_DETECT_H +#define ACPI_DETECT_H + +#include +#include + +struct ACPI_TABLE_RSDP; // forward declaration + +extern EFI_GUID acpi; +extern EFI_GUID acpi20; +extern ACPI_TABLE_RSDP *rsdp; + +void acpi_detect(void); + +#endif diff --git a/stand/efi/libacpi32/Makefile b/stand/efi/libacpi32/Makefile new file mode 100644 index 00000000000000..659a9f7000d9e3 --- /dev/null +++ b/stand/efi/libacpi32/Makefile @@ -0,0 +1,4 @@ +DO32=1 + +.PATH: ${.CURDIR}/../libacpi +.include "${.CURDIR}/../libacpi/Makefile" diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index ae2ffc475730f7..4f51d4898cd8ba 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -66,9 +66,14 @@ CFLAGS+= -I${.CURDIR}/arch/${__arch} CFLAGS+= -I${EFISRC}/include CFLAGS+= -I${EFISRC}/include/${__arch} CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include +CFLAGS+= -I${EFISRC}/libacpi CFLAGS+= -I${BOOTSRC}/i386/libi386 CFLAGS+= -DEFI +.if ${MACHINE} == "amd64" && ${DO32:U0} == 0 +CFLAGS+= -I${EFISRC}/libacpi/acpi/include +.endif + .if defined(HAVE_FDT) && ${MK_FDT} != "no" .include "${BOOTSRC}/fdt.mk" LIBEFI_FDT= ${BOOTOBJ}/efi/fdt/libefi_fdt.a @@ -136,13 +141,17 @@ ${LOADER}.efi: ${PROG} LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a LIBEFI32= ${BOOTOBJ}/efi/libefi32/libefi.a +LIBACPI= ${BOOTOBJ}/efi/libacpi/libacpi.a +LIBACPI32= ${BOOTOBJ}/efi/libacpi32/libacpi.a .if ${__arch} == "i386" -DPADD= ${LDR_INTERP32} ${LIBEFI32} ${LIBSA32} ${LDSCRIPT} -LDADD= ${LDR_INTERP32} ${LIBEFI32} ${LIBSA32} +DPADD= ${LDR_INTERP32} ${LIBEFI32} ${LIBSA32} ${LIBACPI32} ${LDSCRIPT} +LDADD= ${LDR_INTERP32} ${LIBEFI32} ${LIBSA32} ${LIBACPI32} .else -DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBSAFDT} ${LIBEFI_FDT} ${LIBSA} ${LDSCRIPT} -LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBSAFDT} ${LIBEFI_FDT} ${LIBSA} +DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBSAFDT} ${LIBEFI_FDT} ${LIBSA} \ + ${LIBACPI} ${LDSCRIPT} +LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBSAFDT} ${LIBEFI_FDT} ${LIBSA} \ + ${LIBACPI} .endif .include diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 4366763684473a..15201c51a53ab5 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -66,8 +66,15 @@ #include "platform/acfreebsd.h" #include "acconfig.h" #define ACPI_SYSTEM_XFACE + +#if defined(__amd64__) +#include +#else +#include +#endif #include "actypes.h" #include "actbl.h" +#include #include "loader_efi.h" @@ -83,8 +90,6 @@ struct arch_switch archsw = { /* MI/MD interface boundary */ .arch_zfs_probe = efi_zfs_probe, }; -EFI_GUID acpi = ACPI_TABLE_GUID; -EFI_GUID acpi20 = ACPI_20_TABLE_GUID; EFI_GUID devid = DEVICE_PATH_PROTOCOL; EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; EFI_GUID mps = MPS_TABLE_GUID; @@ -120,11 +125,6 @@ UINT16 boot_current; */ EFI_LOADED_IMAGE *boot_img; -/* - * RSDP base table. - */ -ACPI_TABLE_RSDP *rsdp; - static bool has_keyboard(void) { @@ -1129,39 +1129,6 @@ ptov(uintptr_t x) return ((caddr_t)x); } -static void -acpi_detect(void) -{ - char buf[24]; - int revision; - - feature_enable(FEATURE_EARLY_ACPI); - if ((rsdp = efi_get_table(&acpi20)) == NULL) - if ((rsdp = efi_get_table(&acpi)) == NULL) - return; - - sprintf(buf, "0x%016"PRIxPTR, (uintptr_t)rsdp); - setenv("acpi.rsdp", buf, 1); - revision = rsdp->Revision; - if (revision == 0) - revision = 1; - sprintf(buf, "%d", revision); - setenv("acpi.revision", buf, 1); - strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); - buf[sizeof(rsdp->OemId)] = '\0'; - setenv("acpi.oem", buf, 1); - sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); - setenv("acpi.rsdt", buf, 1); - if (revision >= 2) { - /* XXX extended checksum? */ - sprintf(buf, "0x%016llx", - (unsigned long long)rsdp->XsdtPhysicalAddress); - setenv("acpi.xsdt", buf, 1); - sprintf(buf, "%d", rsdp->Length); - setenv("acpi.xsdt_length", buf, 1); - } -} - static void efi_smbios_detect(void) { @@ -1211,6 +1178,7 @@ main(int argc, CHAR16 *argv[]) char boot_info[4096]; char buf[32]; bool uefi_boot_mgr; + int ret = 0; #if !defined(__arm__) efi_smbios_detect(); @@ -1267,6 +1235,13 @@ main(int argc, CHAR16 *argv[]) devinit(); +#if defined(__amd64__) + /* Initialize ACPI Subsystem and Tables. */ + if ((ret = init_acpi()) != 0) { + printf("Failed to initialize ACPI\n."); + } +#endif + /* * Detect console settings two different ways: one via the command * args (eg -h) or via the UEFI ConOut variable. diff --git a/sys/contrib/dev/acpica/components/events/evxface.c b/sys/contrib/dev/acpica/components/events/evxface.c index 54634c61e517c1..6ad67369e76df5 100644 --- a/sys/contrib/dev/acpica/components/events/evxface.c +++ b/sys/contrib/dev/acpica/components/events/evxface.c @@ -175,7 +175,7 @@ AcpiEvInstallGpeHandler ( #endif - +#ifndef _STANDALONE /******************************************************************************* * * FUNCTION: AcpiInstallNotifyHandler @@ -517,6 +517,7 @@ AcpiRemoveNotifyHandler ( ACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler) +#endif /* !_STANDALONE */ /******************************************************************************* * @@ -794,7 +795,7 @@ AcpiInstallGlobalEventHandler ( ACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler) - +#ifndef _STANDALONE /******************************************************************************* * * FUNCTION: AcpiInstallFixedEventHandler @@ -942,6 +943,7 @@ AcpiRemoveFixedEventHandler ( ACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler) +#endif /* !_STANDALONE */ /******************************************************************************* * diff --git a/sys/contrib/dev/acpica/components/hardware/hwxface.c b/sys/contrib/dev/acpica/components/hardware/hwxface.c index 5f645617cbcefe..c5f4d31273d927 100644 --- a/sys/contrib/dev/acpica/components/hardware/hwxface.c +++ b/sys/contrib/dev/acpica/components/hardware/hwxface.c @@ -476,7 +476,7 @@ ACPI_EXPORT_SYMBOL (AcpiWriteBitRegister) #endif /* !ACPI_REDUCED_HARDWARE */ - +#ifndef _STANDALONE /******************************************************************************* * * FUNCTION: AcpiGetSleepTypeData @@ -644,3 +644,5 @@ AcpiGetSleepTypeData ( } ACPI_EXPORT_SYMBOL (AcpiGetSleepTypeData) + +#endif /* !_STANDALONE */ diff --git a/sys/contrib/dev/acpica/components/utilities/utdelete.c b/sys/contrib/dev/acpica/components/utilities/utdelete.c index e88cc736990b32..38b47ccb03cd85 100644 --- a/sys/contrib/dev/acpica/components/utilities/utdelete.c +++ b/sys/contrib/dev/acpica/components/utilities/utdelete.c @@ -261,10 +261,12 @@ AcpiUtDeleteInternalObj ( */ case ACPI_TYPE_DEVICE: +#ifndef _STANDALONE if (Object->Device.GpeBlock) { (void) AcpiEvDeleteGpeBlock (Object->Device.GpeBlock); } +#endif ACPI_FALLTHROUGH; diff --git a/sys/contrib/dev/acpica/components/utilities/utinit.c b/sys/contrib/dev/acpica/components/utilities/utinit.c index b5a4b7e7d936f7..5e051c34dee3a1 100644 --- a/sys/contrib/dev/acpica/components/utilities/utinit.c +++ b/sys/contrib/dev/acpica/components/utilities/utinit.c @@ -429,7 +429,7 @@ AcpiUtSubsystemShutdown ( AcpiGbl_StartupFlags = 0; ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); -#ifndef ACPI_ASL_COMPILER +#if !defined(ACPI_ASL_COMPILER) && !defined(_STANDALONE) /* Close the AcpiEvent Handling */ diff --git a/sys/contrib/dev/acpica/components/utilities/utxfinit.c b/sys/contrib/dev/acpica/components/utilities/utxfinit.c index f295471031d0e9..3b5ff80869bde1 100644 --- a/sys/contrib/dev/acpica/components/utilities/utxfinit.c +++ b/sys/contrib/dev/acpica/components/utilities/utxfinit.c @@ -358,6 +358,7 @@ AcpiEnableSubsystem ( ACPI_EXPORT_SYMBOL_INIT (AcpiEnableSubsystem) +#ifndef _STANDALONE /******************************************************************************* * * FUNCTION: AcpiInitializeObjects @@ -428,3 +429,5 @@ AcpiInitializeObjects ( } ACPI_EXPORT_SYMBOL_INIT (AcpiInitializeObjects) + +#endif /* !_STANDALONE */ diff --git a/sys/contrib/dev/acpica/include/accommon.h b/sys/contrib/dev/acpica/include/accommon.h index 10a39803842b04..b032d3c03a4ecb 100644 --- a/sys/contrib/dev/acpica/include/accommon.h +++ b/sys/contrib/dev/acpica/include/accommon.h @@ -170,6 +170,9 @@ #ifndef ACPI_USE_SYSTEM_CLIBRARY #include /* C library interfaces */ #endif /* !ACPI_USE_SYSTEM_CLIBRARY */ +#ifdef _STANDALONE +#include +#endif #endif /* __ACCOMMON_H__ */ From 1a20a357f9c360b69dc2d8ceecd5746ea7d333b0 Mon Sep 17 00:00:00 2001 From: kpowkitty Date: Mon, 22 Sep 2025 15:09:06 -0700 Subject: [PATCH 2/5] libacpi: Create README.md --- stand/efi/libacpi/README.md | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 stand/efi/libacpi/README.md diff --git a/stand/efi/libacpi/README.md b/stand/efi/libacpi/README.md new file mode 100644 index 00000000000000..9f443463b6cc9a --- /dev/null +++ b/stand/efi/libacpi/README.md @@ -0,0 +1,64 @@ +# Google Summer of Code 2025 @ FreeBSD +Mentor: Warner Losh @bsdimp +Student: Kayla (Kat) Powell @kpowkitty +--------------- +## ACPI Initialization in Loader with Lua Bindings +Intel's Advanced Configuration and Power Interface (ACPI) brought power management out of the BIOS +and into the operating system. We can make it even more powerful by creating an interface +to script it. Currently, the scripting language of choice in FreeBSD (rather than POSIX `sh`, `bash`, or `awk`) +is Lua. Therefore, this project aims to initialize a portion of ACPI in the FreeBSD bootloader, with respect +to its storage, memory, and stdlib constraints, so we can enumerate and evaluate objects on the device trees to +provide an interface to Lua. + +## Milestones +[x] `OsdMemory.c` for `amd64` (`arm64` postponed) +[x] `AcpiInitializeSubsystem` +[x] `AcpiInitializeTables` +[x] `AcpiEnableSubsystem` in reduced hardware mode, with events enabled +[x] `AcpiLoadTables` +[x] `AcpiWalkNamespace` +[x] `AcpiEvaluateObject` +[x] ACPICA initialized in loader for `amd64` +[x] lacpi_object.c (V1) + -- V1: Users can evaluate objects +[x] lacpi_data.c (V1) + -- V1: Users can attach, get, detach data from nodes +[x] lacpi_walk.c (V1) + -- V1: Walk and read nodes off the namespace + -- V2: Namespace format -- TBR + -- V3: Strategies for walking the namespace -- TBR +[x] Man page update + +**Future goals of this project include arm64 compat and extending the interface.** + +### For more information, please consult these resources: +[ACPI Lua Bindings FreeBSD project wiki page](https://wiki.freebsd.org/SummerOfCode2025Projects/ACPI%20Initialization%20in%20Loader%20With%20Lua%20Bindings) +[Write-up](https://kmpow.com/content/gsoc-writeup) + +--------------- + +## Building +This project requires an amd64 UEFI FreeBSD system. + +The current working version of this project is found on branch `acpi_init`. + +1. Clone the repo +``` +$ git clone git@github.com:kpowkitty/freebsd-src.git +$ git checkout acpi_init +``` + +2. Build the necessary dependencies and install the loader image +``` +$ cd stand/efi +# make -j $MAX_JOBS && make install +``` + +3. Reboot +``` +# shutdown -r now +``` + +## System Recovery +In general cases, to recover your system, you need to mount your drive +on a live iso and replace your drive's `loader.efi` with the live iso image's `loader.efi`. From b8fb47d1fc8d063dacdb083285b22eb757fa062a Mon Sep 17 00:00:00 2001 From: kpowkitty Date: Wed, 24 Sep 2025 16:20:25 -0700 Subject: [PATCH 3/5] lacpi: Loader compilation These bindings have two conditions: (1) Must be built on `amd64` (2) Must be building `loader_lua` If these conditions are met: - Add liblua as a subdir in EFI - Include liblua/acpi/include in loader/Makefile - Add set_lua_acpi_modules to the loader compile set - Add 'lacpi.h' to loader/main.c and reference the bindings --- stand/efi/Makefile | 1 + stand/efi/loader/Makefile | 16 ++++++++++++++++ stand/efi/loader/main.c | 7 +++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/stand/efi/Makefile b/stand/efi/Makefile index 6147d2d7734bcb..50e0e0c5901251 100644 --- a/stand/efi/Makefile +++ b/stand/efi/Makefile @@ -7,6 +7,7 @@ SUBDIR.${MK_LOADER_IA32}+= libefi32 SUBDIR.${MK_FDT}+= fdt SUBDIR.yes+= libacpi SUBDIR.${MK_LOADER_IA32}+= libacpi32 +SUBDIR.yes+= ../liblua SUBDIR.yes+= .WAIT SUBDIR.yes+= boot1 gptboot diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index 4f51d4898cd8ba..e41df4ebaa272a 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -72,6 +72,7 @@ CFLAGS+= -DEFI .if ${MACHINE} == "amd64" && ${DO32:U0} == 0 CFLAGS+= -I${EFISRC}/libacpi/acpi/include +CFLAGS+= -I${EFISRC}/../liblua/acpi/include .endif .if defined(HAVE_FDT) && ${MK_FDT} != "no" @@ -127,6 +128,20 @@ LDFLAGS+= -Wl,--threads=1 CLEANFILES+= ${LOADER}.efi +# ACPI Lua bindings compile set +.if ${__arch} == "amd64" && ${DO32:U0} == 0 && ${LOADER} == "loader_lua" +LACPI_COMPILE_SET= -j set_lua_acpi_modules +.else +LACPI_COMPILE_SET= +.endif + +# To protect ACPI init and lua bindings +.if ${LOADER} == "loader_lua" +CFLAGS+= -DLACPI=1 +.else +CFLAGS+= -DLACPI=0 +.endif + ${LOADER}.efi: ${PROG} @if ${NM} ${.ALLSRC} | grep ' U '; then \ echo "Undefined symbols in ${.ALLSRC}"; \ @@ -137,6 +152,7 @@ ${LOADER}.efi: ${PROG} -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ -j set_X${LOADER_INTERP}_compile_set \ + ${LACPI_COMPILE_SET} \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 15201c51a53ab5..13c3c40526d17b 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -67,8 +67,9 @@ #include "acconfig.h" #define ACPI_SYSTEM_XFACE -#if defined(__amd64__) +#if defined(__amd64__) && LACPI #include +#include #else #include #endif @@ -1235,11 +1236,13 @@ main(int argc, CHAR16 *argv[]) devinit(); -#if defined(__amd64__) +#if defined(__amd64__) && LACPI /* Initialize ACPI Subsystem and Tables. */ if ((ret = init_acpi()) != 0) { printf("Failed to initialize ACPI\n."); } + + lacpi_interp_ref(); #endif /* From e90f340aa55074df91503ee144ddba6b1395d35c Mon Sep 17 00:00:00 2001 From: kpowkitty Date: Wed, 24 Sep 2025 16:21:17 -0700 Subject: [PATCH 4/5] liblua: Create lacpi --- stand/liblua/Makefile | 14 + stand/liblua/acpi/include/lacpi.h | 32 ++ stand/liblua/acpi/include/lacpi_data.h | 7 + stand/liblua/acpi/include/lacpi_object.h | 8 + stand/liblua/acpi/include/lacpi_utils.h | 69 +++ stand/liblua/acpi/include/lacpi_walk.h | 12 + stand/liblua/acpi/lacpi.c | 62 +++ stand/liblua/acpi/lacpi_data.c | 190 +++++++ stand/liblua/acpi/lacpi_object.c | 194 +++++++ stand/liblua/acpi/lacpi_utils.c | 615 +++++++++++++++++++++++ stand/liblua/acpi/lacpi_walk.c | 79 +++ stand/liblua/lutils.c | 23 + stand/liblua/lutils.h | 2 + stand/lua/Makefile | 3 +- 14 files changed, 1309 insertions(+), 1 deletion(-) create mode 100644 stand/liblua/acpi/include/lacpi.h create mode 100644 stand/liblua/acpi/include/lacpi_data.h create mode 100644 stand/liblua/acpi/include/lacpi_object.h create mode 100644 stand/liblua/acpi/include/lacpi_utils.h create mode 100644 stand/liblua/acpi/include/lacpi_walk.h create mode 100644 stand/liblua/acpi/lacpi.c create mode 100644 stand/liblua/acpi/lacpi_data.c create mode 100644 stand/liblua/acpi/lacpi_object.c create mode 100644 stand/liblua/acpi/lacpi_utils.c create mode 100644 stand/liblua/acpi/lacpi_walk.c diff --git a/stand/liblua/Makefile b/stand/liblua/Makefile index ce7eb89fe494ef..f858818271d423 100644 --- a/stand/liblua/Makefile +++ b/stand/liblua/Makefile @@ -29,6 +29,20 @@ SRCS+= lfs.c .PATH: ${FLUALIB}/libhash SRCS+= lhash.c +# ACPI +.if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 0 +.PATH: ${LIBLUASRC}/acpi + +SRCS+= lacpi.c lacpi_object.c lacpi_utils.c lacpi_walk.c lacpi_data.c + +CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include \ + -I${EFISRC}/libacpi/acpi/include -I${EFISRC}/include \ + -I${EFISRC}/include/amd64 -I${LIBLUASRC}/acpi/include + +DPADD+= ${LIBACPI} +LDADD+= ${LIBACPI} +.endif + WARNS?= 3 CFLAGS+= -DLUA_PATH=\"${LUAPATH}\" -DLUA_PATH_DEFAULT=\"${LUAPATH}/\?.lua\" diff --git a/stand/liblua/acpi/include/lacpi.h b/stand/liblua/acpi/include/lacpi.h new file mode 100644 index 00000000000000..c94eb61f40daf7 --- /dev/null +++ b/stand/liblua/acpi/include/lacpi.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +typedef int (*lua_module_init_fn)(lua_State *L); +extern void lacpi_object_interp_ref(void); +extern void lacpi_data_interp_ref(void); + +struct lua_acpi_module { + const char *mod_name; + lua_module_init_fn init; +}; + +SET_DECLARE(lua_acpi_modules, struct lua_acpi_module); + +#define LUA_ACPI_COMPILE_SET(name, initfn) \ + static struct lua_acpi_module lua_##name = \ + { \ + .mod_name = #name, \ + .init = initfn \ + }; \ + DATA_SET(lua_acpi_modules, lua_##name) + +struct lacpi_node { + const char* pathname; + ACPI_HANDLE handle; +}; + +void lacpi_interp_ref(void); +void lua_acpi_register_hook(void); diff --git a/stand/liblua/acpi/include/lacpi_data.h b/stand/liblua/acpi/include/lacpi_data.h new file mode 100644 index 00000000000000..564358565a495a --- /dev/null +++ b/stand/liblua/acpi/include/lacpi_data.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +void lacpi_data_interp_ref(void); +int luaopen_lacpi_data(lua_State *L); diff --git a/stand/liblua/acpi/include/lacpi_object.h b/stand/liblua/acpi/include/lacpi_object.h new file mode 100644 index 00000000000000..a1988768409b38 --- /dev/null +++ b/stand/liblua/acpi/include/lacpi_object.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +void lacpi_object_interp_ref(void); +void lacpi_node_register_mt(lua_State *L); +int luaopen_lacpi_object(lua_State *L); diff --git a/stand/liblua/acpi/include/lacpi_utils.h b/stand/liblua/acpi/include/lacpi_utils.h new file mode 100644 index 00000000000000..886947ca266ff5 --- /dev/null +++ b/stand/liblua/acpi/include/lacpi_utils.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include +#include + +/***** UTILITY *****/ + +/* verifies lua passed over a handle on the stack */ +ACPI_HANDLE lacpi_check_handle(lua_State *L, int idx); + +/* destructor dispatcher */ +typedef void (*acpi_destructor_t)(ACPI_OBJECT *); + +/* safety check -- lua stores integers as 64bit */ +ACPI_STATUS lacpi_int_to_uint32(lua_State *L, int index, UINT32 *num); + +/* to convert ACPI_OBJECT_TYPE from table value */ +ACPI_STATUS lacpi_infer_type(lua_State *L, int idx, UINT32 *type); + +/* build error code and push it onto stack */ +int lacpi_push_err(lua_State *L, const int push_nil, const char *errmsg, + const ACPI_STATUS status); + +/* extract error message relating to ACPI_STATUS */ +char *lacpi_extract_status(const ACPI_STATUS status); + +/***** FACTORY *****/ + +/* create metatable gc */ +int lacpi_create_mt_gc(lua_State *L, const char *mt, lua_CFunction gc_func); + +/*** ACPI_OBJECT ***/ +/* build ACPI_OBJECTs */ +ACPI_STATUS build_int(lua_State *L, ACPI_OBJECT *obj, int idx); +ACPI_STATUS build_str(lua_State *L, ACPI_OBJECT *obj, int idx); +ACPI_STATUS build_buff(lua_State *L, ACPI_OBJECT *obj, int idx); +ACPI_STATUS build_pkg(lua_State *L, ACPI_OBJECT *obj, int idx); +ACPI_STATUS build_acpi_obj(lua_State *L, ACPI_OBJECT *obj, UINT32 obj_type, int idx); +ACPI_STATUS build_ref(lua_State *L, ACPI_OBJECT *obj, int idx); +ACPI_STATUS build_proc(lua_State *L, ACPI_OBJECT *obj, int idx); +ACPI_STATUS build_pow(lua_State *L, ACPI_OBJECT *obj, int idx); + +/* push ACPI_OBJECTs onto lua stack */ +void push_int(lua_State *L, ACPI_OBJECT *obj); +void push_str(lua_State *L, ACPI_OBJECT *obj); +void push_buff(lua_State *L, ACPI_OBJECT *obj); +void push_pkg(lua_State *L, ACPI_OBJECT *obj); +void push_acpi_obj(lua_State *L, ACPI_OBJECT *obj); +void push_ref(lua_State *L, ACPI_OBJECT *obj); +void push_proc(lua_State *L, ACPI_OBJECT *obj); +void push_pow(lua_State *L, ACPI_OBJECT *obj); + +/* free ACPI_OBJECTs */ +void free_fake(ACPI_OBJECT *obj); +void free_str(ACPI_OBJECT *obj); +void free_buff(ACPI_OBJECT *obj); +void free_pkg(ACPI_OBJECT *obj); +void free_acpi_obj(ACPI_OBJECT *obj); +void free_acpi_objs(ACPI_OBJECT **objs, UINT32 init_count); + +/*** ACPI Namespace Node ***/ +void push_path(struct context *curr_ctx, const char *path); +void push_lvl(struct context *curr_ctx, UINT32 level); +void push_hid(struct context *curr_ctx, const char *hid); +void push_uid(struct context *curr_ctx, const char *uid); +void push_node(struct context *curr_ctx, const char *path, UINT32 level, + ACPI_HANDLE handle); diff --git a/stand/liblua/acpi/include/lacpi_walk.h b/stand/liblua/acpi/include/lacpi_walk.h new file mode 100644 index 00000000000000..c5ded07be46a1f --- /dev/null +++ b/stand/liblua/acpi/include/lacpi_walk.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct context { + lua_State *L; + int tbl; + int idx; +}; + +int luaopen_lacpi_walk(lua_State *L); +void lacpi_walk_interp_ref(void); diff --git a/stand/liblua/acpi/lacpi.c b/stand/liblua/acpi/lacpi.c new file mode 100644 index 00000000000000..42554f94dfe477 --- /dev/null +++ b/stand/liblua/acpi/lacpi.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include "lacpi.h" +#include "lacpi_object.h" +#include "lacpi_walk.h" +#include "lacpi_data.h" + +/* + * Reference set for all lacpi modules. + */ +void +lacpi_interp_ref(void) +{ + lacpi_object_interp_ref(); + lacpi_walk_interp_ref(); + lacpi_data_interp_ref(); +} + +int +luaopen_lacpi(lua_State *L) +{ + lua_newtable(L); + + luaopen_lacpi_object(L); + lua_setfield(L, -2, "object"); + + luaopen_lacpi_walk(L); + lua_setfield(L, -2, "walk"); + + luaopen_lacpi_data(L); + lua_setfield(L, -2, "data"); + + return 1; +} + +/* + * Unpacks all lacpi modules. + */ +static void +lua_acpi_bindings(lua_State *L) +{ + struct lua_acpi_module **mod; + + SET_FOREACH(mod, lua_acpi_modules) { + (*mod)->init(L); + lua_setglobal(L, (*mod)->mod_name); + } +} + +/* + * Function hook for lacpi modules. + */ +void +lua_acpi_register_hook(void) +{ + if (acpi_is_initialized()) { + lua_acpi_register = lua_acpi_bindings; + } +} + +LUA_ACPI_COMPILE_SET(lacpi, luaopen_lacpi); diff --git a/stand/liblua/acpi/lacpi_data.c b/stand/liblua/acpi/lacpi_data.c new file mode 100644 index 00000000000000..399503da740f36 --- /dev/null +++ b/stand/liblua/acpi/lacpi_data.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include +#include "lacpi.h" +#include "lacpi_data.h" +#include "lacpi_utils.h" + +/* + * Dynamic dispatcher for destructor based on ACPI_OBJECT_TYPE. + * Do nothing in the case of integer-based ACPI_OBJECT_TYPES. + */ +acpi_destructor_t +get_object_destructor(UINT32 type) +{ + switch (type) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_LOCAL_REFERENCE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + return free_fake; + case ACPI_TYPE_STRING: + return free_str; + case ACPI_TYPE_BUFFER: + return free_buff; + case ACPI_TYPE_PACKAGE: + return free_pkg; + default: + return NULL; + } +} + +/* + * Attaching data requires providing a handler method. + */ +void +acpi_object_handler(ACPI_HANDLE handle, void *data) +{ + if (data != NULL) { + ACPI_OBJECT *obj = (ACPI_OBJECT *)data; + + acpi_destructor_t dtor = get_object_destructor(obj->Type); + if (dtor) { + dtor(obj); + } else { + free(obj); + obj = NULL; + } + } +} + +/* + * Create an ACPI_OBJECT to attach to a namespace node. + * Uses ACPI_OBJECT as an interface for building the data + * object. + * + * Lua stack expectations: + * 1 = ACPI_HANDLE - lightuserdata (opaque) handle of the node to attach the + * data onto + * 2..n = Argument table containing each field of an ACPI_OBJECT + * Example: lacpi.data.attach(handle, { Integer = 42 }) + * (see actypes.h for reference) + */ +static int +lAcpiAttachData(lua_State *L) +{ + ACPI_STATUS status; + ACPI_HANDLE handle; + UINT32 type; + ACPI_OBJECT *obj; + int obj_idx = 2; // start of ACPI_OBJECT parameters + + handle = lacpi_check_handle(L, 1); + if (handle == NULL) { + return lacpi_push_err(L, 0, "lAcpiAttachData: Handle is NULL. " + "Status: ", + AE_NULL_OBJECT); + } + + if (!lua_istable(L, 2)) { + return lacpi_push_err(L, 0, "lAcpiAttachData: Expected table. Status: ", + AE_TYPE); + } + + if (ACPI_FAILURE(status = lacpi_infer_type(L, 2, &type))) { + return lacpi_push_err(L, 0, + "Cannot infer ACPI_OBJECT_TYPE from table. Status: ", status); + } + + obj = calloc(1, sizeof(ACPI_OBJECT)); + if (obj == NULL) { + return lacpi_push_err(L, 0, + "lAcpiAttachData: Failed to malloc ACPI_OBJECT. Status: ", + AE_NULL_OBJECT); + } + + if (ACPI_FAILURE(status = build_acpi_obj(L, obj, type, obj_idx))) { + free_acpi_obj(obj); + free(obj); + return lacpi_push_err(L, 0, + "lAcpiAttachData: Failed to build ACPI_OBJECT. Status: ", + status); + } + + if (ACPI_FAILURE(status = AcpiAttachData(handle, acpi_object_handler, + (void *)obj))) { + free_acpi_obj(obj); + free(obj); + return lacpi_push_err(L, 0, + "lAcpiAttachData: AcpiAttachData failed with status: ", + status); + } + + lua_pushinteger(L, (lua_Integer)status); + return 1; +} + +/* + * Removes data from an ACPI node. + */ +static int +lAcpiDetachData(lua_State *L) +{ + ACPI_STATUS status; + ACPI_HANDLE handle = (ACPI_HANDLE) lua_touserdata(L, 1); + + if (handle == NULL) { + return lacpi_push_err(L, 1, "lAcpiDetachData: NULL Argument(s)", + AE_NULL_OBJECT); + } + + if (ACPI_FAILURE(status = AcpiDetachData(handle, + acpi_object_handler))) { + return lacpi_push_err(L, 1, + "lAcpiDetachData: AcpiDetachData failed with status: ", + status); + } + + lua_pushinteger(L, (lua_Integer)status); + return 1; +} + +/* + * Retrieves data from an ACPI node. + */ +static int +lAcpiGetData(lua_State *L) +{ + ACPI_STATUS status; + ACPI_HANDLE handle = (ACPI_HANDLE) lua_touserdata(L, 1); + void *data = NULL; + + if (handle == NULL) { + return lacpi_push_err(L, 1, "lAcpiGetData: NULL Argument(s). " + "Status: ", + AE_NULL_OBJECT); + } + + if (ACPI_FAILURE(status = AcpiGetData(handle, acpi_object_handler, + &data))) { + return lacpi_push_err(L, 1, + "lAcpiGetData: AcpiGetData failed with status: ", + status); + } + + push_acpi_obj(L, (ACPI_OBJECT *)data); + return 1; +} + +static const +luaL_Reg lacpi_data_funcs[] = { + { "attach", lAcpiAttachData }, + { "detach", lAcpiDetachData }, + { "get", lAcpiGetData }, + { NULL, NULL } +}; + +int +luaopen_lacpi_data(lua_State *L) +{ + luaL_newlib(L, lacpi_data_funcs); + return 1; +} + +void +lacpi_data_interp_ref(void) +{ +} diff --git a/stand/liblua/acpi/lacpi_object.c b/stand/liblua/acpi/lacpi_object.c new file mode 100644 index 00000000000000..6ca010302533cd --- /dev/null +++ b/stand/liblua/acpi/lacpi_object.c @@ -0,0 +1,194 @@ +#include "lacpi_utils.h" +#include "lacpi.h" +#include "lacpi_utils.h" +#include "lacpi.h" + +/* + * Retrieves opaque pointer (ACPI_HANDLE). + * + * A string containing a valid ACPI pathname must be on + * top of the Lua stack. + * Passes back an opaque pointer to lacpi_node object. + */ +static int +lAcpiGetHandle(lua_State *L) +{ + const char *pathname = luaL_checkstring(L, 1); + ACPI_HANDLE handle; + ACPI_STATUS status; + + if (ACPI_FAILURE(status = AcpiGetHandle(NULL, pathname, &handle))) { + return lacpi_push_err(L, 1, + "AcpiGetHandleFailed with status: ", status); + } + + lua_pushlightuserdata(L, handle); + return 1; +} + +/* + * Lua stack expectations: + * + * 1 = userdata ACPI handle ("lacpi_node") or nil + * 2 = relative pathname string from handle or nil + * 3 = absolute pathname string or nil + * 4 = optional table of ACPI objects (ACPI_OBJECT_LIST) to pass as arguments + * + * Either a handle (arg 1) or a pathname (arg 3) must be provided. + * Only if arg 1 is provided, arg 2 may also be provided, but not required. + * Any other arguments not being passed must be nil. + * + * Returns: ACPI object or table of ACPI objects. + */ +static int +lAcpiEvaluateObject(lua_State *L) +{ + ACPI_STATUS status; + char errmsg[128]; + ACPI_OBJECT_LIST obj_list; + ACPI_HANDLE handle = NULL; + ACPI_OBJECT *objs = NULL; + UINT32 obj_type = 0; + UINT32 obj_count = 0; + ACPI_BUFFER return_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + char *pathname = NULL; + + if (lua_isuserdata(L, 1)) { + handle = (ACPI_HANDLE)lua_touserdata(L, 1); + } + + const char *rel_path = lua_isstring(L, 2) ? lua_tostring(L, 2) : NULL; + const char *abs_path = lua_isstring(L, 3) ? lua_tostring(L, 3) : NULL; + + /* + * We must have either a handle and optionally a relative path, + * or just the absolute path. + */ + if (handle != NULL) { + // Optional + if (rel_path != NULL) { + pathname = strdup(rel_path); + } + } else if (abs_path != NULL) { + pathname = strdup(abs_path); + } else { + return lacpi_push_err(L, 1, "Incorrect arguments", 0); + } + + /* + * 4 is expected to be a table of ACPI_OBJECTs. + * These are passed when the method you are evaluating needs them. + * Each element of this table is converted into an ACPI_OBJECT. + * + * Each element of this table must be a table with: + * 1: obj_type -- UINT32 specifying the current element's + * ACPI_OBJECT_TYPE + * 2..n: fields -- used to build the corresponding + * ACPI_OBJECT, where n depends on obj_type. (see actypes.h) + * + */ + if (lua_istable(L, 4)) { + obj_count = lua_rawlen(L, 4); + objs = malloc(sizeof(ACPI_OBJECT) * obj_count); + if (objs == NULL) { + lua_pushnil(L); + lua_pushstring(L, "Failed to malloc objs."); + return 2; + } + + for (int i = 0; i < obj_count; ++i) { + lua_rawgeti(L, 4, i + 1); + int elem_idx = lua_gettop(L); + + lua_getfield(L, elem_idx, "Type"); + + if (ACPI_FAILURE(status = lacpi_int_to_uint32(L, -1, + &obj_type))) { + free_acpi_objs(&objs, i); + if (pathname != NULL) { + free(pathname); + pathname = NULL; + } + return lacpi_push_err(L, 1, + "ACPI_OBJECT_TYPE must be UINT32", 0); + } + lua_pop(L, 1); + + if (ACPI_FAILURE(status = + build_acpi_obj(L, &objs[i], obj_type, elem_idx))) { + free_acpi_objs(&objs, i); + snprintf(errmsg, sizeof(errmsg), + "Failed to build objs[%d]", i); + return lacpi_push_err(L, 1, errmsg, status); + } + lua_pop(L, 1); + } + + obj_list.Count = obj_count; + obj_list.Pointer = objs; + } else { + obj_list.Count = 0; + obj_list.Pointer = NULL; + } + + if (ACPI_FAILURE(status = AcpiEvaluateObject(handle, pathname, + (obj_list.Count > 0) ? &obj_list : NULL, &return_buffer))) { + if (return_buffer.Pointer != NULL) { + AcpiOsFree(return_buffer.Pointer); + } + + free_acpi_objs(&objs, obj_count); + + char errbuf[64]; + return lacpi_push_err(L, 1, + "AcpiEvaluateObject failed with status", status); + } + + if (return_buffer.Pointer != NULL) { + ACPI_OBJECT *ret_obj = (ACPI_OBJECT *)return_buffer.Pointer; + + if (ret_obj->Type == ACPI_TYPE_PACKAGE) { + lua_newtable(L); + for (UINT32 i = 0; i < ret_obj->Package.Count; ++i) { + push_acpi_obj(L, &ret_obj->Package.Elements[i]); + lua_rawseti(L, -2, i + 1); + } + } else { + push_acpi_obj(L, ret_obj); + } + + AcpiOsFree(return_buffer.Pointer); + } else { + lua_pushstring(L, "Success: No object returned"); + } + + if (objs != NULL) { + free_acpi_objs(&objs, obj_count); + } + + if (pathname != NULL) { + free(pathname); + pathname = NULL; + } + + return 1; +} + +static const +luaL_Reg lacpi_object_funcs[] = { + { "get_handle", lAcpiGetHandle }, + { "evaluate", lAcpiEvaluateObject }, + { NULL, NULL } +}; + +int +luaopen_lacpi_object(lua_State *L) +{ + luaL_newlib(L, lacpi_object_funcs); + return 1; +} + +void +lacpi_object_interp_ref(void) +{ +} diff --git a/stand/liblua/acpi/lacpi_utils.c b/stand/liblua/acpi/lacpi_utils.c new file mode 100644 index 00000000000000..daea554c02bf90 --- /dev/null +++ b/stand/liblua/acpi/lacpi_utils.c @@ -0,0 +1,615 @@ +#include +#include +#include +#include +#include "lacpi_utils.h" + +ACPI_STATUS build_acpi_obj(lua_State *L, ACPI_OBJECT *obj, UINT32 obj_type, int idx); +void push_acpi_obj(lua_State *L, ACPI_OBJECT *obj); +void free_acpi_obj(ACPI_OBJECT *obj); + +/***** UTILITY *****/ + +ACPI_HANDLE +lacpi_check_handle(lua_State *L, int idx) +{ + if (lua_islightuserdata(L, idx)) { + return (ACPI_HANDLE)lua_touserdata(L, idx); + } + + return NULL; +} + +int +lacpi_create_mt_gc(lua_State *L, const char *mt, lua_CFunction gc_func) +{ + if (luaL_newmetatable(L, mt)) { + lua_pushcfunction(L, gc_func); + lua_setfield(L, -2, "__gc"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + } + + return 1; +} + +ACPI_STATUS +lacpi_int_to_uint32(lua_State *L, int index, UINT32 *num) +{ + lua_Integer temp = luaL_checkinteger(L, index); + + if (temp < 0 || temp > UINT32_MAX) { + return AE_NUMERIC_OVERFLOW; + } + + *num = (UINT32)temp; + return AE_OK; +} + +ACPI_STATUS +lacpi_infer_type(lua_State *L, int idx, UINT32 *type) +{ + if (!lua_istable(L, idx)) { + return AE_TYPE; + } + + if (lua_getfield(L, idx, "Integer") != LUA_TNIL) { + *type = ACPI_TYPE_INTEGER; + } else if (lua_getfield(L, idx, "String") != LUA_TNIL) { + *type = ACPI_TYPE_STRING; + } else if (lua_getfield(L, idx, "Buffer") != LUA_TNIL) { + *type = ACPI_TYPE_BUFFER; + } else if (lua_getfield(L, idx, "Elements") != LUA_TNIL) { + *type = ACPI_TYPE_PACKAGE; + } else if (lua_getfield(L, idx, "Handle") != LUA_TNIL) { + *type = ACPI_TYPE_LOCAL_REFERENCE; + } else if (lua_getfield(L, idx, "ProcID") != LUA_TNIL) { + *type = ACPI_TYPE_PROCESSOR; + } else if (lua_getfield(L, idx, "SystemLevel") != LUA_TNIL) { + *type = ACPI_TYPE_POWER; + } else { + lua_pop(L, 1); + return AE_TYPE; + } + + return AE_OK; +} + +int +lacpi_push_err(lua_State *L, const int push_nil, const char *errmsg, + const ACPI_STATUS status) +{ + int stack = 0; + + if (push_nil) { + lua_pushnil(L); + ++stack; + } + + if (errmsg != NULL) { + lua_pushstring(L, errmsg); + ++stack; + + if (status > 0) { + char *status_msg = lacpi_extract_status(status); + lua_pushstring(L, status_msg); + ++stack; + } + } + + return stack; +} + +char * +lacpi_extract_status(const ACPI_STATUS status) +{ + switch (status) { + case AE_TYPE: + return "Unexpected type found"; + case AE_NULL_OBJECT: + return "Failed to allocate memory"; + case AE_NUMERIC_OVERFLOW: + return "Field on top of Lua stack was not UINT32"; + case AE_BAD_PARAMETER: + return "Failed string assignment off of lua stack"; + case AE_ERROR: + default: + return "Unexpected error"; + } +} + +/***** FACTORY *****/ + +/*** ACPI_OBJECT ***/ + +ACPI_STATUS +build_int(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + obj->Type = ACPI_TYPE_INTEGER; + + lua_getfield(L, idx, "Integer"); + if (!lua_isinteger(L, -1)) { + lua_pop(L, 1); + return AE_TYPE; + } + obj->Integer.Value = lua_tointeger(L, -1); + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_str(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + obj->Type = ACPI_TYPE_STRING; + + lua_getfield(L, idx, "String"); + if (!lua_isstring(L, -1)) { + lua_pop(L, 1); + return AE_TYPE; + } + size_t len; + const char *str = lua_tolstring(L, -1, &len); + if (str == NULL) { + lua_pop(L, 1); + return AE_BAD_PARAMETER; + } + + obj->String.Pointer = strdup((char *)str); + obj->String.Length = (UINT32)len; + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_buff(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + obj->Type = ACPI_TYPE_BUFFER; + + lua_getfield(L, idx, "Buffer"); + if (!lua_isstring(L, -1)) { + lua_pop(L, 1); + return AE_TYPE; + } + size_t len; + const char *str = lua_tolstring(L, -1, &len); + if (str == NULL) { + lua_pop(L, 1); + return AE_BAD_PARAMETER; + } + obj->Buffer.Pointer = strdup((char *)str); + if (obj->Buffer.Pointer == NULL) { + lua_pop(L, 1); + return AE_NULL_OBJECT; + } + obj->Buffer.Length = (UINT32)len; + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_pkg(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + ACPI_STATUS status; + obj->Type = ACPI_TYPE_PACKAGE; + + lua_getfield(L, idx, "Elements"); + int ele_idx = lua_gettop(L); + + obj->Package.Count = lua_rawlen(L, ele_idx); + if (obj->Package.Count == 0) { + obj->Package.Elements = NULL; + lua_pop(L, 1); + return AE_OK; + } + obj->Package.Elements = calloc(obj->Package.Count, + sizeof(ACPI_OBJECT)); + if (obj->Package.Elements == NULL) { + lua_pop(L, 1); + return AE_NO_MEMORY; + } + for (UINT32 i = 0; i < obj->Package.Count; ++i) { + lua_rawgeti(L, ele_idx, i + 1); + int curr_idx = lua_gettop(L); + + lua_getfield(L, curr_idx, "Type"); + + UINT32 obj_type; + if (ACPI_FAILURE(lacpi_int_to_uint32(L, -1, &obj_type))) { + lua_pop(L, 2); + free_acpi_objs(&obj->Package.Elements, i); + return AE_NUMERIC_OVERFLOW; + } + lua_pop(L, 1); + + if (ACPI_FAILURE(status = build_acpi_obj(L, + &obj->Package.Elements[i], obj_type, curr_idx))) { + lua_pop(L, 1); + free_acpi_objs(&obj->Package.Elements, i); + return status; + } + lua_pop(L, 1); + } + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_ref(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + obj->Type = ACPI_TYPE_LOCAL_REFERENCE; + + lua_getfield(L, idx, "ActualType"); + if (ACPI_FAILURE(lacpi_int_to_uint32(L, -1, + &obj->Reference.ActualType))) { + lua_pop(L, 1); + return AE_NUMERIC_OVERFLOW; + } + lua_pop(L, 1); + + lua_getfield(L, idx, "Handle"); + if (!lua_isuserdata(L, -1)) { + lua_pop(L, 1); + return AE_TYPE; + } + ACPI_HANDLE handle = *(ACPI_HANDLE *)luaL_checkudata(L, -1, + "lacpi_node"); + obj->Reference.Handle = handle; + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_proc(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + obj->Type = ACPI_TYPE_PROCESSOR; + + lua_getfield(L, idx, "ProcID"); + if (ACPI_FAILURE(lacpi_int_to_uint32(L, -1, &obj->Processor.ProcId))) { + lua_pop(L, 1); + return AE_NUMERIC_OVERFLOW; + } + lua_pop(L, 1); + + lua_getfield(L, idx, "PblkAddress"); + if (!lua_isinteger(L, -1)) { + lua_pop(L, 1); + return AE_TYPE; + } + obj->Processor.PblkAddress = (ACPI_IO_ADDRESS)lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, idx, "PblkLength"); + if (ACPI_FAILURE(lacpi_int_to_uint32(L, -1, + &obj->Processor.PblkLength))) { + lua_pop(L, 1); + return AE_TYPE; + } + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_pow(lua_State *L, ACPI_OBJECT *obj, int idx) +{ + idx = lua_absindex(L, idx); + obj->Type = ACPI_TYPE_POWER; + + lua_getfield(L, idx, "SystemLevel"); + if (ACPI_FAILURE(lacpi_int_to_uint32(L, -1, + &obj->PowerResource.SystemLevel))) { + lua_pop(L, 1); + return AE_TYPE; + } + lua_pop(L, 1); + + lua_getfield(L, idx, "ResourceOrder"); + if (ACPI_FAILURE(lacpi_int_to_uint32(L, -1, + &obj->PowerResource.ResourceOrder))) { + lua_pop(L, 1); + return AE_TYPE; + } + lua_pop(L, 1); + + return AE_OK; +} + +ACPI_STATUS +build_acpi_obj(lua_State *L, ACPI_OBJECT *obj, const UINT32 obj_type, int idx) +{ + switch(obj_type) { + case ACPI_TYPE_INTEGER: + return build_int(L, obj, idx); + case ACPI_TYPE_STRING: + return build_str(L, obj, idx); + case ACPI_TYPE_BUFFER: + return build_buff(L, obj, idx); + case ACPI_TYPE_PACKAGE: + return build_pkg(L, obj, idx); + case ACPI_TYPE_LOCAL_REFERENCE: + return build_ref(L, obj, idx); + case ACPI_TYPE_PROCESSOR: + return build_proc(L, obj, idx); + case ACPI_TYPE_POWER: + return build_pow(L, obj, idx); + default: + return AE_ERROR; + } +} + +void +push_int(lua_State *L, ACPI_OBJECT *obj) +{ + lua_pushinteger(L, obj->Integer.Value); +} + +void +push_str(lua_State *L, ACPI_OBJECT *obj) +{ + lua_pushlstring(L, obj->String.Pointer, obj->String.Length); +} + +void +push_buff(lua_State *L, ACPI_OBJECT *obj) +{ + lua_pushlstring(L, (const char*)obj->Buffer.Pointer, + obj->Buffer.Length); +} + +void +push_pkg(lua_State *L, ACPI_OBJECT *obj) +{ + lua_newtable(L); + for (UINT32 i = 0; i < obj->Package.Count; ++i) { + push_acpi_obj(L, &obj->Package.Elements[i]); + lua_rawseti(L, -2, i + 1); + } +} + +void +push_ref(lua_State *L, ACPI_OBJECT *obj) +{ + lua_newtable(L); + + lua_pushinteger(L, obj->Reference.ActualType); + lua_setfield(L, -2, "ActualType"); + + ACPI_HANDLE *handle = (ACPI_HANDLE *)lua_newuserdata(L, sizeof(ACPI_HANDLE)); + *handle = obj->Reference.Handle; + luaL_setmetatable(L, "lacpi_node"); + lua_setfield(L, -2, "Handle"); +} + +void +push_proc(lua_State *L, ACPI_OBJECT *obj) +{ + lua_newtable(L); + + lua_pushinteger(L, obj->Processor.ProcId); + lua_setfield(L, -2, "ProcId"); + + lua_pushinteger(L, (lua_Integer)obj->Processor.PblkAddress); + lua_setfield(L, -2, "PblkAddress"); + + lua_pushinteger(L, obj->Processor.PblkLength); + lua_setfield(L, -2, "PblkLength"); +} + +void +push_pow(lua_State *L, ACPI_OBJECT *obj) +{ + lua_newtable(L); + + lua_pushinteger(L, obj->PowerResource.SystemLevel); + lua_setfield(L, -2, "SystemLevel"); + + lua_pushinteger(L, obj->PowerResource.ResourceOrder); + lua_setfield(L, -2, "ResourceOrder"); +} + +void +push_acpi_obj(lua_State *L, ACPI_OBJECT *obj) +{ + switch (obj->Type) { + case ACPI_TYPE_INTEGER: + push_int(L, obj); + break; + case ACPI_TYPE_STRING: + push_str(L, obj); + break; + case ACPI_TYPE_BUFFER: + push_buff(L, obj); + break; + case ACPI_TYPE_PACKAGE: + push_pkg(L, obj); + break; + case ACPI_TYPE_LOCAL_REFERENCE: + push_ref(L, obj); + break; + case ACPI_TYPE_PROCESSOR: + push_proc(L, obj); + break; + case ACPI_TYPE_POWER: + push_pow(L, obj); + break; + default: + luaL_error(L, "Unable to push obj: %d.", obj->Type); + } +} + +/* + * Keeps compiler happy during acpi_object_handler + */ +void +free_fake(ACPI_OBJECT *obj) +{ + /* No-op */ +} + +void +free_str(ACPI_OBJECT *obj) +{ + if (obj->String.Pointer) { + free(obj->String.Pointer); + obj->String.Pointer = NULL; + } + + obj->String.Length = 0; +} + +void +free_buff(ACPI_OBJECT *obj) +{ + if (obj->Buffer.Pointer) { + free(obj->Buffer.Pointer); + obj->Buffer.Pointer = NULL; + } + + obj->Buffer.Length = 0; +} + +void +free_pkg(ACPI_OBJECT *obj) +{ + for (UINT32 i = 0; i < obj->Package.Count; ++i) { + free_acpi_obj(&obj->Package.Elements[i]); + } + + free(obj->Package.Elements); + obj->Package.Elements = NULL; + obj->Package.Count = 0; +} + +void +free_acpi_obj(ACPI_OBJECT *obj) +{ + if (obj) { + switch (obj->Type) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_LOCAL_REFERENCE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + free_fake(obj); + break; + case ACPI_TYPE_STRING: + free_str(obj); + break; + case ACPI_TYPE_BUFFER: + free_buff(obj); + break; + case ACPI_TYPE_PACKAGE: + free_pkg(obj); + break; + default: + assert(obj == NULL); + break; + } + } +} + +void +free_acpi_objs(ACPI_OBJECT **objs, UINT32 init_count) +{ + if (*objs) { + for (UINT32 i = 0; i < init_count; ++i) { + free_acpi_obj(&(*objs)[i]); + } + + free(*objs); + *objs = NULL; + } +} + +/*** ACPI Namespace Node ***/ + +/* + * Creates a key, value pair for the path of the current + * namespace node. + */ +void +push_path(struct context *curr_ctx, const char *path) +{ + lua_pushstring(curr_ctx->L, "path"); + lua_pushstring(curr_ctx->L, path); + lua_settable(curr_ctx->L, -3); +} + +/* + * Creates a key, value pair for the level of the current + * namespace node. + */ +void +push_level(struct context *curr_ctx, UINT32 level) +{ + lua_pushstring(curr_ctx->L, "level"); + lua_pushinteger(curr_ctx->L, level); + lua_settable(curr_ctx->L, -3); +} + +/* + * Creates a key, value pair for the hid of the current + * namespace node. + */ +void +push_hid(struct context *curr_ctx, const char *hid) +{ + lua_pushstring(curr_ctx->L, "HID"); + lua_pushstring(curr_ctx->L, hid); + lua_settable(curr_ctx->L, -3); +} + +/* + * Creates a key, value pair for the uid of the current + * namespace node. + */ +void +push_uid(struct context *curr_ctx, const char *uid) +{ + lua_pushstring(curr_ctx->L, "UID"); + lua_pushstring(curr_ctx->L, uid); + lua_settable(curr_ctx->L, -3); +} + +/* + * Generates a Lua table for the current namespace node and + * sets it into our root table. + */ +void +push_node(struct context *curr_ctx, const char *path, UINT32 level, + ACPI_HANDLE handle) +{ + if (path != NULL) { + lua_newtable(curr_ctx->L); + + push_path(curr_ctx, path); + push_level(curr_ctx, level); + + ACPI_DEVICE_INFO *info = NULL; + if (ACPI_SUCCESS(AcpiGetObjectInfo(handle, &info))) { + if (info->Valid & ACPI_VALID_HID) { + push_hid(curr_ctx, info->HardwareId.String); + } + + if (info->Valid & ACPI_VALID_UID) { + push_uid(curr_ctx, info->UniqueId.String); + } + + ACPI_FREE(info); + } + + lua_rawseti(curr_ctx->L, curr_ctx->tbl, curr_ctx->idx); + curr_ctx->idx++; + } +} diff --git a/stand/liblua/acpi/lacpi_walk.c b/stand/liblua/acpi/lacpi_walk.c new file mode 100644 index 00000000000000..4c8bff741de23c --- /dev/null +++ b/stand/liblua/acpi/lacpi_walk.c @@ -0,0 +1,79 @@ +#include +#include +#include "lacpi_utils.h" +#include "lacpi_object.h" +#include "lacpi_walk.h" + +static ACPI_STATUS +lua_dump_acpi_namespace(ACPI_HANDLE handle, UINT32 level, void *ctx, + void **retval) +{ + struct context *curr_ctx = (struct context *)ctx; + ACPI_BUFFER path = { ACPI_ALLOCATE_BUFFER, NULL }; + + if (ACPI_FAILURE(AcpiGetName(handle, ACPI_FULL_PATHNAME, &path))) { + // XXX Continue anyway? + return AE_OK; + } + + push_node(curr_ctx, (char *)path.Pointer, level, handle); + + ACPI_FREE(path.Pointer); + return AE_OK; +} + +/* + * WIP: Currently hard coded to just walk the entire tree. + * Need to reiterate on this with strategy pattern once + * I have tested this works. + * + * Needed strategies: + * - User ability to define ACPI_OBJECT_TYPE + * - DescendingCallback function hooks + * - AscendingCallback function hooks + */ +static int +lAcpiWalkNamespace(lua_State *L) +{ + ACPI_STATUS status; + ACPI_HANDLE handle = ACPI_ROOT_OBJECT; + + /* If user does not want to provide a handle, we start at root. */ + if (lua_gettop(L) < 1 || lua_isnil(L, 1)) { + handle = ACPI_ROOT_OBJECT; + } else { + handle = lacpi_check_handle(L, 1); + if (handle == NULL) { + return lacpi_push_err(L, 1, "Invalid ACPI handle", 0); + } + } + + lua_newtable(L); + /* ctx->tbl == -2 because in push_node we add a table */ + struct context ctx = { L, -2, 1 }; + + if (ACPI_FAILURE(status = AcpiWalkNamespace(ACPI_TYPE_ANY, handle, + ACPI_UINT32_MAX, lua_dump_acpi_namespace, NULL, &ctx, NULL))) { + return lacpi_push_err(L, 1, "Failed to walk ACPI namespace", status); + } + + return 1; +} + +static const +luaL_Reg lacpi_walk_funcs[] = { + { "namespace", lAcpiWalkNamespace }, + { NULL, NULL } +}; + +int +luaopen_lacpi_walk(lua_State *L) +{ + luaL_newlib(L, lacpi_walk_funcs); + return 1; +} + +void +lacpi_walk_interp_ref(void) +{ +} diff --git a/stand/liblua/lutils.c b/stand/liblua/lutils.c index 874dc8bf7d5db2..bd567fef8fd74e 100644 --- a/stand/liblua/lutils.c +++ b/stand/liblua/lutils.c @@ -33,6 +33,11 @@ #include "lutils.h" #include "bootstrap.h" +#include +#include + +lua_acpi_registration_fn lua_acpi_register = NULL; + /* * Like loader.perform, except args are passed already parsed * on the stack. @@ -443,6 +448,18 @@ lua_add_features(lua_State *L) lua_setfield(L, -2, "features"); } +void +register_lacpi_modules(lua_State *L) +{ + if (lua_acpi_register == NULL) { + lua_acpi_register_hook(); + } + + if (lua_acpi_register != NULL) { + lua_acpi_register(L); + } +} + int luaopen_loader(lua_State *L) { @@ -469,6 +486,12 @@ luaopen_loader(lua_State *L) lua_add_features(L); /* Set global printc to loader.printc */ lua_register(L, "printc", lua_printc); + +#if defined(__amd64__) + // ACPICA Bindings + register_lacpi_modules(L); +#endif + return 1; } diff --git a/stand/liblua/lutils.h b/stand/liblua/lutils.h index 7fff8d3ae83dee..2252f34fd3b485 100644 --- a/stand/liblua/lutils.h +++ b/stand/liblua/lutils.h @@ -34,6 +34,8 @@ int luaopen_pager(lua_State *); #include typedef void lua_init_md_t(lua_State *); +typedef void(*lua_acpi_registration_fn)(lua_State *L); +extern lua_acpi_registration_fn lua_acpi_register; #define _LUA_COMPILE_SET Xlua_compile_set #define LUA_COMPILE_SET(func) \ DATA_SET(_LUA_COMPILE_SET, func) diff --git a/stand/lua/Makefile b/stand/lua/Makefile index d319261e18b28f..e2f16a9d2f0398 100644 --- a/stand/lua/Makefile +++ b/stand/lua/Makefile @@ -11,7 +11,8 @@ MAN= loader.conf.lua.5 \ loader.lua.8 \ menu.lua.8 \ password.lua.8 \ - screen.lua.8 + screen.lua.8 \ + acpi.lua.8 FILESDIR= ${LUAPATH} FILES= cli.lua \ From a53ebc21f63ced0e4c5a1812f04bd5d977014a7b Mon Sep 17 00:00:00 2001 From: kpowkitty Date: Sun, 28 Sep 2025 19:11:53 -0700 Subject: [PATCH 5/5] lacpi: Create man page --- stand/lua/acpi.lua.8 | 182 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 stand/lua/acpi.lua.8 diff --git a/stand/lua/acpi.lua.8 b/stand/lua/acpi.lua.8 new file mode 100644 index 00000000000000..9213690d5b83c6 --- /dev/null +++ b/stand/lua/acpi.lua.8 @@ -0,0 +1,182 @@ +.\" +.\" Copyright (c) 2025 Google Summer of Code +.\" +.\" SPDX-License-Identifier: BSD-2-Clause(XXX?) +.\" +.Dd September 28, 2025 +.Dt ACPI.LUA 8 +.Os +.Sh NAME +.Nm acpi.lua +.Nd ACPI Lua binding module +.Sh DESCRIPTION +The ACPI Lua bindings are for utilizing ACPICA +functionality pre-kernel. They are only available to the +.Fx +Lua bootloader, via the +.Ic loader +table, and require +.Ic amd64 +architecture. See +.Xr loader.lua 8 +for more information on the loader table. +.Pp +These bindings are in the +.Ic lacpi +namespace, and are divided between three modules: +.Bl -tag -width 0n +.It Sy walk +The +.Ic walk +module is for walking the ACPI namespace under user specified +callbacks and passing the information back to the interpreter +through the Lua stack. Currently, users can walk the entire +namespace or start the walk at a user specified +.Ic handle . +There is currently only one callback, and it retrieves the +following into a Lua table. +.Bl -tag -width 0n +.It Sy pathname +The full pathname of the current device node +.It level +The level of the current device node +.It hid +If applicable, the HID of the current device node +.It uid +If applicable, the UID of the current device node +.El +.It Sy object +The +.Ic object +module is for evaluating ACPI objects. It provides +the ability to +.Bl -tag -width 0n +.It Fn get_handle pathname +Converts a +.Va pathname +to its corresponding +.Ic opaque pointer . +.It Fn evaluate handle abs_path rel_path args +Evaluates an ACPI object. The arguments are: +.Bl -enum +.It +The handle of the node. +.It +The relative pathname to the handle. Optional, and only +provided if the handle is being provided. +.It +An absolute pathname. +.It +An +.Va OBJECT_LIST +for the specified objects +.El +.Pp +This submodule takes either: +.Bl -bullet +.It +A handle, with an optional relative pathname, plus an +optional OBJECT_LIST. +.It +An absolute pathname, plus an optional OBJECT_LIST +.El +.El +.It Sy data +The +.Ic data +module allows users to manipulate data on namespace +nodes. The interface currently provides the abilities: +.Bl -tag -width 0n +.It Fn attach handle ACPI_OBJECT +Attach data onto a namespace node +.It Fn detach handle +Detach data from a namespace node +.It Fn get handle +Get data off of a namespace node +.El +.El +.Sh NOTES +The Lua stack expectations for all places that an ACPI_OBJECT +is required to be passed over is the same ordering as the +ACPI_OBJECT structures are defined. Please see +.Em actypes.h +for reference. In general, the arguments are passed as: +.Bl -enum +.It +Type = ACPI_TYPE_INTEGER +.It +ACPI_OBJECT_TYPE = OBJECT +.El +.Pp +Some examples for passing various ACPI_OBJECTs: +.Bd -literal +args = {{ Type = 1, Integer = 42 }, + { Type = 2, String = "Tis but a scratch"}, + { Type = 3, Buffer = "You liar!"}} +.Ed +.Sh EXIT STATUS +The exit status varies depending on module, and can either +return ACPI_STATUS to tell Lua it successfully completed +its request or send back a table with the information +that Lua requested. +.Pp +On the case of an error, the interface will +provide up to three (optional) arguments: +.Bl -tag -width 0n +.It Sy nil +To specify a fault +.It Sy message +Programmed message depending on the fault. +.It Sy status +.Ic ACPI_STATUS +message translated to user friendly text. +.El +.Sh EXAMPLES +.Bd -literal +.Sy Retrieving a handle + handle = lacpi.object.get_handle("\\\\_SB_.CPUS.C000") +.Ed +.Pp +.Bd -literal +.Sy Evaluating an object + eval = lacpi.object.evaluate(handle, "_STA", nil, nil) + print(eval) + 15 +.Ed +.Pp +.Bd -literal +.Sy Evaluating an object with arguments + handle = lacpi.object.get_handle("\\\\_SB_.DMY0") + args = {{Type = 1, Integer = 42}} + eval = lacpi.object.evaluate(handle, "ECHO", nil, args) + print(eval) + 42 +.Ed +.Pp +.Bd -literal +.Sy Attaching data onto a namespace node + f, msg, status = lacpi.data.attach(handle, {Integer = 42}) + print(f) + 0 +.Ed +.Pp +.Bd -literal +.Sy Retrieving data from a namespace node + f, msg, status = lacpi.data.get(handle) + print(f) + 42 +.Ed +.Pp +.Bd -literal +.Sy Detaching data from a namespace node + f, msg, status = lacpi.data.detach(handle) + print(f) + 0 +.Ed +.Sh SEE ALSO +.Xr loader.lua 8 +.Sh AUTHORS +The +.Nm +man page was written by +.An Kayla Powell (AKA Kat) Aq Mt kpowkitty@FreeBSD.org .