/** @file Copyright (c) 2020-2021, Ubsefor & koralexa. All rights reserved. SPDX-License-Identifier: BSD-3-Clause **/ #ifndef ACPI_PARSER_H #define ACPI_PARSER_H typedef struct { /// /// Currently processed opcode in ACPI table. /// UINT8 *CurrentOpcode; /// /// Pointer to the end of ACPI table. /// UINT8 *TableStart; /// /// Pointer to the end of ACPI table. /// UINT8 *TableEnd; /// /// Decoded lookup path allocated from pool. /// Contains a sequence of parsed identifiers. /// UINT32 *PathStart; /// /// Identifier we need to match next. /// Once it reaches PathEnd, matching is successful. /// Requested number of matches is required to finish lookup. /// UINT32 *CurrentIdentifier; /// /// Pointer to the end of lookup path. /// UINT32 *PathEnd; /// /// Nesting level. Once it reaches MAX_NESTING the table is discarded. /// UINT32 Nesting; /// /// Number of entries to find. Generally 1 for first match success. /// UINT32 RequiredEntry; /// /// Number of entries already found. /// UINT32 EntriesFound; } ACPI_PARSER_CONTEXT; #define IDENT_LEN 4 #define OPCODE_LEN 8 #define MAX_NESTING 1024 /** Print new entry name. **/ #define CONTEXT_ENTER(Context, Name) \ DEBUG (( \ DEBUG_VERBOSE, \ "%a 0x%x (looking for %c%c%c%c)\n", \ (Name), \ (UINT32) ((Context)->CurrentOpcode - (Context)->TableStart), \ ((CHAR8 *) (Context)->CurrentIdentifier)[3], \ ((CHAR8 *) (Context)->CurrentIdentifier)[2], \ ((CHAR8 *) (Context)->CurrentIdentifier)[1], \ ((CHAR8 *) (Context)->CurrentIdentifier)[0] \ )); #define PRINT_ACPI_NAME(Str, Name, Length) \ DEBUG (( \ DEBUG_VERBOSE, \ "%a %u (%c%c%c%c)\n", \ (Str), \ (Length), \ (Length) > 0 ? (Name)[((Length) - 1) * 4 + 0] : 'Z', \ (Length) > 0 ? (Name)[((Length) - 1) * 4 + 1] : 'Z', \ (Length) > 0 ? (Name)[((Length) - 1) * 4 + 2] : 'Z', \ (Length) > 0 ? (Name)[((Length) - 1) * 4 + 3] : 'Z' \ )); /** Check that context is valid and has work to do. **/ #define CONTEXT_HAS_WORK(Context) do {\ ASSERT ((Context) != NULL); \ ASSERT ((Context)->CurrentOpcode != NULL); \ ASSERT ((Context)->TableEnd != NULL); \ ASSERT ((Context)->CurrentOpcode < (Context)->TableEnd); /* Must always have work to do. */ \ ASSERT ((Context)->PathStart != NULL); \ ASSERT ((Context)->PathEnd != NULL); \ ASSERT ((Context)->CurrentIdentifier != NULL); \ ASSERT ((Context)->CurrentIdentifier < (Context)->PathEnd); /* Must always have IDs to parse. */ \ ASSERT ((Context)->RequiredEntry > 0); \ ASSERT ((Context)->EntriesFound < (Context)->RequiredEntry); /* Must have entries to find. */ \ } while (0) /** Enter new nesting level. **/ #define CONTEXT_INCREASE_NESTING(Context) do {\ ++(Context)->Nesting; \ if ((Context)->Nesting > MAX_NESTING) { \ return EFI_OUT_OF_RESOURCES; \ } \ } while (0) /** Exit nesting level. Does not need to be called on error-exit. **/ #define CONTEXT_DECREASE_NESTING(Context) do {\ ASSERT ((Context)->Nesting > 0); \ --(Context)->Nesting; \ } while (0) /** Check the specified amount of bytes exists. **/ #define CONTEXT_PEEK_BYTES(Context, Bytes) do {\ if ((UINT32) ((Context)->TableEnd - (Context)->CurrentOpcode) < (UINT32) (Bytes)) { \ return EFI_DEVICE_ERROR; \ } \ } while (0) /** Consume the specified amount of bytes. **/ #define CONTEXT_CONSUME_BYTES(Context, Bytes) do {\ if ((UINT32) ((Context)->TableEnd - (Context)->CurrentOpcode) < (UINT32) (Bytes)) { \ return EFI_DEVICE_ERROR; \ } \ (Context)->CurrentOpcode += (Bytes); \ } while (0) /** Advance opcode to call the new parsing code. This one will error as long as there is no new opcode, i.e. one byte after the current one. **/ #define CONTEXT_ADVANCE_OPCODE(Context) do {\ if ((UINT32) ((Context)->TableEnd - (Context)->CurrentOpcode) <= 1U) { \ return EFI_DEVICE_ERROR; \ } \ ++(Context)->CurrentOpcode; \ } while (0) /** Determines which object to parse (depending on the opcode) and calls the corresponding parser function. @param[in, out] Context Structure containing the parser context. @param[out] Result Pointer to sought opcode if required entry was found. @retval EFI_SUCCESS Required entry was found (search complete). @retval EFI_NOT_FOUND Required entry was not found (more terms need to be parsed). @retval EFI_DEVICE_ERROR Error occured during parsing (must abort). @retval EFI_OUT_OF_RESOURCES Nesting limit has been reached (must abort). **/ EFI_STATUS InternalAcpiParseTerm ( IN OUT ACPI_PARSER_CONTEXT *Context, OUT UINT8 **Result ); #endif // ACPI_PARSER_H