From d77cc6694875d9c5d373323fcde46d7eab5fd333 Mon Sep 17 00:00:00 2001 From: Filiprogrammer <44641787+Filiprogrammer@users.noreply.github.com> Date: Wed, 26 Jul 2023 22:11:17 +0200 Subject: [PATCH] Update the tools and make them buildable Update the tools for building, running and debugging ChaOS. Provide source code and build instructions for these tools. This way the codebase no longer depends on pre-built binaries. --- .github/workflows/main.yml | 175 +- .gitignore | 10 +- .vscode/launch.json | 16 +- .vscode/tasks.json | 16 +- BUILD_IMAGE.BAT | 3 +- DOWNLOAD_TOOLS.BAT | 9 - QEMU_BOOT.BAT | 8 +- README.md | 53 +- SET_ENV_VARS.BAT | 4 +- build_image.sh | 5 +- download_tools.sh | 9 - gdb_heap_gui.py | 21 +- gdb_tasks_gui.py | 47 +- qemu_boot.sh | 23 +- set_env_vars.sh | 18 +- tools/Trim | 5 + tools/Trim.bat | 2 + tools/bios32.bin | Bin 0 -> 2097152 bytes tools/python/Common/BuildToolError.py | 158 + tools/python/Common/BuildVersion.py | 10 + tools/python/Common/DataType.py | 535 +++ tools/python/Common/EdkLogger.py | 383 ++ tools/python/Common/GlobalData.py | 132 + tools/python/Common/LongFilePathOs.py | 79 + tools/python/Common/LongFilePathOsPath.py | 47 + tools/python/Common/LongFilePathSupport.py | 45 + tools/python/Common/Misc.py | 1926 ++++++++++ tools/python/Common/MultipleWorkspace.py | 150 + tools/python/Common/Parsing.py | 906 +++++ tools/python/Common/StringUtils.py | 873 +++++ tools/python/Common/__init__.py | 9 + tools/python/Common/caching.py | 41 + tools/python/CommonDataClass/DataClass.py | 369 ++ tools/python/CommonDataClass/Exceptions.py | 23 + tools/python/CommonDataClass/__init__.py | 9 + tools/python/Trim/Trim.py | 551 +++ tools/src/GenFw/Common/build-win.sh | 15 + tools/src/GenFw/Common/build.sh | 15 + tools/src/GenFw/Common/clean.sh | 6 + tools/src/GenFw/Common/src/BasePeCoff.c | 1417 +++++++ tools/src/GenFw/Common/src/BinderFuncs.c | 74 + tools/src/GenFw/Common/src/BinderFuncs.h | 61 + tools/src/GenFw/Common/src/CommonLib.c | 2091 +++++++++++ tools/src/GenFw/Common/src/CommonLib.h | 471 +++ tools/src/GenFw/Common/src/Compress.h | 67 + tools/src/GenFw/Common/src/Crc32.c | 305 ++ tools/src/GenFw/Common/src/Crc32.h | 33 + tools/src/GenFw/Common/src/Decompress.c | 903 +++++ tools/src/GenFw/Common/src/Decompress.h | 135 + tools/src/GenFw/Common/src/EfiCompress.c | 1407 +++++++ tools/src/GenFw/Common/src/EfiUtilityMsgs.c | 788 ++++ tools/src/GenFw/Common/src/EfiUtilityMsgs.h | 164 + .../GenFw/Common/src/FirmwareVolumeBuffer.c | 1518 ++++++++ .../Common/src/FirmwareVolumeBufferLib.h | 163 + tools/src/GenFw/Common/src/FvLib.c | 828 +++++ tools/src/GenFw/Common/src/FvLib.h | 189 + tools/src/GenFw/Common/src/MemoryFile.c | 225 ++ tools/src/GenFw/Common/src/MemoryFile.h | 79 + tools/src/GenFw/Common/src/MyAlloc.c | 489 +++ tools/src/GenFw/Common/src/MyAlloc.h | 163 + tools/src/GenFw/Common/src/OsPath.c | 264 ++ tools/src/GenFw/Common/src/OsPath.h | 97 + .../Common/src/ParseGuidedSectionTools.c | 179 + .../Common/src/ParseGuidedSectionTools.h | 87 + tools/src/GenFw/Common/src/ParseInf.c | 640 ++++ tools/src/GenFw/Common/src/ParseInf.h | 164 + tools/src/GenFw/Common/src/PcdValueCommon.c | 678 ++++ tools/src/GenFw/Common/src/PcdValueCommon.h | 137 + tools/src/GenFw/Common/src/PeCoffLib.h | 213 ++ tools/src/GenFw/Common/src/PeCoffLoaderEx.c | 391 ++ .../src/GenFw/Common/src/SimpleFileParsing.c | 1323 +++++++ .../src/GenFw/Common/src/SimpleFileParsing.h | 104 + tools/src/GenFw/Common/src/StringFuncs.c | 327 ++ tools/src/GenFw/Common/src/StringFuncs.h | 167 + tools/src/GenFw/Common/src/TianoCompress.c | 1558 ++++++++ tools/src/GenFw/GenFw/build-win.sh | 15 + tools/src/GenFw/GenFw/build.sh | 15 + tools/src/GenFw/GenFw/clean.sh | 7 + tools/src/GenFw/GenFw/src/Elf32Convert.c | 1170 ++++++ tools/src/GenFw/GenFw/src/Elf32Convert.h | 19 + tools/src/GenFw/GenFw/src/Elf64Convert.c | 2392 ++++++++++++ tools/src/GenFw/GenFw/src/Elf64Convert.h | 19 + tools/src/GenFw/GenFw/src/ElfConvert.c | 251 ++ tools/src/GenFw/GenFw/src/ElfConvert.h | 122 + tools/src/GenFw/GenFw/src/GenFw.c | 3262 +++++++++++++++++ tools/src/GenFw/GenFw/src/GenFw.h | 50 + tools/src/GenFw/GenFw/src/elf32.h | 252 ++ tools/src/GenFw/GenFw/src/elf64.h | 254 ++ tools/src/GenFw/GenFw/src/elf_common.h | 1148 ++++++ tools/src/GenFw/Include/Common/BaseTypes.h | 310 ++ tools/src/GenFw/Include/Common/BuildVersion.h | 9 + .../src/GenFw/Include/Common/PiFirmwareFile.h | 350 ++ .../GenFw/Include/Common/PiFirmwareVolume.h | 157 + .../src/GenFw/Include/Common/UefiBaseTypes.h | 168 + .../Common/UefiInternalFormRepresentation.h | 1680 +++++++++ .../MdePkg/Include/IndustryStandard/Acpi.h | 17 + .../MdePkg/Include/IndustryStandard/Acpi10.h | 666 ++++ .../MdePkg/Include/IndustryStandard/Acpi20.h | 539 +++ .../MdePkg/Include/IndustryStandard/Acpi30.h | 723 ++++ .../MdePkg/Include/IndustryStandard/Acpi40.h | 1304 +++++++ .../MdePkg/Include/IndustryStandard/Acpi50.h | 2120 +++++++++++ .../MdePkg/Include/IndustryStandard/Acpi51.h | 2145 +++++++++++ .../MdePkg/Include/IndustryStandard/Acpi60.h | 2398 ++++++++++++ .../MdePkg/Include/IndustryStandard/Acpi61.h | 2430 ++++++++++++ .../MdePkg/Include/IndustryStandard/Acpi62.h | 2983 +++++++++++++++ .../MdePkg/Include/IndustryStandard/Acpi63.h | 2983 +++++++++++++++ .../MdePkg/Include/IndustryStandard/Acpi64.h | 3162 ++++++++++++++++ .../MdePkg/Include/IndustryStandard/Acpi65.h | 3256 ++++++++++++++++ .../MdePkg/Include/IndustryStandard/AcpiAml.h | 184 + ...emoryMappedConfigurationSpaceAccessTable.h | 49 + .../MdePkg/Include/IndustryStandard/PeImage.h | 806 ++++ .../GenFw/MdePkg/Include/X64/ProcessorBind.h | 319 ++ tools/src/GenFw/build-win.sh | 21 + tools/src/GenFw/build.sh | 21 + tools/src/GenFw/clean.sh | 6 + tools/src/build-i686-elf-tools-win.sh | 47 + tools/src/build-i686-elf-tools.sh | 34 + tools/src/imgtools/build-win.sh | 15 + tools/src/imgtools/build.sh | 15 + tools/src/imgtools/clean.sh | 5 + tools/src/imgtools/src/fat.c | 2912 +++++++++++++++ tools/src/imgtools/src/fat.h | 53 + tools/src/imgtools/src/fileManager.h | 15 + tools/src/imgtools/src/imgtools.c | 203 + tools/src/imgtools/src/storage_devManager.c | 34 + tools/src/imgtools/src/storage_devManager.h | 26 + tools/src/mkdosfs/build-win.sh | 8 + tools/src/mkdosfs/build.sh | 8 + tools/src/mkdosfs/src/mkdosfs.c | 817 +++++ tools/src/mkdosfs/src/mkdosfs.h | 156 + 130 files changed, 66559 insertions(+), 176 deletions(-) delete mode 100644 DOWNLOAD_TOOLS.BAT delete mode 100755 download_tools.sh create mode 100755 tools/Trim create mode 100755 tools/Trim.bat create mode 100755 tools/bios32.bin create mode 100755 tools/python/Common/BuildToolError.py create mode 100755 tools/python/Common/BuildVersion.py create mode 100755 tools/python/Common/DataType.py create mode 100755 tools/python/Common/EdkLogger.py create mode 100755 tools/python/Common/GlobalData.py create mode 100755 tools/python/Common/LongFilePathOs.py create mode 100755 tools/python/Common/LongFilePathOsPath.py create mode 100755 tools/python/Common/LongFilePathSupport.py create mode 100755 tools/python/Common/Misc.py create mode 100755 tools/python/Common/MultipleWorkspace.py create mode 100755 tools/python/Common/Parsing.py create mode 100755 tools/python/Common/StringUtils.py create mode 100755 tools/python/Common/__init__.py create mode 100755 tools/python/Common/caching.py create mode 100755 tools/python/CommonDataClass/DataClass.py create mode 100755 tools/python/CommonDataClass/Exceptions.py create mode 100755 tools/python/CommonDataClass/__init__.py create mode 100755 tools/python/Trim/Trim.py create mode 100755 tools/src/GenFw/Common/build-win.sh create mode 100755 tools/src/GenFw/Common/build.sh create mode 100755 tools/src/GenFw/Common/clean.sh create mode 100644 tools/src/GenFw/Common/src/BasePeCoff.c create mode 100644 tools/src/GenFw/Common/src/BinderFuncs.c create mode 100644 tools/src/GenFw/Common/src/BinderFuncs.h create mode 100644 tools/src/GenFw/Common/src/CommonLib.c create mode 100644 tools/src/GenFw/Common/src/CommonLib.h create mode 100644 tools/src/GenFw/Common/src/Compress.h create mode 100644 tools/src/GenFw/Common/src/Crc32.c create mode 100644 tools/src/GenFw/Common/src/Crc32.h create mode 100644 tools/src/GenFw/Common/src/Decompress.c create mode 100644 tools/src/GenFw/Common/src/Decompress.h create mode 100644 tools/src/GenFw/Common/src/EfiCompress.c create mode 100644 tools/src/GenFw/Common/src/EfiUtilityMsgs.c create mode 100644 tools/src/GenFw/Common/src/EfiUtilityMsgs.h create mode 100644 tools/src/GenFw/Common/src/FirmwareVolumeBuffer.c create mode 100644 tools/src/GenFw/Common/src/FirmwareVolumeBufferLib.h create mode 100644 tools/src/GenFw/Common/src/FvLib.c create mode 100644 tools/src/GenFw/Common/src/FvLib.h create mode 100644 tools/src/GenFw/Common/src/MemoryFile.c create mode 100644 tools/src/GenFw/Common/src/MemoryFile.h create mode 100644 tools/src/GenFw/Common/src/MyAlloc.c create mode 100644 tools/src/GenFw/Common/src/MyAlloc.h create mode 100644 tools/src/GenFw/Common/src/OsPath.c create mode 100644 tools/src/GenFw/Common/src/OsPath.h create mode 100644 tools/src/GenFw/Common/src/ParseGuidedSectionTools.c create mode 100644 tools/src/GenFw/Common/src/ParseGuidedSectionTools.h create mode 100644 tools/src/GenFw/Common/src/ParseInf.c create mode 100644 tools/src/GenFw/Common/src/ParseInf.h create mode 100644 tools/src/GenFw/Common/src/PcdValueCommon.c create mode 100644 tools/src/GenFw/Common/src/PcdValueCommon.h create mode 100644 tools/src/GenFw/Common/src/PeCoffLib.h create mode 100644 tools/src/GenFw/Common/src/PeCoffLoaderEx.c create mode 100644 tools/src/GenFw/Common/src/SimpleFileParsing.c create mode 100644 tools/src/GenFw/Common/src/SimpleFileParsing.h create mode 100644 tools/src/GenFw/Common/src/StringFuncs.c create mode 100644 tools/src/GenFw/Common/src/StringFuncs.h create mode 100644 tools/src/GenFw/Common/src/TianoCompress.c create mode 100755 tools/src/GenFw/GenFw/build-win.sh create mode 100755 tools/src/GenFw/GenFw/build.sh create mode 100755 tools/src/GenFw/GenFw/clean.sh create mode 100644 tools/src/GenFw/GenFw/src/Elf32Convert.c create mode 100644 tools/src/GenFw/GenFw/src/Elf32Convert.h create mode 100644 tools/src/GenFw/GenFw/src/Elf64Convert.c create mode 100644 tools/src/GenFw/GenFw/src/Elf64Convert.h create mode 100644 tools/src/GenFw/GenFw/src/ElfConvert.c create mode 100644 tools/src/GenFw/GenFw/src/ElfConvert.h create mode 100644 tools/src/GenFw/GenFw/src/GenFw.c create mode 100644 tools/src/GenFw/GenFw/src/GenFw.h create mode 100644 tools/src/GenFw/GenFw/src/elf32.h create mode 100644 tools/src/GenFw/GenFw/src/elf64.h create mode 100644 tools/src/GenFw/GenFw/src/elf_common.h create mode 100644 tools/src/GenFw/Include/Common/BaseTypes.h create mode 100644 tools/src/GenFw/Include/Common/BuildVersion.h create mode 100644 tools/src/GenFw/Include/Common/PiFirmwareFile.h create mode 100644 tools/src/GenFw/Include/Common/PiFirmwareVolume.h create mode 100644 tools/src/GenFw/Include/Common/UefiBaseTypes.h create mode 100644 tools/src/GenFw/Include/Common/UefiInternalFormRepresentation.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi10.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi20.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi30.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi40.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi50.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi51.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi60.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi61.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi62.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi63.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi64.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi65.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/AcpiAml.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h create mode 100644 tools/src/GenFw/MdePkg/Include/IndustryStandard/PeImage.h create mode 100644 tools/src/GenFw/MdePkg/Include/X64/ProcessorBind.h create mode 100755 tools/src/GenFw/build-win.sh create mode 100755 tools/src/GenFw/build.sh create mode 100755 tools/src/GenFw/clean.sh create mode 100755 tools/src/build-i686-elf-tools-win.sh create mode 100755 tools/src/build-i686-elf-tools.sh create mode 100755 tools/src/imgtools/build-win.sh create mode 100755 tools/src/imgtools/build.sh create mode 100755 tools/src/imgtools/clean.sh create mode 100755 tools/src/imgtools/src/fat.c create mode 100755 tools/src/imgtools/src/fat.h create mode 100755 tools/src/imgtools/src/fileManager.h create mode 100755 tools/src/imgtools/src/imgtools.c create mode 100755 tools/src/imgtools/src/storage_devManager.c create mode 100755 tools/src/imgtools/src/storage_devManager.h create mode 100755 tools/src/mkdosfs/build-win.sh create mode 100755 tools/src/mkdosfs/build.sh create mode 100644 tools/src/mkdosfs/src/mkdosfs.c create mode 100644 tools/src/mkdosfs/src/mkdosfs.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a9ab734..a9d7e60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,64 +3,157 @@ name: CI on: [push, pull_request] jobs: - download_tools: - name: Download tools - strategy: - matrix: - os: ["ubuntu-latest", "windows-latest"] - runs-on: ${{ matrix.os }} + build_tools_linux: + name: Build tools for Linux + runs-on: "ubuntu-latest" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache tools id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-tools with: path: tools - key: ${{ runner.os }}-${{ env.cache-name }}-${{ secrets.CACHE_VERSION }}-${{ hashFiles('download_tools.sh', 'DOWNLOAD_TOOLS.BAT') }} - - name: Download tools (Linux) - if: runner.os == 'Linux' && steps.cache.outputs.cache-hit != 'true' - run: ./download_tools.sh + key: linux-${{ env.cache-name }}-${{ secrets.CACHE_VERSION }}-${{ hashFiles('tools/src') }} + - name: Install build requirements + if: steps.cache.outputs.cache-hit != 'true' + run: sudo apt install wget build-essential file + - name: Build i686-elf-tools + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/build-i686-elf-tools.sh shell: sh - - name: Download tools (Windows) - if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true' - run: DOWNLOAD_TOOLS.BAT - shell: cmd - build: - name: Build - needs: [download_tools] - strategy: - matrix: - os: ["ubuntu-latest", "windows-latest"] - type: ["floppy", "hd", "hd --mbr"] - debug: ["", "--debug"] - test: ["", "--test"] - efi: ["", "--efi"] - runs-on: ${{ matrix.os }} + - name: Cleanup after i686-elf-tools build + if: steps.cache.outputs.cache-hit != 'true' + run: rm -rf tools/src/binutils-* tools/src/gcc-* + - name: Build GenFw + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/GenFw/build.sh + shell: sh + - name: Build imgtools + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/imgtools/build.sh + shell: sh + - name: Build mkdosfs + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/mkdosfs/build.sh + shell: sh + - name: Tar tools + run: tar -cf chaostools-linux.tar --exclude='src' -C tools . + - name: Archive artifacts + uses: actions/upload-artifact@v3 + with: + name: chaostools-linux.tar + path: chaostools-linux.tar + build_tools_windows: + name: Build tools for Windows + needs: [build_tools_linux] + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache tools id: cache - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-tools with: path: tools - key: ${{ runner.os }}-${{ env.cache-name }}-${{ secrets.CACHE_VERSION }}-${{ hashFiles('download_tools.sh', 'DOWNLOAD_TOOLS.BAT') }} - - name: Download tools (Linux) - if: runner.os == 'Linux' && steps.cache.outputs.cache-hit != 'true' - run: ./download_tools.sh + key: windows-${{ env.cache-name }}-${{ secrets.CACHE_VERSION }}-${{ hashFiles('tools/src') }} + - name: Install build requirements + if: steps.cache.outputs.cache-hit != 'true' + run: sudo apt install wget build-essential file git automake autopoint bison flex libgdk-pixbuf2.0-dev gperf intltool libtool libltdl-dev python3-mako ruby unzip p7zip-full lzip libtool-bin python-is-python3 gcc-mingw-w64-x86-64 + - name: Download linux tools artifact + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/download-artifact@v3 + with: + name: chaostools-linux.tar + - name: Untar tools + if: steps.cache.outputs.cache-hit != 'true' + run: tar -xvf chaostools-linux.tar -C tools + - name: Build i686-elf-tools + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/build-i686-elf-tools-win.sh shell: sh - - name: Download tools (Windows) - if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true' - run: DOWNLOAD_TOOLS.BAT - shell: cmd - - name: Run the build script (Linux) - if: runner.os == 'Linux' + - name: Cleanup after i686-elf-tools build + if: steps.cache.outputs.cache-hit != 'true' + run: rm -rf tools/src/mxe tools/src/binutils-* tools/src/gcc-* + - name: Build GenFw + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/GenFw/build-win.sh + shell: sh + - name: Build imgtools + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/imgtools/build-win.sh + shell: sh + - name: Build mkdosfs + if: steps.cache.outputs.cache-hit != 'true' + run: tools/src/mkdosfs/build-win.sh + shell: sh + - name: Remove linux tools + if: steps.cache.outputs.cache-hit != 'true' + run: tar -tf chaostools-linux.tar | tail -n +2 | sed -e 's!^!tools/!' | xargs rm -rf + - name: Archive artifacts + uses: actions/upload-artifact@v3 + with: + name: chaostools-windows + path: | + tools + !tools/src + build_linux: + name: Build on Linux + needs: [build_tools_linux] + strategy: + matrix: + type: ["floppy", "hd", "hd --mbr"] + debug: ["", "--debug"] + test: ["", "--test"] + efi: ["", "--efi"] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install tools + run: sudo apt install nasm make qemu-utils python3 + - name: Download additional tools artifact + uses: actions/download-artifact@v3 + with: + name: chaostools-linux.tar + - name: Untar tools + if: steps.cache.outputs.cache-hit != 'true' + run: tar -xvf chaostools-linux.tar -C tools + - name: Run the build script run: ./build_image.sh ${{ matrix.type }} ${{ matrix.debug }} ${{ matrix.test }} ${{ matrix.efi }} --user-programs-all shell: sh - - name: Run the build script (Windows) - if: runner.os == 'Windows' + build_windows: + name: Build on Windows + needs: [build_tools_windows] + strategy: + matrix: + type: ["floppy", "hd", "hd --mbr"] + debug: ["", "--debug"] + test: ["", "--test"] + efi: ["", "--efi"] + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - name: Install nasm + uses: ilammy/setup-nasm@v1 + - name: Install Python3 + uses: actions/setup-python@v4 + with: + python-version: '3.11' + - name: Install winget + uses: Cyberboss/install-winget@v1 + - name: Install QEMU + run: winget install --accept-source-agreements --accept-package-agreements --id=SoftwareFreedomConservancy.QEMU -e + - name: Add QEMU to the PATH + shell: pwsh + run: | + "C:\Program Files\qemu" >> $env:GITHUB_PATH + - name: Download tools artifact + uses: actions/download-artifact@v3 + with: + name: chaostools-windows + path: tools + - name: Run the build script run: BUILD_IMAGE.BAT ${{ matrix.type }} ${{ matrix.debug }} ${{ matrix.test }} ${{ matrix.efi }} --user-programs-all shell: cmd diff --git a/.gitignore b/.gitignore index fb22d88..7c206f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/tools *.o *.map *.elf @@ -20,3 +19,12 @@ *.i *.iii *.lst +*.pyc +/tools +!/tools +/tools/* +!/tools/src +!/tools/python +!/tools/Trim +!/tools/Trim.bat +!/tools/bios32.bin diff --git a/.vscode/launch.json b/.vscode/launch.json index db01907..8902871 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,11 +15,11 @@ "launchCompleteCommand": "exec-run", "windows": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.bat" + "miDebuggerPath": "gdb" }, "linux": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.sh" + "miDebuggerPath": "gdb" }, "preLaunchTask": "QEMU Boot Floppy & Run GDB Server", "internalConsoleOptions": "openOnSessionStart" @@ -38,11 +38,11 @@ "launchCompleteCommand": "exec-run", "windows": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.bat" + "miDebuggerPath": "gdb" }, "linux": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.sh" + "miDebuggerPath": "gdb" }, "preLaunchTask": "QEMU Boot Floppy EFI & Run GDB Server", "internalConsoleOptions": "openOnSessionStart" @@ -61,11 +61,11 @@ "launchCompleteCommand": "exec-run", "windows": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.bat" + "miDebuggerPath": "gdb" }, "linux": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.sh" + "miDebuggerPath": "gdb" }, "preLaunchTask": "QEMU Boot HD & Run GDB Server", "internalConsoleOptions": "openOnSessionStart" @@ -84,11 +84,11 @@ "launchCompleteCommand": "exec-run", "windows": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.bat" + "miDebuggerPath": "gdb" }, "linux": { "MIMode": "gdb", - "miDebuggerPath": "${workspaceRoot}/tools/gdb-multiarch.sh" + "miDebuggerPath": "gdb" }, "preLaunchTask": "QEMU Boot HD EFI & Run GDB Server", "internalConsoleOptions": "openOnSessionStart" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7eab166..dd97b2b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -27,10 +27,10 @@ "label": "QEMU Boot Floppy & Run GDB Server", "type": "shell", "windows": { - "command": "echo a & \"${workspaceRoot}/tools/qemu-windows/qemu-system-i386\" -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s" + "command": "echo a & call \"${workspaceRoot}/SET_ENV_VARS.BAT\" & qemu-system-i386 -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s" }, "linux": { - "command": "cd \"${workspaceRoot}/tools/qemu-linux\" && export LD_LIBRARY_PATH=\"${workspaceRoot}/tools/qemu-linux/lib\" && echo a && ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=../../FloppyImage.bin,index=0,if=floppy -boot a -S -s || ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=../../FloppyImage.bin,index=0,if=floppy -boot a -S -s" + "command": "echo a && qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s || qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s" }, "group": "none", "presentation": { @@ -64,10 +64,10 @@ "label": "QEMU Boot Floppy EFI & Run GDB Server", "type": "shell", "windows": { - "command": "echo a & \"${workspaceRoot}/tools/qemu-windows/qemu-system-i386\" -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s" + "command": "echo a & call \"${workspaceRoot}/SET_ENV_VARS.BAT\" & qemu-system-i386 -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s" }, "linux": { - "command": "cd \"${workspaceRoot}/tools/qemu-linux\" && export LD_LIBRARY_PATH=\"${workspaceRoot}/tools/qemu-linux/lib\" && echo a && ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios ../bios32.bin -drive format=raw,file=../../FloppyImage.bin,index=0,if=floppy -boot a -S -s || ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios ../bios32.bin -drive format=raw,file=../../FloppyImage.bin,index=0,if=floppy -boot a -S -s" + "command": "echo a && qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s || qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a -S -s" }, "group": "none", "presentation": { @@ -101,10 +101,10 @@ "label": "QEMU Boot HD & Run GDB Server", "type": "shell", "windows": { - "command": "echo a & \"${workspaceRoot}/tools/qemu-windows/qemu-system-i386.exe\" -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s" + "command": "echo a & call \"${workspaceRoot}/SET_ENV_VARS.BAT\" & qemu-system-i386 -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s" }, "linux": { - "command": "cd \"${workspaceRoot}/tools/qemu-linux\" && export LD_LIBRARY_PATH=\"${workspaceRoot}/tools/qemu-linux/lib\" && echo a && ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=../../HDImage.bin,index=0,if=ide -boot c -S -s || ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=../../HDImage.bin,index=0,if=ide -boot c -S -s" + "command": "echo a && qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s || qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s" }, "group": "none", "presentation": { @@ -138,10 +138,10 @@ "label": "QEMU Boot HD EFI & Run GDB Server", "type": "shell", "windows": { - "command": "echo a & \"${workspaceRoot}/tools/qemu-windows/qemu-system-i386\" -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s" + "command": "echo a & call \"${workspaceRoot}/SET_ENV_VARS.BAT\" & qemu-system-i386 -audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s" }, "linux": { - "command": "cd \"${workspaceRoot}/tools/qemu-linux\" && export LD_LIBRARY_PATH=\"${workspaceRoot}/tools/qemu-linux/lib\" && echo a && ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios ../bios32.bin -drive format=raw,file=../../HDImage.bin,index=0,if=ide -boot c -S -s || ${workspaceRoot}/tools/qemu-linux/qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios ../bios32.bin -drive format=raw,file=../../HDImage.bin,index=0,if=ide -boot c -S -s" + "command": "echo a && qemu-system-i386 -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s || qemu-system-i386 -curses -audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound -bios tools/bios32.bin -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c -S -s" }, "group": "none", "presentation": { diff --git a/BUILD_IMAGE.BAT b/BUILD_IMAGE.BAT index 1a80c07..5513c1c 100644 --- a/BUILD_IMAGE.BAT +++ b/BUILD_IMAGE.BAT @@ -88,7 +88,8 @@ for %%a in ("%user_programs_paths: =" "%") do ( :imageBuilt if "%IMAGE_TYPE%"=="HD" ( del HDImage.vdi >nul 2>&1 - VBoxManage convertfromraw --uuid d32a4d71-7ccb-4864-a684-c9d7c7a425f5 -format VDI HDImage.bin HDImage.vdi || echo Failed building VDI HD image&&goto ERROR + qemu-img convert -f raw -O vdi HDImage.bin HDImage.vdi || echo Failed building VDI HD image&&goto ERROR + python3 -c "f = open('HDImage.vdi', 'r+b'); f.seek(0x188); f.write(b'\x71\x4d\x2a\xd3\xcb\x7c\x64\x48\xa6\x84\xc9\xd7\xc7\xa4\x25\xf5'); f.close();" ) echo %IMAGE_TYPE% Image was built goto eof diff --git a/DOWNLOAD_TOOLS.BAT b/DOWNLOAD_TOOLS.BAT deleted file mode 100644 index 94af0c9..0000000 --- a/DOWNLOAD_TOOLS.BAT +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -cd %~d0%~p0 - -if exist tools\qemu-windows goto downloaded - -powershell -command "Invoke-WebRequest -OutFile \"%~d0%~p0chaostools-windows.zip\" -Uri http://filip.mg6.at/chaostools-windows.zip" -powershell -command "Expand-Archive -Force \"%~d0%~p0chaostools-windows.zip\" \"%~d0%~p0tools\\"" - -:downloaded diff --git a/QEMU_BOOT.BAT b/QEMU_BOOT.BAT index a6021f6..dffd875 100644 --- a/QEMU_BOOT.BAT +++ b/QEMU_BOOT.BAT @@ -1,11 +1,12 @@ @echo off cd %~d0%~p0 +call SET_ENV_VARS.BAT set IMAGE_TYPE= set DEBUG=0 set EFI=0 set SECONDARY_HD_IMAGE= -set QEMU_CMD=tools\qemu-windows\qemu-system-i386.exe +set QEMU_CMD=qemu-system-i386 set QEMU_ARGS=-audiodev dsound,id=stdsound -machine pcspk-audiodev=stdsound :argLoop @@ -22,7 +23,7 @@ if "%1" neq "" ( ) else if "%1"=="--efi" ( set EFI=1 ) else if "%1"=="--x64" ( - set QEMU_CMD=tools\qemu-windows\qemu-system-x86_64.exe + set QEMU_CMD=qemu-system-x86_64 ) else if "%1"=="--secondary-hd-image" ( set SECONDARY_HD_IMAGE=%2 set SECONDARY_HD_IMAGE=!SECONDARY_HD_IMAGE:"=! @@ -48,10 +49,9 @@ if "%IMAGE_TYPE%"=="HD" ( ) if "%DEBUG%"=="1" ( - call SET_ENV_VARS.BAT if not exist kernel\CHAOSKRN.SYS_debug echo WARNING^^! CHAOSKRN.SYS_debug does not exist start /b cmd /c %QEMU_CMD% %QEMU_ARGS% -S -s - tools\gdb-multiarch.bat -x kernel_debug.gdb + gdb -x kernel_debug.gdb ) else ( %QEMU_CMD% %QEMU_ARGS% ) diff --git a/README.md b/README.md index ef1736e..b588321 100644 --- a/README.md +++ b/README.md @@ -36,56 +36,57 @@ git clone https://github.com/Filiprogrammer/ChaOS.git cd ChaOS ``` -### Download tools +### Setup tools #### Debian -Install wget and unzip if not already installed +Install tools required to build, run and debug ChaOS. ```console -sudo apt install wget unzip +sudo apt install nasm make qemu-system-x86 qemu-utils dialog gdb python3-tk ``` -Download ChaOS tools +Get additional tools by either downloading the binaries: ```console -./download_tools.sh +wget https://github.com/Filiprogrammer/ChaOS/releases/download/v0.2.230727/chaostools-linux.tar.gz +tar -xf chaostools-linux.tar.gz -C tools ``` -#### Arch Linux - -Install wget and unzip if not already installed +Or building them yourself: ```console -sudo pacman -Sy wget unzip +sudo apt install wget build-essential file +tools/src/build-i686-elf-tools.sh +tools/src/GenFw/build.sh +tools/src/imgtools/build.sh +tools/src/mkdosfs/build.sh ``` -Download ChaOS tools - -```console -./download_tools.sh -``` +#### Windows -#### Fedora +To get the tools required to build, run and debug ChaOS on Windows, download the binaries [here](https://github.com/Filiprogrammer/ChaOS/releases/download/v0.2.230727/chaostools-windows.zip). -Install wget and unzip if not already installed +Or gather and build the tools yourself: -```console -sudo yum install wget unzip -``` +- [QEMU](https://qemu.weilnetz.de/w64/) +- [Python3](https://www.python.org/downloads/windows/) +- gdb +- make +- [nasm](https://www.nasm.us/pub/nasm/stable/win64/) -Download ChaOS tools +Cross-build the additional tools on linux: ```console -./download_tools.sh -``` +sudo apt install wget build-essential file git automake autopoint bison flex libgdk-pixbuf2.0-dev gperf intltool libtool libltdl-dev python3-mako ruby unzip p7zip-full lzip libtool-bin python-is-python3 -#### Windows +tools/src/build-i686-elf-tools-win.sh -Download ChaOS tools +sudo apt install gcc-mingw-w64-x86-64 -```console -DOWNLOAD_TOOLS.BAT +tools/src/GenFw/build-win.sh +tools/src/imgtools/build-win.sh +tools/src/mkdosfs/build-win.sh ``` ### Build image diff --git a/SET_ENV_VARS.BAT b/SET_ENV_VARS.BAT index 6238a70..e73213e 100644 --- a/SET_ENV_VARS.BAT +++ b/SET_ENV_VARS.BAT @@ -3,9 +3,7 @@ if "%CHAOS_TOOLS_PATH_SET%"=="TRUE" goto SKIP set CHAOS_TOOLS_PATH_SET=TRUE -set PATH=%~d0%~p0tools\python27-windows;%~d0%~p0tools\i686-elf-tools-windows\bin;%~d0%~p0tools\python27-windows\Scripts;%~d0%~p0tools;%PATH% -set PYTHONPATH=%~d0%~p0tools\python27-windows\Lib -set PYTHONHOME=%~d0%~p0tools\python27-windows +set PATH=%~d0%~p0tools\i686-elf-tools-windows\bin;%~d0%~p0tools;%PATH% echo Environment variables have been set goto EOF diff --git a/build_image.sh b/build_image.sh index 01e9d42..1a10651 100755 --- a/build_image.sh +++ b/build_image.sh @@ -64,7 +64,7 @@ if [ "$IMAGE_TYPE" = "HD" ]; then else mkdosfs -hd -no-mbr -fats2 -fatz12 -spc1 -z2 -noverb -b stage1_bootloader/boot.bin HDImage.bin || error fi - + image_file=HDImage.bin elif [ "$IMAGE_TYPE" = "Floppy" ]; then mkdosfs -fd -spt18 -heads2 -cyls80 -fats2 -fatz12 -spc1 -noverb -b stage1_bootloader/boot.bin FloppyImage.bin || error @@ -90,7 +90,8 @@ done if [ "$IMAGE_TYPE" = "HD" ]; then rm HDImage.vdi 2>/dev/null - VBoxManage convertfromraw --uuid d32a4d71-7ccb-4864-a684-c9d7c7a425f5 -format VDI HDImage.bin HDImage.vdi || { printf "\033[1;31mFailed building VDI HD image\033[0m\n"; error; } + qemu-img convert -f raw -O vdi HDImage.bin HDImage.vdi || { printf "\033[1;31mFailed building VDI HD image\033[0m\n"; error; } + printf '\161\115\052\323\313\174\144\110\246\204\311\327\307\244\045\365' | dd of=HDImage.vdi bs=1 seek=$((0x188)) conv=notrunc fi printf "\033[1;32m$IMAGE_TYPE Image was built\033[0m\n" diff --git a/download_tools.sh b/download_tools.sh deleted file mode 100755 index 868043c..0000000 --- a/download_tools.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -cd "$(dirname "$(readlink -f "$0")")" - -if [ -z "$(ls -A tools/qemu-linux 2>/dev/null)" ]; then - wget http://filip.mg6.at/chaostools-linux.zip - unzip -o chaostools-linux.zip -d tools && rm chaostools-linux.zip - chmod -R 777 tools -fi diff --git a/gdb_heap_gui.py b/gdb_heap_gui.py index 96a9d61..3895707 100644 --- a/gdb_heap_gui.py +++ b/gdb_heap_gui.py @@ -1,9 +1,8 @@ import gdb -import Tkinter -from Tkinter import * -import ttk -from ttk import * -import thread +import tkinter +from tkinter import * +from tkinter.ttk import * +import _thread from collections import namedtuple Region = namedtuple("Region", "size reserved"); @@ -32,7 +31,7 @@ def update_gui(): def run_gui(): global window; - window = Tkinter.Tk(); + window = tkinter.Tk(); window.title("Heap"); global lblRegionCount; @@ -45,9 +44,9 @@ def run_gui(): treeHeap.column("one", width=100, minwidth=100, stretch=True); treeHeap.column("two", width=100, minwidth=100, stretch=True); treeHeap.column("three", width=50, minwidth=50, stretch=True); - treeHeap.heading("one", text="Offset",anchor=Tkinter.W); - treeHeap.heading("two", text="Size",anchor=Tkinter.W); - treeHeap.heading("three", text="Reserved",anchor=Tkinter.W); + treeHeap.heading("one", text="Offset",anchor=tkinter.W); + treeHeap.heading("two", text="Size",anchor=tkinter.W); + treeHeap.heading("three", text="Reserved",anchor=tkinter.W); treeHeap["show"] = "headings"; treeHeap.bind('', on_treeview_click); treeHeap.pack(side="left", fill="both", expand=True); @@ -62,7 +61,7 @@ def run_gui(): window.protocol("WM_DELETE_WINDOW", on_closing); window.mainloop(); gdb.events.stop.disconnect(stop_handler); - Tkinter._default_root = None; + tkinter._default_root = None; return; def stop_handler(event): @@ -85,5 +84,5 @@ def read_heap(): read_heap(); -thread.start_new_thread(run_gui, ()); +_thread.start_new_thread(run_gui, ()); gdb.events.stop.connect(stop_handler); diff --git a/gdb_tasks_gui.py b/gdb_tasks_gui.py index 8a8357c..63d7f36 100644 --- a/gdb_tasks_gui.py +++ b/gdb_tasks_gui.py @@ -1,9 +1,8 @@ import gdb -import Tkinter -from Tkinter import * -import ttk -from ttk import * -import thread +import tkinter +from tkinter import * +from tkinter.ttk import * +import _thread from collections import namedtuple Task = namedtuple("Task", "id page_directory cpu_time_used last_active threads next_threadId") @@ -81,21 +80,21 @@ def setup_treeview_thread_queue(treeview): treeview.column("seven", width=70, minwidth=70, stretch=True) treeview.column("eight", width=60, minwidth=60, stretch=True) treeview.column("nine", width=50, minwidth=50, stretch=True) - treeview.heading("#0", text="id", anchor=Tkinter.W) - treeview.heading("one", text="esp", anchor=Tkinter.W) - treeview.heading("two", text="ss", anchor=Tkinter.W) - treeview.heading("three", text="Kernel Stack", anchor=Tkinter.W) - treeview.heading("four", text="Stack Begin", anchor=Tkinter.W) - treeview.heading("five", text="Stack End", anchor=Tkinter.W) - treeview.heading("six", text="FPUPtr", anchor=Tkinter.W) - treeview.heading("seven", text="Parent Task", anchor=Tkinter.W) - treeview.heading("eight", text="Timeout", anchor=Tkinter.W) - treeview.heading("nine", text="nice", anchor=Tkinter.W) + treeview.heading("#0", text="id", anchor=tkinter.W) + treeview.heading("one", text="esp", anchor=tkinter.W) + treeview.heading("two", text="ss", anchor=tkinter.W) + treeview.heading("three", text="Kernel Stack", anchor=tkinter.W) + treeview.heading("four", text="Stack Begin", anchor=tkinter.W) + treeview.heading("five", text="Stack End", anchor=tkinter.W) + treeview.heading("six", text="FPUPtr", anchor=tkinter.W) + treeview.heading("seven", text="Parent Task", anchor=tkinter.W) + treeview.heading("eight", text="Timeout", anchor=tkinter.W) + treeview.heading("nine", text="nice", anchor=tkinter.W) treeview.bind('', on_treeview_click) def run_gui(): global window - window = Tkinter.Tk() + window = tkinter.Tk() window.geometry("1300x600") window.title("ChaOS Tasks") global lblKernelTask @@ -139,12 +138,12 @@ def run_gui(): treeTasks.column("three", width=80, minwidth=80, stretch=True) treeTasks.column("four", width=70, minwidth=70, stretch=True) treeTasks.column("five", width=70, minwidth=70, stretch=True) - treeTasks.heading("#0", text="id", anchor=Tkinter.W) - treeTasks.heading("one", text="page directory", anchor=Tkinter.W) - treeTasks.heading("two", text="CPU time used", anchor=Tkinter.W) - treeTasks.heading("three", text="last active", anchor=Tkinter.W) - treeTasks.heading("four", text="threads", anchor=Tkinter.W) - treeTasks.heading("five", text="next thread id", anchor=Tkinter.W) + treeTasks.heading("#0", text="id", anchor=tkinter.W) + treeTasks.heading("one", text="page directory", anchor=tkinter.W) + treeTasks.heading("two", text="CPU time used", anchor=tkinter.W) + treeTasks.heading("three", text="last active", anchor=tkinter.W) + treeTasks.heading("four", text="threads", anchor=tkinter.W) + treeTasks.heading("five", text="next thread id", anchor=tkinter.W) treeTasks.bind('', on_treeview_click) treeTasks.grid(column=0, row=3+queue_number, sticky="EW") window.grid_rowconfigure(3+queue_number, weight=2, uniform="fred") @@ -161,7 +160,7 @@ def run_gui(): window.protocol("WM_DELETE_WINDOW", on_closing) window.mainloop() gdb.events.stop.disconnect(stop_handler) - Tkinter._default_root = None + tkinter._default_root = None return def stop_handler(event): @@ -252,5 +251,5 @@ def read_task_queues(): do_nothing_task_str = do_nothing_task.format_string() read_task_queues() -thread.start_new_thread(run_gui, ()) +_thread.start_new_thread(run_gui, ()) gdb.events.stop.connect(stop_handler) diff --git a/qemu_boot.sh b/qemu_boot.sh index 151e402..b798d91 100755 --- a/qemu_boot.sh +++ b/qemu_boot.sh @@ -14,7 +14,7 @@ IMAGE_TYPE= DEBUG=0 EFI=0 SECONDARY_HD_IMAGE= -QEMU_CMD=./qemu-system-i386 +QEMU_CMD=qemu-system-i386 QEMU_ARGS="-audiodev pa,id=stdsound -machine pcspk-audiodev=stdsound" while [ $# -gt 0 ] ; do @@ -23,7 +23,7 @@ while [ $# -gt 0 ] ; do (hd) IMAGE_TYPE=HD ;; (--debug) DEBUG=1 ;; (--efi) EFI=1 ;; - (--x64) QEMU_CMD=./qemu-system-x86_64 ;; + (--x64) QEMU_CMD=qemu-system-x86_64 ;; (--secondary-hd-image) SECONDARY_HD_IMAGE="$2" ; shift ;; *) usage ;; esac @@ -31,36 +31,27 @@ while [ $# -gt 0 ] ; do done if [ -z $IMAGE_TYPE ]; then usage; fi -if [ "$EFI" = "1" ]; then QEMU_ARGS="$QEMU_ARGS -bios ../bios32.bin"; fi +if [ "$EFI" = "1" ]; then QEMU_ARGS="$QEMU_ARGS -bios tools/bios32.bin"; fi if [ ! -z "$SECONDARY_HD_IMAGE" ]; then - case "$SECONDARY_HD_IMAGE" in - /*) ;; - *) SECONDARY_HD_IMAGE="../../$SECONDARY_HD_IMAGE" ;; - esac - QEMU_ARGS="$QEMU_ARGS -drive format=raw,file=\"$SECONDARY_HD_IMAGE\",index=1,if=ide" fi if [ "$IMAGE_TYPE" = "HD" ]; then - QEMU_ARGS="$QEMU_ARGS -drive format=raw,file=../../HDImage.bin,index=0,if=ide -boot c" + QEMU_ARGS="$QEMU_ARGS -drive format=raw,file=HDImage.bin,index=0,if=ide -boot c" elif [ "$IMAGE_TYPE" = "Floppy" ]; then - QEMU_ARGS="$QEMU_ARGS -drive format=raw,file=../../FloppyImage.bin,index=0,if=floppy -boot a" + QEMU_ARGS="$QEMU_ARGS -drive format=raw,file=FloppyImage.bin,index=0,if=floppy -boot a" fi -cd "$(dirname "$(readlink -f "$0")")/tools/qemu-linux" -export LD_LIBRARY_PATH="$(dirname "$(readlink -f "$0")")/lib" - if [ "$DEBUG" = "1" ]; then - if [ ! -f ../../kernel/CHAOSKRN.SYS_debug ]; then printf "\033[1;31mWARNING! CHAOSKRN.SYS_debug does not exist\033[0m\n"; fi + if [ ! -f kernel/CHAOSKRN.SYS_debug ]; then printf "\033[1;31mWARNING! CHAOSKRN.SYS_debug does not exist\033[0m\n"; fi (ERROR=$(eval $QEMU_CMD $QEMU_ARGS -S -s 3>&1 1>&2 2>&3 3>&- | tee /dev/tty) if echo "$ERROR" | grep -q "Could not initialize SDL\|gtk initialization failed"; then eval $QEMU_CMD -curses $QEMU_ARGS -S -s fi) & - cd ../.. - tools/gdb-multiarch.sh -x kernel_debug.gdb + gdb -x kernel_debug.gdb else ERROR=$(eval $QEMU_CMD $QEMU_ARGS 3>&1 1>&2 2>&3 3>&- | tee /dev/tty) if echo "$ERROR" | grep -q "Could not initialize SDL\|gtk initialization failed"; then diff --git a/set_env_vars.sh b/set_env_vars.sh index 62629e5..483da61 100755 --- a/set_env_vars.sh +++ b/set_env_vars.sh @@ -2,21 +2,13 @@ if [ -z $CHAOS_TOOLS_PATH_SET ]; then if [ -z $BASH_SOURCE ]; then - PATH="$(dirname "$(readlink -f "$0")")/tools:$(dirname "$(readlink -f "$0")")/tools/i686-elf-tools-linux/bin:$(dirname "$(readlink -f "$0")")/tools/python27-linux:$PATH" - LD_LIBRARY_PATH="$(dirname "$(readlink -f "$0")")/tools:$(dirname "$(readlink -f "$0")")/tools/python27-linux" - TCL_LIBRARY="$(dirname "$(readlink -f "$0")")/tools/python27-linux/Lib/tcl8.6" - TK_LIBRARY="$(dirname "$(readlink -f "$0")")/tools/python27-linux/Lib/tk8.6" + cd "$(dirname "$(readlink -f "$0")")" else - PATH="$(dirname "$(readlink -f "$BASH_SOURCE")")/tools:$(dirname "$(readlink -f "$BASH_SOURCE")")/tools/i686-elf-tools-linux/bin:$(dirname "$(readlink -f "$BASH_SOURCE")")/tools/python27-linux:$PATH" - LD_LIBRARY_PATH="$(dirname "$(readlink -f "$BASH_SOURCE")")/tools:$(dirname "$(readlink -f "$BASH_SOURCE")")/tools/python27-linux" - TCL_LIBRARY="$(dirname "$(readlink -f "$BASH_SOURCE")")/tools/python27-linux/Lib/tcl8.6" - TK_LIBRARY="$(dirname "$(readlink -f "$BASH_SOURCE")")/tools/python27-linux/Lib/tk8.6" + cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" fi - - export PATH - export LD_LIBRARY_PATH - export TCL_LIBRARY - export TK_LIBRARY + + PWD=$(pwd) + export PATH="$PWD/tools:$PWD/tools/i686-elf-tools-linux/bin:$PATH" export CHAOS_TOOLS_PATH_SET=1 echo "Environment variables have been set" else diff --git a/tools/Trim b/tools/Trim new file mode 100755 index 0000000..2fed213 --- /dev/null +++ b/tools/Trim @@ -0,0 +1,5 @@ +#!/bin/sh + +PYTHONPATH="$(dirname "$(readlink -f "$0")")/python" +export PYTHONPATH +python3 "$PYTHONPATH/Trim/Trim.py" $* || exit 1 diff --git a/tools/Trim.bat b/tools/Trim.bat new file mode 100755 index 0000000..4036bbc --- /dev/null +++ b/tools/Trim.bat @@ -0,0 +1,2 @@ +set PYTHONPATH=%~dp0python +python3 "%PYTHONPATH%/Trim/Trim.py" %* || exit /b 1 diff --git a/tools/bios32.bin b/tools/bios32.bin new file mode 100755 index 0000000000000000000000000000000000000000..5ae724b08977937cf3c089043e934715b2fcde25 GIT binary patch literal 2097152 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�sKam|Zph(h$HmWg6$Lb)y{P1k+rhKS@Idl@RN< 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
A?s5aN{1l(MD4s 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

#j1v0|96#zdHD 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Ɠ$ZCZUI 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ξRkWFz^YALOju*tn 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

Svzt0%WPD;^}Ab+NoTci)e*!p8|6>dm@ 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 W0KCT6UbcpATByi(VmL8KzXY;C<0b9xtB*7fy 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∓MtybSPMWa=^8O8;G<6I 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

XQT8|7A!qL#|p> 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

e~CJcO2 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

{r*Zr?P{UYmHa{fUR9!x+89vVPju@03OokL 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%0ARE(F?>yff}cD@PbBcq)IKMZ&C=#K zc~|jEBeacvmL7%S1^d0p6elM}un>%c`W5ZAV+kLi{%ZQ(jOrPlK9cyg@}x<433faH zZzw77({^)-)=bL0$aQNz|8Meis7`_6rq)Tchw+4U{pn&9d4a+*B?X7a7{CM)^(NYq z1PC66G+}0>3S#qy1gnd7+7tdh0EBJ+=CmlBMykbql=7l)P@QYqRXEr&NF+?q3``!> zxJ7XZf{c#*H9EqNhq{Jt$<@w9uC}UBYL0ne+owGaH1aih|f5)puo6QJgO1g#4M{9)_om*9*r?GG)uC=iyXmk^t0P7|XcY zmk0lxjkOpQ?TE{R%Uz=LB=9jV+;`A*w^aQebVa*ujlDcZP4v)s2K%eE5#9^lZVD0u zsD-in?Bxt_tm{0&2~5kL-(ukdNX>cz4K{2Fz0$46_evpSOHEX2|Lm(a{7kVWWb=Rj zZS$+Q^4;&0+u&_c_WWdVSKsdKjQRR(M=IzpG0-V!-YPW3aIxOmvE>wRXeNmeRJHzwS9m(xAo_fFrMLDmlu1E-J-z{8ViM%<_q0^5 zUF*LS-3v{Vaw9nh*U^?`z2gZ`@0T^ru?8s8c-8CE5YRPu`lzvo)TI$c=ELA{S5{UR z&*j1aY&!RqC#g=v6T|BVnt~vX$?7u10W(@;l?ed?`b)e>j&tt!DwT(xOq`BR6|C{b)Kiupm*SDIT{Ik<# zgA&%f_-OXCdBM87gzL(x>u}F#Wo4sp_TFh-&pFr`B*BpHf##ru&595O zRpohDx{#pH;|G)Y8zYHy;ZH!zH$`%0JrAcOC)O}ui&RB7Lg(R?>_|I}lyj_!Bf=*F z^qoO;`i77VoBL_CbY)jL6GC@OT{c3?uxmwc>a)XuNvXWBsc!Z~^ zWQbvo%PGFj(srDI0;`XW(Yw7a@E!Q|O0J)f-#JDgwl_$Uis#eibZ-S=qPaeZnvs zHIK|sml-rra*|TEU(fGc8KwMcW#<54YFsKO6@cv}a^z^?2zLLrxmoJ=zKJ1uYV7{3 zNrCyB><)0_fv6gR-nt&NHQjQ$u4)Jm%43d1t=uBbR@q!`%Rs2AUs5AC#miGCI&@8z#?!v^hKZ_8#>GePVCs`nl5utBmF_@IV>O{F3)G-;$+f5r zAZX0GLh1yFwH2F=_x{O8vTZzrKkaGwkuuaaVV6LsyT!IOsO4T>_>&b6IukXT8J8#= z0`kvLKG42g4dPG_{o#FNaROmVHbbhMW_f2-9`66&RMkZre`nEw&UNC+Db}q6DTidh z((_aU96|l#M_x6*#&7#NLwH~!H0({uY#J%!D+~ZX% zOn7!Kk^8s0GO08y1PWFd*Hs%a$U;+JCanaYo6*TlzOU`2l34XpEYtn)p&Ox2##)B| zWmLlDJMfpWLz>${)F3JqJRBm2S%|tn$@W&@3k`3G=C9e^5g^IuK1j8?gXS#Iaa$R~ z9wqsRiLBIkd;q`>Crv6;MVR??vv*yA)F7phuN_zRry+t=n(!5TCI+j$c7yMaq0h>> zD-xlu1Tm^dIkwJ}x@^CL(}2xfa_` zdTR6q=$e41{1uccY1K&CEwk1*%ppNXi^|195~lT=3+qG+ymBj{-AF8jeBhc#(JNUk zdd84(;5dV5*1xyiPyQS5hgE>cyd6|%oi=xvm4_eRBGi@Ic(e0I{7#?$UUZ80`>DVEp(p&yPkm~nr}ClR zD1Qbrscdc`T<3(YMe;exNrB21jts$P{iFXB70x7T(*LyHL|QwdpWqP!l6)rYQu1}h zJ3a2pW=l7g+|j6QGx}i2C2H5v9$5tYI+m=-5S;-J-3Pc>K1=FfE0Rskqf&$maSU#>^Dts4I) z{sG}LZ_=CJ)o|`&vNL;<4hx8PgPToUld{T5h<+J+rV9WKreKETJZ$xLd^Ptv4APc# zGgUn%SC>Yu%(Uij;3XIE8RvuClfW7p2fiH{+`YQFgSSh%kBN0A;%(wYwlQ zLLMFWM3}|flp|n*lkI2+7WXBch=lwpK5QRW3uE_~poR!v$xcA^at~%a;xI>AzXvDX zoQ){Pw78dz1j8}C9yys7$ka|7&yn^k+!VMH5suHq!vY9%$e*;e&MBUWq)Lw-*x#uB zKO#x8xp%k;_U+Q5rFI6UM4Rb*_4ZJEh2NhdybfxO|FU1OQ#XwwNPLJi@c2*IR`#8o zZ?%eNZb(QDR&7absbm9zba`sffv9?(Zg&3Els#7UmG!IsAwh$ZZa&vzUH^Fb`tYQ9 z2;D9m_gLNX=OQe5Bb+B7yS*AMH+zEOjF9zBEbPW>B7Gq=b0E68!0aAl8~Hmo6M5=} zw89}Z7o^iRaQd)2XetrdZUrGbKbIk#Q8$yZU>y6ZC9KHNbs8#=STX_M#7CJa69=n$ z0RcW39^NH$SA6_Dj7v{tGoUqv=vA^e*`|8+I4HD9o%HM}q#Bj?79i||O7KTciFg2V z=5p(lx?(h;!Q76Ro37CB{WV%?pkOc;53tdT3ZbPAmgsMpIn6C&v{d{eXP?I5McQFS zL>acgM)<_tgd$>UE;vUiIo>6TDRGm>K$aJ8ZhF*|O%Zn#{wB;Y)QMHZlJ427Xg3pg zpUT^l2p`WQ-#fXkZrwLdeto)Q=kCp(o=l4Msn&fL(Pk(}@?~kUHXOt)vKdu@>M8yu z=Rl?oUlzsRx0y~M7p|c-EjJd)`zNbxSWE)4tSgOmbgOfqRl?2e#y#O;RP80$be)&A z|JO1GZn`@z-bz3q`>NP_;%UAeNmS;upxJHNQsLr2f z84sV)Ub_iF?(P_ps9usJkX|cTf6FhGq2H~+b>^JQx!HZ-R1vX7ipyUYh*`NrSI3J(t3EpZ(k*hZR3)vS*Cf$T zmd$xh5!?$HvFzwGd+Jqih#91Vtg2ATuFs>RW{ONBQHzKTF7?7L)e6nV(b`+YWY9fM zpiZ#QJp`>%u$OWy&qoIzPK_{{57SG(g4qCYZwXt6sD2RRKE1skwzLA|=J>JsEPH^@ z3S#5`^)%YeoJAO0dd)GkM6=~$NaL7-vLRr|;RReI@*>z(u3u*WvVc9y`qt$&cie01 zNP}xE5(XWw6q|=2{#S~~fmy{Xv<)WV+nEu>@D|36UD5_}Oh+`wYQg-Pu14Oy@L>de z{`-!q6C6HMY_S*5FZB`-F%H#Ic&`?*B+5l@bpjc9Kc{n`S5%&s-`%OOSi4b`;B{K89MV*aP2C%?$8GT8pTPB~7U9<~GCpAJHUiqT@D zc8jE0dQpnJ=w*aW!Ic_mI1m;X&!5i;y-F{$K66$^CZvY-eS%lvQo244)flQ3mPodn zm?*L*V|2H5Cd-RD%d^^zx-Q1N1*Wbl{8n=U5!!d_n9W_z^Ue)_lU{VDXcKH)>CwM*fkk=X`Pb=S|ptxGCtdas^VdCVyb# zD{$gtw)~623l)Y2ejoOQY4FQUd|K9SGP1cO_zia~0I1Tm_WHo-J6TeQJLK7t&{?DL zG*@1HyX7|vr3yv+6mwN@Kp)_fDr6aom2t$y5m|bQ1AAgryMNfzf~V4~Hta4~hP7|c zzIA^>NNWIPhis9}XAD{Ea!veJ+uj0bwBB~a?<+C?BcT8)b}YPqwBlCMOKfnWO{rq6 zyTH|ViE0JsW0y&3$(7^fSfa35KHDBHW|ILt{pwf{obHQ6=>cSt4PpVWWVD{Amtezf-?q`LVveF_s4Y&MzfXweyCGNc9}*292_BIw~Cb=qO(-RH)STR-2fpavBVLDgP|`!O=Z)z^l3Jk-+; zwCUbRY!dT{h9m+$LNLk^oGm3Bi%%1H^ufp4Ru-Z#?u>_B^i*|J_=}`LYN=gC&Icn< zNI~rV%3^Ob@W)}y9wY!7OITXyKA_i8_(OSBZ4Au8E3%+(Z{+i@L%*`@DkY{JK@hbe zgajc_&A$X`g!QAZYBOZ}US_MXI&j=eh)QCmqyhKi$XV5^Hpu$(ee*Yh_Q#wfJ}s^S zUwJ21me?%fkd217ru3?Ae_?Mw7e_1&6Oz0%9J+%-Ba0}&wl0j>p$8?vY}M(BquX#ver;1>G- zs^Arn#98C6g=5O@r|?8b7Mn<30$&Le`NQt2z~pM?a68luZFpzT;P&I$Ji<7=z{9ik ztn`b8fF=y_Y}7LXBiQ)JPUYE0zo7WQ$qo*g?r-R}`3);&dfD`$gLiztbGI~zpGvsn zXJG-FN!JowQo{#;Uw|i5m|&{4Sr5$t!;u`kgphu)Ejik?#gz33y>mx(8=fkj{xa_~ z=uisyce}T;Z{P%=m1K({2?+SfWi=8)G>8{g>7!q0_of5SSBg#0_`#Qw?h1&=9%e?f zK&y4)+UnZ?CgeNXV^+hEh%KbviBqPQfuvj)XJuXX?)(ZO;VeE*>~rveKAM88I);vQ z27KD9I{My+$Q1tDGcda@5wa#vbS+%A2v*h|N(ai1 z-xb{|WEXAiE>}lFKD)pU;znwkg{2M#zX^dzBE88{DIqGUi0G zF~TtFS#Hi4#>`5D>a}6u2F7vHu=7gTmYqW*toWIQLATQ0?a%W>j~nk57GL@DzXj(c zENKKKRRghZJ)`ZaJl4cqPYLuhtu%IKd1i@C<$jZ%vB|iwX*LzD=55Z}cBwYfSIQc{ z!Wtv;crn0>%&x~xzQ?dIHBP@%2r6bJkZrw5J-e!;=%0ky60e?{hYX^qiC?Jk4wNlc zM4f%BQ{J0@H5CwJMrnS4Bb$0sd9I8v8nh9RYzwQmA;m@HJRp~`0t*mpQ^<^{NN@;t z?K>SmU;*@~_&{~-q;mn`iT4D*IRWhxmzQlT=VaH--E6M+GE{l;MYp%SPmbrNxcGN! z-+yC0QCoig80spc$;foYuuTEgS+5cY-0eg5qV~wvk(dB^Qr`=q%_ydBHSk}aYAs&4du(*<#mHiKubitR_otBl`ZwSuM2KmUq;9+SpG{XonZNcW|`61s%Ocui%>?wryVHJ$8>6JmbF1 z50y32=8LhobKx|1>xrBy|EtHr&aw+(t`1bpr0Guw)2Lke?r(#ynfPTb8YXb7*#QSId2UpmYiZaANJf^}xxhM50)@#Wq!= zmrzHs9$=_LtO=;bjZ1P#lD@KIA_X5kDXez$I*qTv2mu~4g~9tE-5>RyUXBIyw&GOn z7uSIG$z{1T!KxRqIPj^|!#|~#Lv|9b?ylOnfV0onW<2SEhm>nObm!rwhI!Kn%B?go zd8}!%*ag9r+QiIT=!0xFT>Yp<90jt-5H>ZD4oApmR<7$H;hZi{S|-c_sEjfoPjatZ z06M(c*Y`y&@l|}xfa%Gm4y8$)hGxrBh{l9r=XNEYuEni9?EVNOe^d;x1!&xPhj9z6 z*7~9K1T6m``?4*q%{$!50n-~slhaAJo)3Rr9M;skNCj1kz9J(|yy^16Ao}(X{YD&Y z-V5c&o0$%!I))XMQrd<){iX;lt{}=igVd)R_%DKKjrl}1=q^fhVZW+aE|JM??zGCdqACozAnR!;U~EfIgn1D9{v52h9UiB zqWf3BJX)M)xsxahgMxDidml>RZ5>+n-Ei@4aboAb025JK6iTYR)pE6oPyZV~y(^jC zy~y{cfH1W2Z@(Fr13cvg^$ff~N+aj|mXJE4+bj?z>8I?!@!c?KAkc;~B;ijf;d^8e)D5R{bwHl?Y`v?9Q{5=-QaDaczC-fNb6 z9Cm-cL!pL;PgiQqeylS=Dpu1aGL6m;!`M3~Zsg94vc?|%DK^$QiOg^55AePWXi7f) z4+}h7ob>z20b5|hyMW#K6ONO}SWEz1xK*mFbZKFoYkeNuc;%NIT(y(~`(4!sSug-5 z@A-zsSGMVPd8XKfS?;12G58Ryb+B{qe;7eAjY6K~)%+B;CtmS5t2Ig{^+%S-PNvPKYx!|( zN4BblIYv!YZ6u-rYvIOhDnlrU*&~Xk=Vh(4i%X{ht6%qtDpWd~li7&UO=cV3eU3!tAfe$Z%(>?p>h_?#W~#TNFFIzQP# zuh#w&T(d{ngsiLk!hdkSt5Z!HyV@#_^Z=dEkIaf}o$`(#e`3##=+E5O$~Ik1yFUMo zW5ojP##XB>kNe_=$pD+0fVXWcXc&MW%2MB~Nd<^{=bIvk0y553H1*H8iH}jL<$w46 z!=j*+-;f5pz6K%M+K#l#k&J77tE%Yg2va4{w#mi{gfD!GpH6ETr?@N#ab$SbJEj zi<=QF!(+My4jKApP&&PsIP~}~jV5(qUohMf6X1A(;PsHRo`D++W1c!Yjf3UGE(7B0 zQk_@+g2Dl-8z%Odd!$-ryZ^s?Ex^xjV%Tn8__o*um2l>)YDNXc5}a~*Tv#gaN=jed z2{g^2zrmU}fzI~+q$qmT{A>_Wfwiq;LCA91g4|90!mRV*e)4!hZ&ZbQ56%fj6XNTi z<$0;9sYq|hV+GdVS1Edz91;_H!;HUI#>VLc$x5Z2bW83__mxuM8b#%=_eJm+H_Ad6 zvK!iy!zhUN5GW!2z=GdqQDKvcUvK!BJRt!+;Ivr?=$D+1xX@`53V>B>LYq9*)6VO9 z-L*1rG}_B(_+%-*>(i||Oz2GiqeIUqMH~o)jwX$Zc0q|`KZvc9@+D_d6`%!Vu?e0< z*o-JUB;4Tl7Ju&(|2AJNC`x?LEhMHUdd0Yq zFaYAIx7PP&CB*2b1ahnxGqDs!sIrp@0Gba}i&}?RfwhkQW3MxYxIb++<-@+5_0Y@~HsOk0o`02hdz_qjUL+az7ImE`$a=K9W4p=hC)6Ua^hjqP@5cU!{62AFn zr5R4uDI#GDf=HzBTBorNW{XWZbFg&6in#sS%6fvk6uv9LRF$sIDWP!{M9$1uASEQ@ zq^r`L5DIaF$InoukS6DetqSZ7#4pHcJ<~4Z_w=NdA@v-6&V-o>DB+X`rUM3Ud-PJm zKUebfR3Fjhzt~f4aijNk#a536!TivgRTOjCqSDDV5x)~ks|#6}*CCjw+DlzDt9_x% zq2ueQNQVpjZ~z;0T3Qyn2sVkVaiVC`m407e;+yXXs^@8R|8WTx=f&9a#vJS+_I_VM z>*g`k+soIg9o7zPoH!d=R9!T`HtMpc!*@rZf{B-TTsS9*jPMi4ijcQA@Z!I$ibtZf zpMs8}QvKx6<~d|a8v8AEM!z_j4&>rJHtFTJ;-##Xr&ZXgCDt_s$ z>@_T5tilD;cC>pjl>C!byX0(!m4@P8S&w7EX~JU5SLjfWbfsPkkn>!qVBT?AR;ARn*a8X^} zbWo@%qvB+Pt8XQGQ6;K3%k|P3DV^!|fSPs2>;mz2MgvMwvg(ZxyNN;+$@b*5?D=-o z*Td#vpr-g|9~p!Ib1DP7{ZT1EO&Ta>Qop6${uPgLIJ z&`3r)$hv#gd7C-F7A{IN76Hptnps7ZCgNa35)5k$-DK18f+HXyr{9YKqFi6oDk1_= z?O_?L1LqvKXmMKfsYSe#4iKsb-mZLmG!!RI=TqnSS7@QFz zCV}~~c$Z^hTqy#oZkevYW*qwJ)#KCr&UxGZXX}D`Tka(kioDmdZC+QcdcQ?g5jZZM zXQ!t=OqG0ebrzqVewFa@oEG1)v(C5gGbO5zwNw6QM%U&MH{afID0CGp*ZgGCVhh6fHjg>CPc-5UuP-$2ID+) zi?v2&h_bnXl{*-Yk-N0NIlr5Hwt%1Uem*`*bz)E~N6jCm&0ozr53{ZVTSz5chppl1 zp`*n-pwAe>k9cUS>hxcK&cm0%Cka7(S;xecu$?l8*E3No9fle*7L-*TW|Jtj*6bpM z)k~+kF`eC{VOs3uxKrlt5)4g*7P8r}6qdih0=xNHaGuCiqW3FwI7`B&SIL4jw2xSl6I@VKsxp2xp)_S7qmm+|BHep1;Bdg# zFw>mjDrJsSz}pyg!EK@fFTTKZ+u!K~%2<4`GZZY0z0G(l%CtK8V?YVh-nn!LKu?oE zVfhSUY4zuyf*{zD;QJgBvaU`3ksuF@S6Atab9OF%amJ<7Xh8%x z;SZqOwL7A|O##Bg)~eiOB5+nqq6}>#GHrzMzL#T=+ui-qEM3q$wX*`Lv0bh=Mpfmq z0D|w>TeleT@bP3bIA^!tVIKY&l)AHtvUQu|)W+^kKWO*~D6F(+Kr*Z8_Ibyvh+BZ< z5+`)nx*6{mR@6_%Q>E6sHqi#gsF5^pot#NRH-qI|Gd-tRLV1b&iUnIXY$iK|M`*|E z)c%sBR{RNtW`EQY`#hD`#`=blxBiOp#x@5TFK1>%#}PE9XsV3wwKPqrK2tdsXyrKl zT~*{ok1SCLX9nQxbHiSkAI^?Kx6(WT<*xwo4Pu zKx?ljFy`jJ47T+AtJ;)5RJJAXY4SX`2vG=DZbs>&AGL!yhpLEXFPs{eaUD)?Ug2Zr zw|~Y|&w&kP%<_~Eu1>vo=%KFOXUtImoxwEvWp~ErS>;d|W&-K2BEH`(BdWUx}<_^pUE$=29V6U7~RsHn~EPVl9QbC zWA7MOLW%}G^R~pSA74G+$#?p1vXrfRrK`balE?2eC0Wk zk8vIApatnO_^P(V_nw$u6_LDD%?dW3i6-okRg=_!INgM*P)rpCP=@$hzCf3ZGVU*8z=4o@kM44WhMRhrRONB&`W=2CE&sq)AbIZqvH4C3nRZhNL5X=~*ywBS#M;wj@y&Q8H3qOY;nY{@1jq(;8=CBL>qm}w$n z7?P;neU-MZA<{ViXAj-bRl$_Q9x{)SOLK>%N5ur=qVA}tXE5lNa+_lCv{uQNEgSd9 zt}t!0IBgS$9X@1{UQ2eI&-p;T2laTM2UnhJ~|Zln&X~^r<=i3o5)9cxy*PYLQLhb#X#E&&pP^))_kr#HXL%>yu2E-CG1g=9Z_4krGE`gT+7 z0jJA%y>Gj46^^kO)h7YP4;4|W>%)67!TwOFcocTDQCBP)%R8IW zRFv_h@#kiEeAY5&&2Kj@VOR>B_HP?E`^Q`L+bfKqUTknq>t%Ybnw_;Z+)z-fZ0qMl zl<4I?eqk~tVmAJ33I&nrz2cKpJkCJu*$X}L9CP@1>Kq`v?R<#XT|!Lp<=DBb%G${F z#5gfnb&3~Rj#0f|3hmsPV5+f$QO(I>WN&V#xXDa$emS;vL=>XLBm*~>t)XoWW3ZY7 zv!-fxTLPu1e3kTZkU|ur;~o~>G?2v4A$;h?HcTk28u`!?_%dUNIVJFW0{57k3e7kl zXuT<|B2yCkOsYyAV}@>T4Z2oLtxZ^7Kg7o`BsQDjDGQ*prE%ipEn zRse6M^pxC!UI;D#=c;52uv-eZc{dT)$bqPTcy$_cS<_K?C_E07sox>6ELk^HJIB^t z`=cy6v>^f#Z=660ySC>-BBLh^TSzu|-J|MpFeZxF&KKL=v%aw6#{&`hMW5D68rT)@*3P*-x)x2q?N?ep$Ke-4C~}?xWC*O7tgKtvVKwJGtZ?)xyT4$nXN#j1U;OqZ0}Kn0-pc-py} zm?9QemIGeZAqt|NjF=W}@NcY&C&8ya`5f?l9@!sP)?=D|0SAhR^HNugUhegu53dDl zVv8b;>-;3;lgJn8FierDmfZMWEfM_0JYyp`UZ_P@_IKs#kiqeVcdg`gWi!b8K*Q@E zbOKl*!j3R0mwjjZT96WG0_SL6SVs#^T!;F5jCqrKmv%W8b6<{IesXi}M&o=*QuKq; zE`msG zc8nYkuWUN34yWUE197tWfcnC)2ON+sX7QjzcGBezvTLH5?dNXZD?{+t5lUu=QBz1F zj`Z%v(Gbf-kwSeHBHDWK8B_U4ONqy|yaF0<5Gn$6M>O5?o`Mv?tX?>K8@(~Z8xgp2 zu_Jolhm8`?RH>n|U=3k?U_N^P3zkaCHT5 zm)MC(7rTFFP8_vIGXq5bhM^M9=2`UI1&22dBo5f!XX#{vkKsm&3r^15NsPQIs2p7n zvlHF^HdeHVSA+T67Qw(nbz_7MYMmi)4t`60Jc$JWyLu8jdd4KxK?sJjmG$xYdUyUS!9t#m*`mf@XzF)97yrRH< z)Ir@;aOLba&uNl3@dBCAik_z7OdaKa6M(T)9HR|NLMPEl%V?=DtY;EMtMkEKLd;H%MxM7yR2`%+0dHn2VNXJuZIO(lX=f{51om&0 z$|+Nv;p#n9e%aE=gy}YIS<6UW>}XA(!as`lCRqNK20Vm zJ(;YuK=WM7EEoy>p_nkf~v}+(h?J-RJqx1b;E{iNFj!qzhjyc+Bfc z?ed4HtT(X-8PxGyIfD>F2a5AA@d^0EZZ!J&$~D56Ro*|xI8o`Q}@{7Ynn0rM7I>TTm~5XL!9XRmG?S zN88Z*UQ9m;m|KCu=S*vo(h`WJ$sJ9{fv}fU=d5rw#345?<|((dF+lq;O=SF*NL*7* z-Q9r;6J13z___%#F2;LV<1PTSBMz#wNTE6}?)@`62Y5tK@01c(=}KMG2qh9-D$$-w z95MMV$j}`6iE`G7T7lU^6kxPd&XI!o-Qc4!CayS^f6t$v5}SPUo-u-2C0Kfj&0R~_ zufpM>2lvTlk0KsN3bSFj1h7*Y@Y)YftQrI9R|_2J3(`|MF`il$Y%}_LWXEh_PA7rG z>Fvpltcm7fa2TdnU_i1M6ne{xHsfDX$;sl*RGM5cTOYHJ)7kpJ)@RK@d-L9G-oWJu zGccDyRdpmtc1WcjFNpBxl$9X%)^rLe08c7oZc$y<9hyNB;)&}dN-KXCg*Rqf{2#kr zW2d%-{}~;`9ygnYT+TelpxgyOHNU#`JH((L;{ETVdiOv0eV=2U-e#{c_*oKOeqBL53(r~uNzz7gb;;a_emgKqU-Wv0ibqiYM?#?_+#QB15R= zsWN+E<9$BOAk@=hc@#oLkp4xmun_pQGKxa8gnQ}?gD(;+<3Q7^oZcF0uaXO zPjWD%yZuC3X~4>DwD#_*&22|3sZiLR9Km)AKw2%LQJ8euGyM7ek5_Zd{znbMHsfvv z?k}xQuDkl$y*jCzG365gog5oGf|r`n;Ga86%MTAWBUBEIuUi1)qq8Y16#HOS8x|?h zJ*Q$Lgmedf?O2bTtgi|ESG3N?ySpk|5HZqKdB43RSpD}GE)Y2X`Ple^z&i#u_&kWE zr_Hp%XQ`M|f+|sG?k7Lk&Xhj50>e_l+VYCRAd0cMmebgaE_SZLB`NUQ;r95i;Re0u*?I%^0(uo=A5$%By=IEj68kJ>_ZoKk%;pst{h&$h3D%7rWij$x*s!s-d z|51LZ|5AjAsH-ND`nmEhoJx2U-K^3*x0@s><<6x8!7c*{ufnTL%x=IY3=?6TXHM3G z@rz~P0ys>w(Z#rna;_`IkB^LR80e{-;&d#ayoSSVR8@Zz9FKOd)8+o7WW)bic2?qu z>+JLM*PEt6=@>keXfe~t#_H**kRl;*qpJhmD;=<}Yh!yWmolS|* zjRkdE(k;b(!hbE)P&9x+R}*}Z1Cq7JzfahlTLL1N40vi< zRcSdoHV85Vtg06tGl9i0VUF6z$`>Y&S*Stz6%1wL`Ie;j!yBuQWtojxyk05EBH&a2 zGKaw|R9>h-rX2@qB`tmv@$-!Wy*Z47Ol+6)RUpSpI8i-c8k$ecQu0D7WH~bopbUU( zg+&>v3IZ0n_;*N8sLP<2C=ED1+9Z~3CY~maq|^_PEWboZ7mt!m6&$YfLn@R*(wkw8 z)Re#1)*^rtTh%ei|2>aM+OEf0m?Y+{=BCA$QeGs z4f$Lb21~ds2or4qlf_drH6_tR-}PZJ@2}K`Z^0JIQF$46BFYs88)#}zuXQcV;bOuf%2i`Wt8_td=-t$2f;Zn#dtZ1~RFi zJdRnhyrz?^#E$Z8)p$gU%cSw#Iv$)F&uJWCqjp}=yIGEz*?b)#TH2d{(A z_TZS-^#v_}574!0tx{migyPxHlikIGedpZSvpD8@r&ZC*{7mlnAy-J7xwp#6k_fCR zW337%?uVS5fg%BL|DkpVf~^x(=N&OIHPh5|AwGoFidzx?vxg zI%cvKkF>q4oh>k^PtRr;WH}batQOeA!&E>i<^x5qK5cdlURjY`C8WseF^D4}ExbOY zrz;}5=wGV`X$RH{l+`Xd69N8NA|r@5lUpyu?YFr>LnLuU!uVKBMw(kojcLj2&ww z=QxU-2*ELb{l6>F0BC{Hn8QX=v&)N6Iy(1mPD+#C`s!;vh&AL0(3qIkQpxbT2ZdY< zBymAqJkj~(T{T;bwas@9K^E?-1b{_cL0YTgOS%K*>H^q)W}Smp~ZtnSz!~D zuGE?V!%+#_*n^zor@jD3)M>s^K>b|GX}TNi6{_L1sH!~kAkI1$RHwNY@Lzs_hAWKx z?Lzq#-%RFAqsy$-nX=$<>}oi4ub={8O65Y@+NuJgsq+gEEoX6*|ta}gG;p^K{OYUq*G zu|8t(-KbPGgoGi2XcUkN&rVWAwoJpmL zAr3x=usrLI>-J4fDVWl}V;yl<&pM1h+;#h!5?{@Hrn`3~;c1*Up5{60!U;Uco)PE^ z+l*Ng)`qSQqqs=k9ci>R)x~b7WLOFSQ*$l?(BSwtIRs~khU=ZuB8jAJXT>tV>)#mRk2%M$2*hyt%7XWgRsaT)#D}=49%Tm@$e-3P zn=IV)(N8O-)u7}jhs<{|{Je_qmtRG^Sb=?XWW4^+!gn*|F`c|HdcqmCcl?R{Szirj z*`$#I;|vX?E9mnn!+56UyR-uWlJ?^2Ngh-=HAu}fOaxvo(7 z)BqHYj|nu|1Bp46 zxa*Fq*5P&6eKRQr=k}C_4@^AZ;Qx~oi{f%ChB~AX41K@Ljl>3qXnTuXK;D_Mg3HE2 zcP!?S_*f@4Q!7q%_0hoYNsz%MZ|~L3J*}U7WzQ-={NiRP#$0_~#oHNrEfl0hP1HuR zS;j_VLOZik8X1E1A-7^5mB!LIDqYsfsG1h%E;#0{-m4`_5!q2YU~ITQy!-5(?3LTK zR|IOl{tozh2CCf*GX5u{4=G8im9y!a4mNCh#7bcbsn>r!iYY^R&3`2r)MuNflTodE ziX~O)Du{AiiXP102f zl|5rH=ujlK&AxGJ5riGsN_In6?xFL>osNn^G#%?*8TOv$khAvLpH6njBFraA?Rj z3gj4 z?T2kcl$+Ato|b`HuP6QGO>S#65jk9uZsHwJZ5<(C9OYXXN$z+iT8cHqu2z*2!e1f1 z%u8RrJSB$>G_EBG z=&3DO$5mc_PFrgxejOQkTH}c^>2Ttr>Ct9Ur^U~$}Gg@tXrPyN`dmY6e^AjrkwefZ;)R3^ewxy0>)1AiE6G$lVk zC2zE*K_n#JuHoTqS2mtKv0CEAftEaOzOo{Yj1o#?eEte&V@WHdB}j>BfN;$))|ryy zY$gW2ywPQq%uN$=v_>$kDumW-6LhB-ikH_bbOjj?&nCNRz5OQg$*D)A%St+l^M{3M z?I^_RvXb7*r!nEX!#NRvHGo4DVD4)Dy{raykNm*Eyk_qF$|gBff!>eh3btQsL?x$Wp!5Jchmdo0UsJRs;@z)AP+= zzgQ}qMef&uF`xgl;MimtFn5%c=zKr9F*xq*VMb9}@?%ef|Hq=^zf+j3#&jbEdL}xR z@;dJ@#&-fX(F@$+POXb!(-m%1=Ff8#eX3q^K-XopHe^x1!{nv0yddq(6BZ4W29GKIgciVs@O?bRf)lG zMy(m>K8y?4!Pk8K)8N1a0FRPO;pug;(pZ1a_ol@QnnnYvJ4sYTC$C3tqoIZD#p=re zmelyL+!{Ljp_gkm_`|L29vik(TsPLl%Z>LW%8+VCAbme+;du-ZuS_-!B=jg8HL6u+$}qM#1WsI^3n- zb|pdoXW#4+t5&W6_ab|_NnXA3S;MehzHk0Jlf^7|Zswv70NL1=NKKG%3VQRa=dY5pekvj*#bym zVB5=blCPX&&9x!CikiY44KZw0-_NJSV55LBcYAf-fV5L)oFYo;*!kjxuc9$d==pS; z>zG$zA$7AlJlfSvNk2EP4GmFX%;dDmi9qp|+kE}vLN!twzAQBV33~lU@J`ow#xRkh zW=Jp`f{mh_d^e3m_=t+K$miH{sBne0M(DUez{1_cyDPQ^*4>f?dqX+;Y*a5w6EP3r z#d>&~i~9rAMo2wNC#VO(_cV-gcg}3bEXd;1b?0S!Hr2Jp|I4{YtDGONDdS@Kl33s+ zr2dtPCri>i56Gy$hxtpMl%`E^k%r}7=1|3?jxNJN-G{jg(WY)n*-pefrO$h`uU*}U z3A{afy`GCpGn-j|MQGcj*+%NZe5quUV_qe|6v8u>_#VbP|61%tCnqWhmKv^?Hg5ZlW zW~dnRMDrEt(jFSpCXv=Ey83yyn$0%UvHog?u#ks?T8Kgh{Sbp*8HRaQO{aS2dn9 zEumzUe;SMmCT4xn`n|-{`e7t_5s-erOngk1rvEJlNy*hvn$i&*r`52(HWNDitubjM ztga$SjVrTj*GYWWR0`4&VwR8N@Bh0PwYLF7D~Ptv%nMPQ@92aa0%L{%=ouLOYg`w8 z{M1j0)@xLbLoR3DC1If$xHhpQ#B*Q_XJV1n@~O1~6mx@@FcI)!LqH+#t{H({cVwms z3C*x7CA9(V3E1bKBKIhHygU*}ZVB|S+bfsZ8nltV1cZU*5Q0X%AuhKQf4pH4@Zzx+ zvrBoYUw`XBqj*%90nxon8jIR{*jwHXgb%zNimt5AKzXaln4U!J|acag#zsItPImTF<&Cu=Sy?(lGT&7Za4dP4-5g` zihZxWy~pSZczK_YunRqXgJBvqXg3}w&9;2XLn1m2X0Z#W_qvD)GE2O=0Cg5s>DX*3 z#vZvs9RQ8<61%@Mpc%~W?CaaQ-B}7!<7W@F#|b4O@ZCn*a4Lpfl;$a5a%(-yy(9_b zkG>SnX*Y7LGnD7TK zxtKmkeXs~Uc9S5wdpY39J6}pXY$A-?vgIrSpDUU3;k&{Lb@8nyjdu4%(f{| zrH9Sz+PX*i8Rz97{G9e!T8;JpTgN=4kr$li6aO*hyXa_Vpi6t{4h6&8ATd3&+LAU` zUn@>9fLs)D5FXz+45;H3y*Aw@AyUm8dK0s2#&qNHF^*TR`sFKD?+}QXEeOnscPN`EGb_ zh~iNsp7)|e1n7+*u43of)}Idv&G{sh+lYdsT=2~yo;M{y5C6QmOZ;BfVP58B&xf)R z6f@Bj$Uo?*V;1qMF&eZ`Dr`89Py=Jqt}bYRcIr6RGK6AaK_Na&kH;{EALz+t#(Xz% zsD!v+Y5Q~#6ojzKHbiJKQ%{6C=|w~XiQJ##fr0U36kX-&bXm_n?9Mx{C6u->B0>&5 z;#VBb&+FC0!IiwJC)P2*{-GrP$gQQ2%{!}7mle(fEWY`~xqL#x5ON7r6CZ zRz<@6xsf@#D_<6B2bC+>PLMvjm?hFT+sBp7pOCqfWjLGAD}|=c5!8XDJd8NTK)FL} z?ovZU;j+^6?B z4I<+6%)8tQ8j@@VzB101-%AirnxaB+g7=eFIHN*TtXLh{c?C9n0g$0aje^0AmuFt_ zI?DoUr=mMBST2c^4>6o~A>Xp)r9?KKpo+(@X3k@+I=P_$iY8Fm(r;fFi!VzcaB#Z{ z5a|GHXuAVv$5*wzLq%tQx~1j671`DiIe9RlwlIDf0I*+-&F{Ma8642tqS#SN@;oqf4c<7 zBo^7w2ZTg*x7~m#zEEPbza!wl;3iE?ULy-2dm7!`<_1VM4aPXvYAGreJ;9n=P`iv@}(;-Nk$E7 zd2KxL=r3knWC|MHYu}qD^$Y8T)JedpMYn&{(K?F4ylGO@Vr;8B2PFUkY{COxii>q9CyRD$Pj@XuFTm@j3@ zTDP^pUzMU@A1R|v!KU_~4a~oG^^uF;$^omY_U5d(j+RE|l(O&iYnyDWT53ALF5;yT zyRz=cGBYwdrG}8F4%W6=M`&&fTJ*poVtP%GpVHT9d{GPVf1uP*#$*uf^a(VFht8lS z5XLs&)64hU1~NZ3acc&Z3C!0@aUf@EVPzS}46N-XaaHXv4;xRx$rWsaq-4}0P!uYS zExT1L^ip`BPh={02;IbxVK_DiSd6zNmaua9v&xu5Jh#euv%U~He7o#4`%q2!JYO|a zKBXubtVN8eGbjoZ9{t=Inr&V={w*|AEO`q;G zN0|d4t=Ug8x+4AFWInUKw1{%OILEYvmD<2Zuz>YLdEFS+RR#x!Bi|khreUIUyw$5V z{0&~rt(R)1bH5{TWE*9Uz4Q+LgH7-ZK{5mmiM^I>7AV_R{DGqW=`1zs8Ig3d>R+0H zw4XR^=17XiCVMS!81+FJFC4ul(5GIn6{ZQ8BiUMss_XUg3}V2*nk1!!eU_?TVh{#9 z>2Ht^G-OV#ifBOsmj1*CaHB1A&_P9hUP^C161(`?|Bng~)T8?^ENWqSiczu3Avu8B z0lUBX^dPavEg5wPo+vMz&h!#4QuKvm57jpk#9WIjQZVI^mj>sy;-GW7hVLr1#e7Z} z4P@w7Ynv#mrVuwZ`Wlc3BGb@*vD|58Eznl=bfdG7|;`dylAoGFikJ2?-*+p0&1B`Sya#6Lrz}?&nTNVGm?3`0ILap|1*S&h{w1 z*}{4~ZWL(j1d25Ok4pM>_&mF99h_3-8e*{>`Xj3|UVAJ6_{-*5#@ZaV0gvP~ih*u_ zTx_kk&UUbnq;!TP=s{S=Y=QAko;MQ_Ulsb>%u22a(oLaAE5|jEY=)zrjZvt*6l0F7 zSGv=U9A?SLsPv!0_%jyOvx~w*zWF-%d}yZ@AiCjtkJx>a)a9AKE^Wwk*-U86-`y3G zfsP1qC+9;!_@?p#g2uUs^1$YitJg?mOAm)ge#L?^9Xm>TBua*-9E-784Bx(Ggzncm zV!1h#$Fyozr~toM()a4u>$oX1t#F)4zoXxXg~d1&&?iTXMGLkd^6jnLlJ?+LNBEOH z`kxDLprx)=S&hAJ;(zc|7m#z!;9XA-C(_GWtNEt-&8D#a|n{kFuW|3qp4;~ zuOY4M8tD(?X0{$RM@c;2<)x-*xGp1LJ4){pcP>70*;zn02(bFmLN8!P7Y+#<8}!1` z$E*ccfeQVxSOyRXr?kLL&a<{zun3W;S$tb24)O+M;gHISA^J48aQPO_+E zxYwOV#%}|CXC5zqSYKHNm22}B`_165uQ=G%1%@)n8z)Gn#0=?7u69PLS$Ny?i8QIe zWC4+>qr-dkW3SMG zb>ukgr0zeS*#T0K0}V9NdTnr|oVBLE5@ug$G+I#|-J45@_m)JC{*W#1Rk4r3~MaRrJ#n9nv2-DVE$6 zBSg@F^BxC$;Pp#vs;<2+rXy@}^jZaW_&etq)T7ne*1MugNySQ%R02Z06GgXlp@mYp zEZk1X8VekWY^9c#o9qLGWmT~&2Ww@)%ri*xAyj@KvLy#qmj}jN%cmU6F-Dg=Ds^@R zm3eqb7Dn4!TQZ19oaQk*0*#d%z_SBMgQ)+vkv@Znw#4Y)@hYBuPo*L&sNs5G`9mfRT`EhK!hPBaXh$UGB;WvoHbHdrPt?Ck~t2YZ&rXcVe{EoELzF-cR}* zaQh*^=GIT?g*EZ)ZEc?plnv`$ttd{N>5|oip-fvOWF&R4&-{adQJ8VqjQLx4L|ptM zBa9nLkMrvAz}enf9JHBnW503r-lyHfSE?cZ$^fyS;6e_CMv;*^F}>EdP^;8(_U9!1 za0;%%fwe3zTOuaX8_{&R)LdjgVrJrawPNU>JumFEfeL8bbPI@%6XIsfR+rt%htk8X zjmMPi3J;SMK5&`CgB;1q(N(OOFhNt;xUI9QyaM?*nL^hmWbQC7E_Jxq7hloN=I!fZ zAe$l%_IXBYMknj2OH;s_-YVk|>>+mnvJJEv%%|zc!)?5%aBOuuy*5N&hbL{~eZwK% z5bay{&=fWs8_vnlypGhsT*8ng-p7z8X~P_w==JToM8Q+^m+Zars9~2i1 zA!FF$7DdtNT+ey36>#(siLTyd{4Pck{i2gPulvm1{LhDfA+_2-1c55Yf`E;GRp+Rb zyFI<^N&Rt3^)_HOTvzt(nG|o4ICXIDpV5)()l}nG^mMA}TC+Lq-O(J_t8CKGO$wY7 z2RHo|_x2xM0v-YPci z;@8=L8q-BOXk10^Z(!gGcO?Z>Quz#a)0&1ITuL=0Eyx>7fUZ%Cy%@y)O=@Ix`Q=R-aFq z%`S95JrmB2G6QKNj{Bg$)EH9*RVXMkLlo7-J0Srza~CM1nL(y|_^So9Drt-POH~(Pr zas6Z5c!mClgST9(ZRuTD>9Ok6yCDCv*|7TvEz$(y?kj&9df69x2 z))w+6Uh17LLkzy$th6u44tkEts$AjkO!Dwm{}s_b0`wsq?t#v+O!H!(2QVmj3>K02 z+j0apC~rG*cKb3D znE;RXuFtU6!6o^<@>}&t>)HU>@KPhhAA$tVAQrVkw26DUt&iw9KlPUHoNsJ($G%!Rmk0_YRzexDT zkDp0AOA>!PSM@I|1cVX|;m!#r&C-JY{;9-2wNoxTaz0$ozSg{Wnx`*%Z~$$vz--(e z=!)tx`5ox9e-r`-lSRi5!xN*e`}DF*#b{v)juU_&<7GSzE)(l6TNNhyGps-C>?8hs zQkQoexqLqW{$cfq9mW|}#OI-`RGdRiQ1!|jpJq>nQ*M#QEl$N^psgQ}g4m9Djj%e1 zmeJRb6+yPHsr>V--+w@hbXNJn+T7yO_zR)2U_ypS=SU|F88lMYrAN6NPlt^e{9E=? z?g2CJ-zeWTou!bOyGSy`h+&0R?Q?j;2+kYM-#Hm=yNJ<(ujKs*&xC=~S(KiR*~3q3 z1`mqXAX#y&2V3y6z^? z%_cG4F-_Up3VyN@^s6n#=ii58K5ax!z*f0pGCDd=4RY{+h!teWfEh{r3Z`*O{}DZx zSB*IEL_R?tl26F))Bsn$M7j>4`TkjyE)27ON&=!1cxKc^y)P!f&y?NT`Y$`|uPUZi zw~R#|3w%2||1IcHW1s6&0@~6nO)|0%+)2}!wPLV)`#bYZxxv)j@VHlk0W!@*M|kUU zBb%Dmy#WQ1`Q+G1n51S}%(Ej!Lbad|#KyejvKAj^$+l(7g_Tt0WcC!Q_C3+Eu!)tt zKhOaEnW<2V9w^8V+~Qb^=&{4Wh>9VV*tdct+pnPA+8}jGEAL4eO8(XHJOQt`5s4)k zGsl7wBlr;_qS-h5fz%5aK4TVC6GUyETOyNDrC==uyBXBp`o~qk63P(X0Z^Wa8&FsD zIi&d}a{c>Xq5|>{R7?#;A~prX|CWMiP)KK(XzZmi8|A5RdZ345znpa;;I0i}?=7@_z-X9`9? zg^RU3^}2iG9^9{P0mph5jH=lmZS#5)TOb9nRf_ zidQ+6SzQ#Af*7mS){~!r=C?@E&oOP0ca@gkK#YN+h+>N37tCifxgAPui&d^P8{6Rg zcKqqPH?1~_TMheT=_S8niJmji=Za)0o(qsO)@4_!wFkngJ5$WuR(gx}gdH zKtuBLiudoICi;J$aE~xeLkc&xun_rWL0rqfZbNtWci}ZokcU|n1uA#D{c{@iAo0FL z%MW?KF3QAd@JB74aH3N6NN2M*O~th_inR%>!kgG2X}IYtqqz8csAQ|&7~h)HdUZyc z2_t2lOdwR)E*kUpHolOjO3=1_4XdbosS3Er+%1PU$(RD=VSPH9dfcN32UvyaQ^zfN zQ_W%BqCS_4%sO3gRD(Ksr?ydt|dgaD+;Y!-7des8{o_^yLc3?b++g~ao}VURFOQ&*mPItHwknic75X%6lFmdS@` z{{FhaM#k$!bY;vofTWGku!)Ozc;nNN5%YeWK7*c^OhqJr+}ImiJYq;KCEAn;d7dN1 z%T=?a7vrlmoBG8bL(Y5mbGLC9bnYM{lujtUQFa$v=@f>oc%mc^V>)UR1FQ+>G0kJ4 zDpyisPSTCo45AmvI*zUN`NdxXrvCoj-T=Xl%pkkQ`q|JYjxKx~R48oo=aW!ps&)XY z1rne9katqzIOCDZo`6{qhBwELMVr)xrGnbE+DF#UVj(6^KqAH_)rv1xyx$9E?WQh} zS2?h>zs(&0DBS^J9td~o!G1PvHK;IV3N37>J}WGezV1sA=Si?Zy_IhPS^y|%{8SG3 z9ifXkKgrAZe;0bUTZF=8eW4iD*O1^;=`?G+kkGLh;~JNx*g!uilnL14?qDOf&AF5r zp>zvxk(H<5a>=`@`5e7nRi{63_bw#ddZd_0b{ktR_|y835|Bx?XptcSbY?KK z&nP3b5I}Ntsmz!rS(=k-uCya|u&atMjs=pwf5M@fC`{+fa5*>uc+EFOa4~!BhuUem z-}jiDSvW-<9%!q^1wCH&u_v^Ah4O`!@E|Z~5^QsMc&8Z^?*}xvt;@@Z&YOQ?o-f%`%s=fFf z4fogkz4-L-JE-e3T~Lb(!-Z9wsQ+pO*I{d`$5#ze_qD@u+LyrJu$ zDnETeg>u{WPPTdHHGT*uivA&wkYf2nL_C19)Sf$-xB|0D+hJ>;V2d>Q00*d_DA!%% z$cbXSlBEbToa=AwO?yYnhknRNC4Q9^tiTi;W3 z>mP_(=LG}#kbk0b3*HhtOMzqLbhfBo26q-EJm{e&iO}cfw}hX}OTwU%b{aH6XP%bM zSl<6xYvrkC&jKmoXd;Q&!1mzl@0HWn4SgOkL)>xH4O$l*5tUFVdq9IZ<$PsW2Ojj+ z(f00l&bLMD5T2)F<#yymxzfo2s!G~#H~c;xQFIKZTVvjI&8~B z=(Jfq;$?CzEqBc68-LBn@<|?hvkEV*xua_MMTp)fMk@kOg=D7dPJ#ssB=Kj+eRO=S?|ItbD&Eg}a897`7>6w0MI)3@YANc~aZ$mS@LEDjS!a?*^%Hl5~Cn4{s! z(V#dXSEUcoOjXFr#E2k~1xv*Xe1U&&Q;$t)AyLe1?n4*q!}Hl-6K#-Ge%{Y6q?wOQ zwi%~@>8f3>%!zgPhuHRhvT*c08Gb87xn<<})xUAhe~aVYf6J{0W%oe)Bv6A38#@+e zdJX6o#M_n%WD?r!l6fs!xtKH6^>|kRF|&goXZ^cGl5WtsaERV%L~UZa5xNb9$s)W2eGE&A)6kn&{7iPJUYQqwRQUgw<&P3 z^^^>4VLR}UBtfRVoq?3*@TCBC_uAxwWjcX?RvpGJxfD6+qVuH9aLh$Vc%L`~|4^b9 z)1Prfpg|fTRsO~0LCn5bJ!HMG@R=;xMhn1+20SA{7CT6lde6L?znm+DWK_nLg1Y&3 zhOfn9^F#?_>L9s%-05M>Ipr&c!E;3+n$>L|-0myNZJ!P0SnLrEFP!J0I^Vzx&&+ zlWi;_mkuvOd!3y5Q{L2#-o8EHVShw#t|KAT3d)fND0&nQCa_9qE%OR&&N5B7b&R;; zC+v}J8F@8}QO7}{X?=@tTF60q7{_`qYXN0o$H8et0CTt3;FKg6ii6?HFQ4LvZRAtM zGeYK7P-=>E;S7_DLE%y6{x|j-cph07qMY!!r{b-mv%52^z?(LS9gQ^S(-|(qc%0IL zjLZDAE3n(Tpo*e>JQCsh1)AJ5-)@WYt&bxU9>?Fgc7uc50B2qDV5Wq#I;68MzFDKs zMQ5DdwxSraT&OJf+eKw-#u?bb`A9qB89UbCNN$y$Ak+amOwUzWJsrNZ>*M7`W@WOu`B$lF43U!- z0t|l2)bKqNGg>7^{ahs=x|zwp00_(N)-a>idC}zJl;5&q2IqZTm=Tf#vHy-t>SSsT z|FEW_ga}qxxqm_oMjBZH_E@G~_lLsy`OB=$d@Lle*=Q+Bm#K;8U%Ve?o~>%fUNo9Z z-|&a=r))`(vR{Ph<-??yy92@SWig#Kq}&~iR%)EYR3k~Rfn-YH!wjo)%O^e%yAZt; zQD9Wdmod?7N`IRHE}{XSuK(Y$g3f1D+hd#HVoBk={6LnxCw$BMAA{1N9{+|s}?LlRA8YxD$UhnJ6`nv z3vp@nv$hQ2+N{=_2LXQ5LBJays@p0TMrh3+jpr=GOiORrqlkgR7$RUY6?ZTr-X8F> zzvwW9oqS{r$6@k6+y?x+eGCL^oWtG{Y2J(0o$e5^MY8bdPy~n)^ETR+{R?e6g@O8T zN+S|H{l#|`5Kuis;y6Vz8FDV={^#6PPwD+l-}_|iM%C4jpefHCprmOl^xD*Hdk4eQ zi*F6h2JImP%F>+=-6oAmnMu`PeUc8hFpSq*HeeuM`xJhm$(OOJ{xR_zXi!BMgX@NL z$b{e5HFQtu?V%RTxV*fj>c*yhyC^S#FC#t0mbz6wjDhXD8bxz!;1HWJ0~W= zoDZqCJoX@68(P%h&DcD3WQvZl#OfF=pgIMW-je>QAggLc?i%vxYn&lSP?t6qTgAM`^|x`?ywrU#j1IaWPch z8wY`+jr$!%%*p2(b%-4e{YdzhRuu#243;dzUzgt?GtP75-Zue3Ep%dT=ooeRjpJ9# zR|QXO#1O$2zd4M`LP_=u-Ut6et0cE}0t}Wp} zOVl$?vNjgD04q2Hi_b6>n5U5kM+@ApuHPu@0I;K${7QSiQuKKhHl;!2xRUO z;R6lBH|OS~+TYteCI5Xu;i(QKk};h7OL7p*1{55VHin+3)nyEJmyS5jSEUNXfnx|B zL#B3m^sH?UTZoK*5(WSn&mF3VDRS37xJ+|)%Qe8zwyZe?vwrnI{Oha*8Yu3?my$Ng zOuJdTQ?j{WUX>=a^`&vOalE9nL*IMd_5uy~F>oG7>?kF9SYQ^f?4Pj^FGs_Y2v7u% z15Hi7khueYWc(O=8##C@P-FR2Hi>J$X?lLyt-Xwt6IZDuexl}u-4KC`Is(eR43^%% zLmqJ;CkDl%=GM@yLx|(ffYy zoxFw@MW8@79lHy&;L_%mZkG;~`E_X3S-6tMO*qeJ4*>Kfc2Mhz#Ex%&o=bq#tLZ>p zs=L6Ny*fuSBduj61=qx0s*7Ysv%)$ zSiTawIm=g-v-n<;A1Bm7bD*sJnFNO$HgT0Ho*%1<-0}*=oK{^7UetdE#7>3X2X2st zjY0`T#C7^h@wWqtVrh9cR$}n$D^#LRGiOpa!2-S-saIi!NO~lg=bCmy8_$d^DT#K6 zu%ij2dF21fzNmCn$082Mw|Mj|Qvh8rrKUye7iNZU*3}%j#f$L!1%P1eY(DqihB=1XWkU}eiBZLC$R;0gRw&nu3JK5jrMf3jBw?Ot5!V8LQ@U@S;na8 zY;*!^wM1tYgEk?*KRItl%?Gdif=s~6crOHffhP>=cN9sYz=^3#Tg|i>G6@l#RwN5p zEt-3Ovo*9RE!t>ha{cm5)es`!RV4U&=pf!Xu7>#dQx#6TAYqu;h4u#RD|oo1q|@OI zi6fBtT?h%a3^4AU_dq}Yyk0~n!wMKX%*`dV4ejB0x~$?fe}|(~w3VOdQy#Pe#*79d zOAr(J?2r=cVjjccCEHAemjt$B-JJ6%`Er^qDGMpa#xaXtEN-#^N{}obEuy zi@TX5_NL}?$3&oQ|GE7a(damv-519BWy~N~5^m(vaUbHL{Es+VP=i@D$#vb#rYTMl zf)eB~etT@5uB2scnh5j8AVY2gTvJ_lt$Urvo%gV368r^iph3QJUZxN~tntD>6 z-@*3nfbkop8ur}2nShL5X;7t9ZG9oHDM1Z*NR@lY4_e{r$BHuU4%#R zo!31OEoPqu4M5-e=I0%ikM~>H-tx7fV9#uUk~tMRgpEsoat55opAcA?r#0$Ox0@y*dZ@}}%L z-}ZHF!DhH0;+#CIxY%7nVk@gLe*+|k$TA=(hdZ{-nn;`$(J&E{E%xmlX@}3^;xAFL zbPZN7umhaDDqmkNKc$<<-zn*QOP`37bi-`GA`mR+a?`@$uRr|bH8O2I3dOOIJHu(z zj?XREmRsPBkFoL)9zQiRx!?fT&d?H&H(Dk>-Jwi; z{PtP`(F+J>1TcrdS)Nv{)pG4Ze-TlqKqV^sB}N3_LUx0tr_ID$XeLV z))|7KhuJaCQe%c}5~_th7dQyl6x_wFZw4avf76!TrlZnn&2&QRi8%Mq(D_fnuQ_JA z6?rwnXC>z$rFKCE?t-(++ZZzCU$dO3R;5lo)MPbeX*&wB<)`IQ2?w6{vw> zex~9%=+yb20g4BzULG2(cS~B$CGaF7JT(tpf*Rb-VcnnkJOwoS&7FfGW3O+qV^dbA z3WU?b?!@L`(=sa!KtMpaGB}+tnJ<{$8>89F+%_-gcY!up zVLu9#6kpoR^;NuO+}|ooGh>RmL$RPN%L4p%l4zS~_E*C&ZjsK4~cBtp;s@e22d z(qii)o&x*>P0wcCF#XF@4}4j-9_XOP6*<2XK*hf+|7c4oNX%|y5HbRS7w(^H`%YAS zs)4C%h~xIBEmXJ4<|pCWo&3zL3;xgmRE)qDAllE?w0|fqvwgoiiE`x%=?~C7HM=ss zR$!WN70haZ=9hY`FHoI_gA5cn-%}^1!77~uNQQal7m*~Nrl1rrq`my*vD^WT`4g1K zTZC7d=lznJUOOx*iAHM~i(ata%LwE&yWw zzLQwLbyK4bsajirCT)wyq-c(q@~XWb)xS<5v-o*KwQt1NhM0hTsZ{Q9RK}dFLsuK+ zkD%FF<)cwTF{wq9!({m$8|a2(UL{Jf11lush}&B+NH7(v0YorRoJ<9v$;XTU9 zvfoD0$#;t-`M~)Y$kuld;Rco1^%R zEcB1h);_)9a&*8i-FjP+bbRS`vBDH*tp&$nzD1elti73Xa`$)LE;Y>R5O=qOpyv_b z%Iy1+rp;!;iH63VNS?s;&EON?K+$#GkPjI@T=v4*xv1Gr!{sw%!O5O#gP3Q|4GKy| z_nAtW`cdR+MlCZv>7Pc2c@p54PnV?qVCsT80sINXI5P`VP$=K-er)!$RB866KDCkz zVNZ>KgQq|x!jTrUn;O0Q%#rw8kU8Zpwk#OQixa&`=ao!bHRfa|=No*xr zcG{tOX3}jBQ&`VFaCeZQTn60DjN2F$xWzN_q}^x2y3Mz}$pV?1Arp2BrMq#7RJS4W zmICB85V+1jWL1A3KBT+JuOe6Kb~~b|Cu+ov5pk;ggv;f_6I{#-BJu>`z zK!)9o`m(%o>LBP@k@~Ctq1LE1*nqy0%dz6K3t^5sQ&I?1#+lr8nMEy>NCs1Snl-wW z8DXVto7>6_1Mpe0-uZN?R7gJ9Cs+TLrtPV3sqbg1YpEof!K(jDgu@+S5xIZC=hsj3 zy6^(`puh5nKE~FIFcE;7nO?U`IA9}`aZKk-MzdAyoYxF^J1_d1VX5>U!lTV83MW2B z2J&NHS5$rMio#Fa54>FV|B@VJkT0RXCQBFp;&Y9^5|8ra&_7z}uL|2{i?s!OC+eI@ zU7Blx;qSj^Uo$slj7Y3kHEdgPHHo<%8Jez)X?DPIRtb&)tEHJ&uH4qus-a#T=bm#jSv&+K^K!-CQy+^Q7F8-M6Kw?R1>ft`$MTvO0D73PKYGf{q0p0 z?dvda+!W~<{OIVuo170Utd~Hal|ZgRCZr^KCqSMysGK&2Kx6h(jV19(j}jrHq#jnJ z8||5c28Tc3Ix?Oye{SfscfZFLw9F+aevftHD>m_iaheOt((S`vs=5Vh zAZj<7u$UySH1DpbxKQS&uM3|^=QR#Z7vyX5iA4qowUsb{{a6R$7e5~65=iU>J_Q=p zhA%Cfh-r0w9ISwR}cyJo3W8C9$lF z?!XP!E~Yz|1Enmd%g7X2Z>Osbr8<W0k+p7?nQ}B-#!n&3!@z-?)ly- zsj6;yM?iKkYCRi0fu@eGSTl1JgdX&2eZDO`l|kvjGEkV$i%VWD9vRiq?`Z&3zQ4=| zp;Vur?yp?$y}FLr_QAad*{E+O`b)=Hq=1l;S3`H!z6i6;hio-wUpqXLHobNwtfc5cdE9r}HNJ=KKbI z1Wah`QvBYmdXM5QM%gd(ia=>el-CpJJX|{he(Y9)r3`70zbUdN))4`4XUP;DL8@$1 z0$^JL)>d)#)7%g1X$nQvGCht{>4jCHKN-@PK=UK?vZgRcT1oJx#1(j%o72*JPAESf zVsSSDjvDhr(eAvb?r$qP-QxZcpuJ$1SdZrl4`3X~Ov!tMH=9+rj?trA?-IYUM>dU?76+S|NKX`XjaXutkk@Nu;Amq16`F{-^~%Cn z^E?X|MaCT*n(D`jgm#z#GrCBhyL=o)PGxG|>d7gN5%C^1okkU|JJ1TCG5k^fxy5*0UZe2v0{30)G}K`w@kwTQg#D!yRMFo4R*d3 ze}bH+>f_OGz}rl1^wo!TwS2!Q%fr^{ko=d8$WY89d~DXTRf$JU^IL`Y>;z&cT3h1P zL(iF64JGli5kshUSIXQknC()>e@P-QaJ74O`-E5sm=Oj+rChI z)(2=Nw<{ppo@jPu9Tp1$MvxNT{;*@|Tn;Xq+Z<%Fu2AiGnC4Im8bI)Q*~31m&P1K@ zvNo)WoX!vbUC0x|p>@-Uo?8`l#cKMK-`{wSrR4ly_zAY_U6mC}J+zr!{t{zUb)2S+ z)UvTrvhsbPxUzhxohD?kPU;kC(%jut)sVNeQ+u+o45Isco0OrbkL+&u$Q4B5u991~ z0$a89rWaFTNKZs2(mUT?L62dQUMFv$7K7E{s!wAn1&bl?A9I%gOF*>07~uR8&f|uj zITVu=Q_?-rgzn{>lTR|rXE$R(n5%j_8}Mc~CX5R=IBr=2#?s0j$t^gkmx>!@NO>{u zy2kkU^y6>{vQgL-SGw?2%5DggIc7tXMxjN-;|KQ~R_FhVW$(rBf89d@8lB=+v9JlMiXt$2oW_Ff z=B9{$tu8GYqN*+s%XROx6a}V8lW|M`)~nUNF5%Psjg&kXz$9L@-udT#3&pJRNOHZ@}xaiyV1aSQ&IDOdfMzqMDVz& zmQWOlOCjeIs@b@uBrI6;wCV^x=!}%whN|i9`IlSzRdtX@bzwV&R-OwmAAXjvzszE@ z__0`W1kx#iGjo|-Nj!Y3)f=f!0~HS(xkoh{-1V*tk~!%$9`&>JMtVPNmGiMQ;SApKt-bTB zJO~lusiV(5GyVbW^sju$a%(UQlv$r0;337G?^MJsaArSBpk$7&Q|?Uv`wY zW~b;fwgN&^uNQ^vg2d0NsS( zP_$|r5wKH|-WHKOQ&jsWZudvs%O}dvQZZEgYr32(`~8dG*eZqCT}KUu$0KnU@@_J2 zFyf{=N2Co(B81^)$5rxVeD|BA=STxG0)PI_oH)8NusJDM)Ym8pG^uz0m;N(F*2xo- z-4Wq0gK|+s0@frwv{}}Oum~D2q7owFj#?%eUySw48f6PfY~zq7Az*M5v&h|LNZJ9U zde{pDFa+K{b5?=HQ5Q6@(J<=y>Ay3;F4sYLwpRYNGgW!@meO%CsErsl7SHeV=vYgkL3Fp`oPV)@8Gj<<#fT z^6S^oSoV+Ue5RMh^Ly`C>MdN;NMwZM7*BKVune7UUkw%`V)}E-;0GE_-CiTJon9WdAEeT68 z<|=6$>P8kA9p~@HQt2xJ6~6>PT)kxLkHTvww849Vc<98LMjdK;TOPm^*d z_umRKoC|+N;YAaBlevPQPlQ2sdTkI?4M?Hu5RGw(wy!y@XF5)$uT27U!n?3VYm@Ns z%ZC6s9?BelyrX~lBJ?V%b%ZN>2PU&li#n+osOb%!jK{Gk|4Z7dsD-~3L$gqSB*L)5 z;`NJsY@Z>PBvLT)U;&m9Dp}ty0{Hp_RZ0aZWr19_JMtHz!Wq$vxV^1RyH`OKXkf%o z^*5eeP9+br=d1iz;{&{z(zo)TP^`yE_99LjZ?uJv`b?@Vpndc57R{Z}`B6dFU;<`>OO zaKEf$WgBj^nu#DUM{(yq$;hy#d+}s+Q1G!fr*ozxtgqnYzDOC+eIh{`izL)duUOFM- zRQkzpNDk-&&p9*WBM-Ca?muTX(r=_vB8-B1&j6a&XcvZCh%CKNsQQ&XN!GWY{Z1^D zYDIPqnmgd;)GYe2gBGh^+6^9!Sbbs37eeu)qgX@^x)S}eGO7rwD-ydYWCz0#>N6B} zTHU8EIn0_@t|~5yz{0b=+PE>aP*?)I#+tVC3Eu46ku@ z!b{mv>mFKkJTW zwy2I$J`0Y2Y11Ul8X~>Ck`oCCA97Y<-TjycFxVlVWHs&{`tokBsKO>x!R*&qMBE52Mvp^psQSfADL0jW|PMKcXq`?k~wHAV4#vy%=wv)03gm~c&tJZ^x=a` zarrwMD(KehnlZ^@^_+3Aa_JT~g^63W|Dam0f)VBpILUcfA-|+#(zpfqQpyOH(3@`L z(z|Fn%TeWK^E^>vpta2dS&4F)8hoy(=c+uZ0fBsoA~bvw{PA?M48|kSz;PzJcWLbo z3qbi*rK5mBk8jcznP2{Fyuqs1=-E!cFNynguNX}FF?no=kueui6-{dffHkFCi#=6CPJjbEE)^Yr;`U_a1;Y? zE+xYLcF!tLr+UOwFpp7ARCVp!*~Pu*%~Sp~k~I95op9o=v}e=oj)ity4!-*Iw7ja? z0YM)Qr@`tDC2ezHLA|uJ4R)@_0`h9Nt6H2i=rhD%+0jBZ6kN?Vmwm;5#LL!jGp)K~+uLs=m;GMix$qSIsigtE5^>D6ekcUbTO?Hv;sWfW7e7uUo^?9Oys_cr zc@GW|zS-N!2e5Kn|Z4`Kg-?eEn(iL1aL6_3Y7{th)PaySjz#nYq{W{3J==)}`!xGT_kNvRw z9@+}dEgQ-WL;V65OH=O_9G_Z(jNS>a2vfr=DC&1;uGj5^4E%LbBh(9tQj{iog^Vqx z8y(FrWuPPsG^@UPs3LEm=bLX^Rg#Lwcqb>MWx>?19B^!>C9R^6d!h>>4JG>J+?1Rv zG9g@p2q0nzD&7-poCR)<6<(>;VS2f1R4;@+?M~r#FLAq1L=u7_rpN-S)GCfRs9bcV z-!)m|R8++dg~rQJ`}?pdcsiLzvXYnw)Dn+dSLXH95<=ZAhhY>8!SGAXvQ*xVntC(O zMeP$ZJq`;QE5`%=a4*MLVN*{{_+ewl1icp!)$8hDzRJfs1727|b(S5mb{eaCt$hxl z6GteO@>&1Ns8>x}-IOT={U97DTL;m!)~~Z{+#FObCXcyn21|SlEO?5hSg@j2R5t#Q zjr5Xvn!lR8k&Sr8dJ^h#H6qqKCHKpw6}B%oWOOkg`25>0cJNJ}p0gfchcTTi=6jGh zb4W(_srZx`Vn0liD&-ULVVmIl!b1?F`?ES<(HNdZ?B{Oi1^OrQQJR8$uTS9l5QyrD zz!+-#x0M?P(6^TQ;wgS*J}sUQGDpyI44fkOe+xGmYze2y5Z|NT>#omlp!gA;-(}od zn{;BhN~X&u_wyva{7Q@WV0Df}2J)~a_s4AO#%<;xCc4e8?)v9OX4ofD+h$gcMiwlAb9r_E| z%avsgN*fb|(`r8uq_#Y#j0AhEqgL&vdOh|D{lY&vzioXzBL#G zl!00?_sk1D@2gs^vk%E%`jSwNqyHZAcxUC8!WX^`y@ia>qtL+|f%uMU>EFyx!*$=Z zXTa9erT*%?%I|*!2ZRK?*|&kB@N(5sviO6#4*m+|vcG{FdKulmRmP9bG74=%B)U_3 zd=ldtQx8Hpp9pe&YSkpgAT!e*>3E4#7)QUTe2=tL+a0gpKSg`PzGc*YI?4w?riq%$ z+nK`Q)DP96!o&STHgSDVl|4gR61A8$L8b{4e$cf`KIf$m;$Kh`&zoSo`s84zK@FgG zi0D2*Y>lxG93^UJMICYH*AD11(5U2~xpUZ(GZZFLgg6GIbg+Y-=;(pb_DPFFlO0{! z9zKdg@qwA3sFnF@!ihE`dZ^LkuS(EDDZ3!SFJe3q+Hebdl8=Rh$d@>=Se;Zm-1=Bt zuFHS9{|mPLxGJnBND45WVSXKC4ddJA{6~y=U44`pg=0w1yBPW!+k|$j7gHz~L8=BY zl9S|Z7h%K!VUC7#)A*d65|S&#=*z=&#p~FrE=*jqgvwDkXYkt}tm6q86(-^>p%_Nf z*ZP~ulNH*U8kXWuINp(ti91C(VdTdJ0b<$?^W7#iK#z33ow+-;AS5www4IKUV6%_E zS(lw$Y>9*>2^enar5tBUh7Mqo-9AQM%jxM<+!5O#BjBVO%imFi8qKYz+@Wuc>B_7Q z8GevSV^u84(fb@Bb<9cvE^D`Yo|dgdt2+gdjgr2_4KezQb9X;Oof3M&+PhrdaTgC* z>rr~94<`~gkl!*8sLc5PInLyraV2W0D~ip#Q}P`o48`AiVHmqL;t(>=m=u6&K>1-q z9+9Bup~6^$pMuOwBYR?n0y|Mxnf%FoH!LiPlg!9o<786w{vJp;9tQ3)msONTDVhPA z_{*#$i)bngC1@8|_by98RYgLrj@Q0@Ec-S;+wv34PP8Oo-((12giHb`{lbErGF0cH zM+5u~#(%}=f7zQB4WMmX9+?OWlWs=YO|%x_zupR5=M%K#Vr7A&ri9m*_*t6JdUO+0e*@7YLf)G> z!pU0}zBa@D14YICPk5lpX)$*0^9uP1& zUhuk37Jq;6@36f`5Y}jFc(N)c?sJFD$j;E1LXRMkA`; zzW$|Wr)D}yS)KsTC8#J4W^BRsjZTOVxesf(;#1Y*Ph9RAY8oiL;ec!hy_xCXd9|D` ztGdo=2T^W(a7=5qQnBO!fHEFE?~rZb)p6&%?d&>{a#s^UXffXE#`a;;833=YUQTdW zWMHj4f|wcG(@qK&eI7Nx$!xdTxTO$Bbl>3&t^OJ_&$uYhxAB>Ok-1eAU2H` zppfs{5y~ygC@nMt@l1E_R}UV<=oi}H@kKRXQm*^GE`I^-aS{^XDv(=MDY)s=8ov6a z@gDwIQUYN%3ofuV$+0Yzz=L%4x2HG2EMh=c?#s z7kYB#$`lg+usi|st<}+UN+koW+l($veCcbP=yL|jGrh)*zI2Bk#7JRwus4T8m`dLa z5Zn4u8gE&sKYay>)nqQe;{i0(cLiHOzvU0Jm^kF#ra=8Gb+G{Oo}xJJ*L8R`UJai* z3ynqq0h9r~Jv6?`V$W|6`d4BGd{0 z=rm2#<=G%r|0|;`{G}+n5F!2@kh9gXbA|c#NBXGuMu7A@`s`TyNA@*I;&mfw|FFS- z9N04k`jQe6aVh&iN`>JtrE+@gmas%z=_$+YxSn=j00rbBK3!pvaf-G9L5BUTui{Fm zcyc#*+g$ZtKB3`V3qVx4ZSP<+VmR8UE164fLo?IH0}{m6AK8ZEKDXygg4Q5{tT{a~ z>E`cPm%R}H>WRY&k~z;NZ}g!P9LXI$;7GF!u6#62N}J6+i|tfMk)F$aM~>7yh8)QCgm*M69l ziWip8O0z75A^H;Md^n39DqBCXw7BjGm$3&58EGJ$NkF_n1E`Mg<;tNvxb}fzedG;k&GbGFwxYT zS!82^UU(p&oYTpRdHE*!6GS&qGtsdA;|K2$jI5oXR*6Ps$>NpONjBsOYCcM>=KKOj z1#G$&2mR~k2jS8?=4@E4U`ND`!5QYLoR!xS=8LzjN#6RwUOWpXu-;R2XLudhboant zX-F#jGLNR<;0u8*QN}LV&mOl7^@{ewbAQKfHApHkTWNIV6~onV9ddbICXW<)Y#sjN z`InX7S@MwH1~n`I>v;*4_w(K+2VveAE6HOlDs|FU{88R))b6E6;?pdK#ALJ9{z%VZ z&Ru=USwX@-Z3YS6EHmZza#u04>oU)f@Y9u1Y(qu?^RHpBM2XkW1Ni}?76<(*s!nd& zVa4AvEQhvGK86wLM(fL%&C+n3!K=uUy^^%zrNxKVqeyoiQ+TQ1){Xn>i?%Avov$Dw zlZ62qXn?|B4w0p;typ{oDN>Dk)6^#-9C2&96H4iEu@wki@;Q-KY`eRqxPKGm+Mhpl zV~rDFTvx1S@#ezB6@HLA%R5VEoPL26-<~m-{5Kn4myu`Lr$=iYiHV!-sw}(EQB`Gy zL~r-@T+SL?9m2a%9oe^_`rbcD7z~NJ$#-8i74nXIrsT+QDd1#FjW3?;E7x&&|72Jz zF=+;p0C@$WabHJKRdCAL=7yL-7kY?f`*T||dU^kR5%kd88(%f|&a^owC@(du!NyBI z^|Fv_jm0#4INapWdzjUrGz3E3Jqh(nQhb89LgU8fsckwqB2 zIfOx*K2~_T(9c?pV`n$C`D$gmviWK8zT*gE)mcG)+n>-Qbd?>mz86Uaqvk2xK|l^U zNmGusV@&`}o&TdKrSCzNDrZnSw_!iWj0@(8sO5m5^Z(<&lyVfJw8-&}lBNSI0u$Ec z`%x5(RSMedo#6={gP(pM$kT}e*8n}Kq0BK~;^eMGmR=Y>)38)({GR;dixFbYKqZTK zIvcskADQaQPQwLYB#_r_3KS*cB63~yZqBzun$Duj1FwbrslHB(#5@Dj25)`)bs*wk7uvR4u5BG z{QzcTy*!z_Ot~+*^NTS9$6!Rt)IANZa!z;$1j9H~b(QxLTdmzw)4y#xIOL<9RYL$j zGmN7-ph&c#6Pq$*$cQUM*E~$hVJyq8fl&xcMNHhn(h6Z*7FGg~sVDzN9g_`t!CVEn zDTHGdtF9sB2(pG!?ec0nSy^2d#QwHNl}8tT-ZlH=82&IR;R&_g7GRR89Z}%0B9=q} z>EZ)Cp&;8pVGnOWiM#h7dNia6+lB@>b?=*anZR9iH8{mhzC~%8=_a^yetcqNJxHE^ z5-rlsVUKI8RV9<=aJmSpHs*&ulka4J(T4A9o^iEExTXL^trbV(iS%Ai$_hFm^Io)A z>6=A+P58r(9f5KbC!pTIXQvT}lXZz$s4M+Ybdczovjc7G-G3i$N+cO~LK8+*#KsSW z?D%mE2`iskk0Ic=-6?gtIaKx+Qb`6{_BVn-VN-qA{8}YOdVCf|2^3i{$>mz?rn?F@ z_)zYw32gUelzlgveVZV0Q7tKLC8OjyBGM;voL&NKV?HZ2yA@@k3ENDasVLkOwi5Ov@OuAQ=7U{d=Ip`QM7d6B(yNWSvJD$&&5pV13}Aj00rgQ;6h^=e z#Yb+Y)^h2ahC&yC{CO&h6@JbOOv<*(8SU-MMa3}B3GEp`R}Fmt1b$VF&S0E1e{z{G zL{v;SY%)cibo)1nX-Mo0xe#-YUeWv;gVBCBcsx24FX+ednFV1UStU20`#(Q4FbR-T z=Bc+GA;gWW)l7U(x4j*!=E3L&t6MX`aoejR#{8!3>(-u|s*pRrcV+fu8@!yo*6q;Q zwi?uCp2y}nf|CD3k!qemWIp(9d*Zvp60gGT+JWo}G~)Vn?ZP{B)hr#TYW85C)OGgQ zuigv=N|cSZncFM0d_--LvMF8MQG&W6%QZoY;@bH)EuW2;nHBI5oR4CfmF$*2WH%YT zjvFQrt;qV2qfI?J(yP9Np39euh0b#!pX=b(aI4^n05rB52$P;yW7ZW8_sPKKKUL;gE9ZEJ0?7D4RgU^qO_dxQ?)jJlC62i~+k;h27FNb`Q7TVKbU?|!s%OB?YpziO^CTQn2zHRvwVy0mu% z!Ip4q0d3zQGz9R`z;W3RdUJ_)!q=$hGNOZh(Q4$B9WuNVqK!RjAFb*ylGh&LGy2(m zv|5dd1rHi~AbW*DA3YJ{$C03V`dA3#b?RvkEj+GTFZ`$yl0AR!6%i*_DQ0!#wDF{K z&wNn>6-05UMr~XpyEe2|=*p@YY5PoAMWM6brA$-t!{(ojC=PYM49w3;$IyT1{L7TI z)Pl!MYY+mmMt4G4gp7&T}S>Ezxz7Y3WG>t5fMgA6f?VhCJ?QsMt#!R7*uzWGh$r_>AO zDd6Am7J=!D`1Rb9OV+8hPItse>t6K5cs9y3uCBoAD@ZKZ`o3WTVn=QO5=a+YrO+C#*gbh|V@bq6pD+AHkgNYM z+p54X-}0*WD8<7(t}rFjC+pY-=n+6aX>6^h-?m&%RDi$yE*gK z;Wr8VW!RY{h|X`yeao-jAN(vy-P?;?x#sXKm67{Vfi9UN2j7*R(I-sKO4TZP5)84F zd6u-L<z>IqaFQLqVo*gN?G)&` zdyOvZVrA(ZRK9SOs}0Qvx#ssW9Xu||`tl3Ko;wO77Y+~qGw1<#Oou#naue#$-$zyP zT)C6e;j9NT`IJI>WvDT~~TBVf;2z3iSqXG*9bk|3d}6 zhd$m_j-nqBrAOhB+v7nLF4epFaU^9V?xJ2Nfo@T;sqiTvfMHDIxRx5&x>5S{=jZHljx2 z8x3>%aaf@pygYB+!;kn@VcZu^(TWFn!?ANIry~-s-#)xNW4Ol%6z%CC6pxKj z#>$;gi?fXLdPZUQp{BsQ>E46T*QdUm&mR=gMFU~jZc%@la)V@-6*wNktoO;X6aO(M z%Z`^=z4z82%uZa-VA(c*gRFnqPzWgbBoZrmy6wEgDxJ_I+Lz|sd1>?d3J@wahbtMP z@1^U0WiWyh%O9HLs`MrL=euVYcz=I@|<0xBNE17@vn8t?a$reR4%{(*t>BKAZrX*ENtjC-Lm z1Nr3-XL1TSvW5fIYK6p_F!=`M&nj3b@UhpQ|%HN z;^%^`?j>@6;XhyZgh@m=T-@^&$wh`2tToaWcA<~}YfdBidPp>=F1j`QP=&b_G>9ul zQtT?|(hDl5#=JZj$+gtFOKQReyeg~`VP*I#iY=#S=*T737goTHj(Ro=#8%QIG_<*? zTre&fw3S;0P9-WGFYx+CYilsui=fjd_mlzlhiHW zKoaN4JCI)i?qJ-0x5L+U(#Xo|c+ zaB=VxU$GarTHnoeUkvGMp_;0jfEtd#h2=NBF^1XW5BN9H?_qphSOZ}C+-maeEGrlV zfm3~LZdPLUz{TB1?l4AmVJRRY&h*D~oU|YytZn%OmMa&4F{?_)#mM!i| zneB3KuFohbbFbzQF5hgiFzS%kjgdK;_<1Su$Je@#Zy|h!n3jHmr<{QKKODqnsK4wR zZJ`fXct1nxodD5w7KfGP+;*7Gdh_u}Odko8_gR2m0m!+lX^^C)zF?%Vje8f){2yoZ zVV04rcUD2&Lga5|!#oejV~)+c7>}(|9cSTr548JS&(^DN1fEW~0E{iE&;Tx zWF|Qs$Ox>Bw3E7uX8J&>qGHofW|3xTBm(>?`qW>T`OMYL>&4^s-rI~3EW_h=P((W$ zPpFa*@!T{*hDJn?iuR3L0{TTq%xZWoG7bzKZ0a z<;0Siyp^T7&=K+iEvnfmP_H#%Yl`=F8B+6`N{L;O@z+i4|#japam6*(qNYQG22d^YN3c&9a;GA1lXF z)@Ep4UDQ|VQvVC-uo?xUVnb2(5}2x!Kohb~V2hZ+^P)6kwSH;nsG=_9EyWNTz1mbH zP{S8x5Mha1P-6C5dyl^K4AyPY-$<#Jo!A{+I-2{;xzS2vI{C6U7USNwCk?GOXtMG% z=Vg<6k|Z2VE*Yq)BSn0<96Thq{58?xd)4czf+tdVT^2ib`+v*Dm5**rtv9@PJEOPl z$Rp|g%>_>pj(8Yi;rAXuVGHwympISff>g^b?Jw*sZB@Lkz?+kI;_|op+QzZt0z=*# zvBVQc$*gDGk$`eej1o+>+}jF^EIjprecehl+S(`PE7{Sd#ug3gke@Sp@|U{x-7GcE zP5xQWOKL1rCpY|LwF%m>9*Gm)S?2>6;}} zb`dOT{F^3!w?6vkkAXLMI}~XduzJBv!FT-Dc%|uPtwNUB9W)Bpa;00;q`B95@DL1X zLCG<}9jJ-UF=Z(NCT^O$srSS(M;glU&0%Da;=VIoW=i&13GY)&jg@|esHEF}BV?tJ zZ2c_DVO1WqG|#DEn3f0KnER^?xcRk$0;_P~YtjaOFE^CREMvu<;w^>O_e7jdy9`ZT ziCW|}_*=lvtTSy9du9xvVw1r2M8Uyg%9dx`FP@BNuUcR!YAj21Q=8k{D(hl33v$WS=kGw(G2l8Em4#oJydSB~) zZ_}}7^#L%DfjUKAB84xu`|QAlA3;{e0yhTBtqn)p3j*4CY^1{zH38I+StCnkH>-PnCYFb-t%1qs;%M_z$nKU&&p>) zmj5=ZMpB*8$+hLZwDI8%brFY&*s0)`ZWdh784l4)XTRv6tzdJC_`Z3vHz#_c^~I~h zmPGI?RWS=s`~I`!%J}Wu=5_D$z#!ieDCv)$mp8hszCBk(4?O- z+o~i=a1(QIyd-$LTSA2LJcg;!M*K4+_r~-@mqY<9E?YWamK<=<3Fk6N2)zhWWoPoM97!J$k$aulnW}NA*(e?t zlzQ3$7j4dLgJylq1PYwpr7KTi6YfbX%3E&w6K}MsJH=o=n0uuwsD{!YbIfB=Rn{(O zBjg(K$7W&W(n6{wd7~)6rCZCm--*x|(f}p@k@l$^K1|JtC4O(|s@+ec*80G>{&FyElrls_z;8;4^-v%nevL4^^GDe2Z4!Nx7mL1DB=O@G zFb_3kvCgV$U@!)$fyEyL)<~zRNs(O9%dBYBheW4%#P02Lafkj_oCQ&mBYE5M(2R86 zL?+?*y>Vltnly*4*KmEx2jkkkjt3M^Ul;tuIt0wxiXv6I*t8}y9#WV-J_>T~HvDx7 zGmnsuYQUT!6xM3iVSOC=H|*&j9hSeIw994Dv>n|fskTf>Y-%31zO&;v^Z@2y`@Z11 zjja1H8oK^cyQiIGt(9)#-!LXNYth10L+oiZowYqy60wqe>J$XveOtX?03Kdmc~lze zi3Qw}c%9nO;5at?<2C$~8B5V#-`CGQlWV(=3x3rd{vd@59utE=54(8=3llRBjbQhL zKO)d?7)ccHdoWOhV#M?}pTHg@S;=)d_<$DTXFvc!^`$*>hAzghaW7Lc_KbMnj&thz zvI12Z58HwbZcpP@iYzaWeF}oR)KE>5anX}%oUaZ2;nd_OI|&P`7<#7J=S)}>^3R6- zmz_q)SOYE%ntWUON`ROGs?Vj}?>^B<*Y12?D3y~)!D1Y98GeeVDmhwS@CXE9pQ0jS z>v2XK2Z@>>qIOU%17xf6EEs8=SjF9C>FnMrFL&L@4cx&NM0-YP2o)o7YI%LRL;V=q zMkZVk94p&7GMQNolmhGTP3zEdv%T|d%`ws>8e^Gj0?aNX-h#F7r(5p`VW9V^&%J`p zO|}*TGf&(<>)u55ey*a9tIFSx zqb*3$Qcf(4@S|gro>ir&0TyGr(^a57yeJpA{U!4j@6a>_eP1+^vvtb#eRNea^XWI& zT}$1hBinsNuWX?1H3>ODznb#6L`@Kw7O4-$W@zujTf4bW3N1duj-+h3)40uiaJ6Xr zwxWFE7Wu{J(5D$XL}0@GqA@Nh5liPskIXkwsmViv5kC#Z+G`l`V{02E-S1lpTy_!T z+Drv%faBn@%3ybT-WDP}>$>CgM{`QB9F4~VW6M&2&mhRR$;tNXhIsN~4ki@OT*unr z|At3TxG1twqF{9%GF)J(;{GXKF6b$)VN%TI?L6kO)LzICNE#Ko2qh^RN-T%I-LEE- zvf!{HM^i9P4a4AG@8IA5ayS?ndmaOPU*lpz|9zVy#n+U;oL$bho>F}9s@UI_5{)R& z;7%DEftcWuqVRuC6rP-%Hgb8(^7zM(Vs&*NqC!)XP;TcYI2zu5M%h-cZsyQBx8;{# z0G6%dU)VO|qHf^Bvw8aRwE8)s5x540Y?$#Kyrq)k8q#)kGiY?)z=6`TH;vkdCKSdc0z14 z&L|PrgS7Z8a-rS70!);H%X=IUMw5+v{t0Fj=D~D*xJv!#{saxJb>iv-tJ4osf40$x zIbiGHmhzE?83=;_^4g|L(Z)mYbiA2=d%Km~u>ZNz<={I|WTow_oA8JNsKx0lFS{{|Ac7#pa;dM`DV7Zn1J-5(Sx4Zp%p zqy|lfzdJf$=(ES9Qr`W?iut}@;YS{6@7>1s3Ud1(g0#4{0Q=tb@eOTa!pyi)siW0Q zH8fIrj#DPLsj$D*b#~CW8|5CdqN1HHw-M{n&d7*Eq!6d-%|VO#AT>H(b)=CHh{8H- zleWJPhKl){7D?gX4p#z(tPDjcm9@`#l=>v82Q;-YSQ-OsV5`4`i}uM+ zossMRgYZ01T^lud1mY<4|K3UtNZ_HqKN+7nlaevR5JZT>Q4G3Iqcz#QZ1Ojr|L+Z0 zvL%JVFxYPAZ~XUOJBZzo=#E4xL*Hr~sr*GQ#qq5vc)qxw9*{bk*!j$N!pq}Nd~PYA zbuNCQ$*uZ-4bX|+15j!FtXN%{YZk6(Lt`>DoyWcoL<<|Tv#-6Y9PSDE zyW3s?zr4ndOP~`c%V=Sz+J~DQkFlyWGfbX3J}4;s(iP6CC1G|X1su`RUxD_EBW`)W zVXTS9ApA8p`cUo8LQU`?$XznpTH7HU1>Zfim3`as8Px_;(^ai7QvjgIaI#mklD^go zfYujWU|z<&=0fwp)+8LCxI8}K3R$$e=VYlb46pz$o+_9U&*({@c>)6y zu+Mq?1lFi+uQeeDk>h5&2fUgf>r-3v?O?Xz?IG&e@+y-l@=xw@QjCWJj;)!=qMb-~ zWW*Dz=Rvr8%OE*JakZWkQdx!r?_?$wS~uDdN!5?`A->v>z*EX&Zcphx)MU(DTyuqX zf8aAH{jq4kx8yNh`-2pxeq4_UI0x-}SMzRO`8so?3_?Uc}0q2yJjV|m@ych70in>C5tco!VQJN{{I^d$dYa| zhOQ4I=?Qtv;+`lM^CV$g*$j%)(cXdNV?x_2JcEs5L_E5B*{7A)I}1S^cW4dICW+G2 zYz2UpXQp5gQWXBALL;!+z?qk>n;6*4vr0`xARrVBlUo7C*wu+m9}F1i%DyZ#QU@l=v4fDw z!32w32#JNHY}kztJ^<(l45R#Q;b*1hT28y^iAz7*^yfq8uck%Koxo;v#`~C`68^LY zgGzX3^#f_KQzMM3#rCflNJAOSgjQ?1Y*bG}=~g8Vgwo)T6yx#xH|tU{m!BmvO8rd* za+X*ES46B^K@EU=(uEM*$YSK&SP*<nx^x2mM#?+sLF=I^!p`3U z22n_(#v%c<|NWY@02btj-snh&gnl?0mYSWeQVL~qr$-4Frj@3YMF>p!{YmpF)6ssF zy67lehx?A}LTiF5#hd)??ah|64+1dE1o%`(em|;JZPN|5T>UXjqd+2zB}7Ai0*syG zxYyQ6u+jg0v}jFxic~XnNx3;&<5xtc7rVrQSO~kHw=@7hHsjlLVC4e!E=H34nuY0C zuKHdU(YCys`bz{XN850uI7+_0r5fz=Rr(!>R&~gWUS2#WC^R;cGtT1RDY9LqaO48t zzAKp14!tVZJ_IJb5x0G6t4wgR9T!7Hu*q+O1l0tB&Uw8g|2dze{m%)LjB3m>EC$YM z1}L1pCf=I{NCbU$Vfh9lv2>0d`H+9K_yzXZG3%a;mw$7GHMO-RWLCX9{(ocuziomfl zbJQP!9fqd%gsW8}c>yn@+%TJD-!RefL2z$m$b19@(uL+2nO6entOJcU`{{G z_!HbkID=f)eX3n}6QCC9XrPCKo*h(!qT26RRDI#~1$8Th(1yWW8D>Sk9>&cO*PmZQ zeSBgUKo3H_+`+7~W2KjXmQ$e5Fu~}w*|EAJ0#4I|*|$rlWpYzA{~lzi)?gIBdFB^W z|JoAcqGCfJX6}-b!D5g6D);rdsfb2_>*=yDhzpOcj#|HOfpt|LN0w&HAFxTL=pBgA=2g(EaUpRK&5?k+s~gIT)X6B+MNsPH}^Q zXbo4?%$D6M{XEp@MLWzhrkDM2gB|(-{sz(4f}4aAzc8xveb>oBJTZ#}G7n)zTLP>1 z`ip@1kB)4vOF;)(?Azja7PpxWzUNov>lJKa_Uu8XjEWB4D3Ju{qlB9?BZZA z2~Om&PiTY$G;bsXM?9z36u%dc+^V>kCcs|h1U~YxW&Rm#HYGl%p%F=A-}OzVFx<(! zsNs^+P|~hmvt+1Ce4rvcmVxZ%ej}0f`*V4h6Yoj15e zo?UCJnTl6HSzl~%Q~N+kcPzxP3TtCjV8@T9*XdPEZbuF~(e|851E~SgY6(!6$S#}E zEsB|kfrn2=0DX3vvd4A=qTz?MI?Ytm4eCznVuOHfFMKqXz?H^pU=`~5?+@sc@B3D~ zrTwyg>nN9esMM>DSTBs#wfpuMLYw>Y}4vUur8r}e%O5rm%zcb&$uYYUuK*x3# zpV%H7%!$o2JqQazi|Z;?V!6ElQ9!Q0drB>VJ1&~$3o0H#74uzkj8%!IyU`h-JGy7u zY*iIySi#!iK|v*DO-K}!$JMe`sELLw|NoxXctdaQttf8~JhSCxG-z_vc;BNdTMjsm02>e5^8MRVL#qvy6T3*$2$*beTJKye#oX9Q2AYDr3N)l%2wMBmirzrNZY8!)CuBbAOB z7G2Lhj{Y-Wpvh~?dVw;z&I2*F#EI33 z>KLfQi`*7rN&F|w;$u_b*|hFhDXF0y+rZs zN9pI&ekB20a*T>y+SHxdPOrFV^Rib#~KQCGV@IjkodJbR7 zrGOINwO&E2NA{N1KHes!#W!7#fYQ$naFmgYBK+S9ivBR4S^{wulhXMJ*8)8Z7!}~l z+-dx9bZ#YpgX|M@nvGaWt|;-onn%DM`^25%kbR!VPl0PVg=C@B;l~M(`Q-nO9@X4d z*2crpTiiE|dW&kCCy5|I*HsRF(Dm~?n^a;mTwUSdAzw*aNO8HYD6wlhdf2q0}AnlA;%Hudj3SQ%h| zvPWzgA!O-F*n`Fdu0!ER=s%#ZG=Raeb|hi74X=@A)iiM|i4;(4gtbMrpEOalkJ~9t z;oz2{007+}pVTkW59xAXddSdr12 zxLf;?*U9$yP5k7|?D;|8v}x?*eL8HeZar$p6PidxF?z}E(Q#y49lv4Jh&IIqF2D+8 zE<^asCtI8|G~37C!za*8Kesnm|vDgPpuE=EWC4WOa zso;o1ml`eVOR|fjZYW*l5t_F<5l1h52It!voNe`5RQDWqw{4z@Y#Z~ZlkfX)c0q$D zT3{zg;N{_-BfD;Jr;ar&Z|X4BzkEcBK0ch5gLDW3RGBy4p^&sty1!v6ITRcRj_ul* z+axv&Pq^z9YR7^tA+cIqZkYMpfumIr)H1p+|Hm=x4*iKaVmZJ>x22T<#d)<7%pi`l z(d*Jane;Aq=hn{sQL9ngHjijaCx0)|uYe4hOArVjesp%lXcB|;U?5gr1k_{wXcVMo zerC0Xjm^eBH{kJ@;LCH`1QHlDq>y^WL#H;IJO8Z>@|)ggnng-eN9F~=pBJkIA1}-+ zxB}WfAy=6YiLm?4n(7BZ&=y#AR_`FpoC_hdo-WBf)hS>Cm#7fXq4mUHEE&|op!13+ z`i4k@Wqj_}Rv#nH<9N04?ktkpe10>QF1lPX8=hEgInpYt1=POSA!CraEH^kl`Q#N- zgZ&BZH_%or+nB=$_JV-{2s?K1UzWIV0Ar_t&WCvu(n>M;6_~O<JVQ=#g773T6wTnF`d!u23OCu(LXDw^1|$M?M8+( zWMN@+OeLh^P`nSbdk1m_F-zqihG0TlfF6*|!E;PU9=wx7CuJj?Lwwk?im3&e!v?L3 z`8c`9tONi>jiB54JoYIwU!Bv%Is}O>j7(IS%X8(ZUz)5nbQn`Uvw9QTOs0B|Uj1%< zk>TEWB$$&GeEoLLtFjX+J=OM;0DsraBraWtVGXoHK4jfYFv@fE%#3c?H&H%Yd~vt+9@a8k1gKNynFX1=kbi)9q&n}2$Gbko zQ9nFb?wc?QQfY5A4Tw-+qw`LF|E8b+r_YcW$62o7D2m<&7FFxs)=)RHnz5q5uwXsFMxw==LHfmYuSx} za?KjxIn`VtLQ9{0j{O}AMZ(JfE{Ca=F$s-Pg%p5gnOe?Pk1#cu6y=)8Z5epNZGMg< z3dCHH?_u%zbNs@TSotvk0h$LVnX|j}VsQb$=r^S!%^+}f7+`7fFQ&O^NpL!Vl)U3b zc`6?eTEbrnj>H_Ai! z1=!dm$~%4)ngn%5-_D;i#H^vuI$2gET&+k}S;jn50i--B(Jwx)e)-6bT-K!|Q~-4% zKE1D(XmpV&Ay42Dq{^UHf#1g2fyYhH0vMZ%yil_4k4gGOodw4_>@X!q7oN?@#BaiG ze}?uns{d!6?(W?%xwD$1y2}5@;ExUF&RZUy%6YNKH=(#{&AfaI?jk}H3VZEbGrV#@ z!4Cnmd3yk4iY33{bA zxLw5^tr!ae98TPMWy72qLG8G6YuUb4F6)2`zOO9M_S)Koy`+EA%g-c$mE{>Wze(c} zbFqUyh!zN5XPqFH2Bk6=j5p>^E9Id1@oSi4Ksv*>4*+Wf~p%s@X)o&>XAHw z%2=+NMpW81Io(yAAQ6gWT{5Svns{nXHP9J4X1ju%ZD7mP$~4X56oI(H0pvKlp|SVPA}JI z;rX|2im;LsM5zvl<#TEw7;`%e32GD0s52YahUXJ)bdI;cO3!FMyQ$9_Aa*Q_Q_q}@_e2@_@W2+b4Od{0uT}@*oeo?pi%*f6>GpsALM_3QVnV`(&Nl8_`;Q$MqPMRVi%xWFyoAT3Tpa@*%f+D@D&1F zh!(K!*G1quWBGbTcWCT&bur068(+e-&=A;}XB(>H+V7pWKcyd%U8o&V0{Y^yhQ>h@ zr#poR~Sm0IgUFZ)J8vSBP)+^Ewv_l@@AlG z_bd6@4_=l0&c~1(+-hcs9tFL@=i5T_ zS7iBWEJq`rI^7SY==UW%WX~2y(dmc_9p{Q_cMK8a+5gp0Wna`@N6e!tlu z_1>VSjb^9B=tcyEU-oZ;-4wqSDQtOfggQKp(?SklVCqSGMGA3KUG_$xjen=QLFw}? zp#Ay1dXn7HhB}2fY+{5O8Cd`f(5OU?{P&K&wF2 zi-ayoAFBV%FAT1mWHiCU@SCM8vDVH<$CNKm&tL<^l)N0hx)$MweDc&~y0G9`D6IBD zq}BB#9EX1(zW|9!rOFy>OBF`QmjX$dJ({GPfp(^TP9d#{MK*Xr*j!3 zo!mRENd4MlOOHF)2lu5J`;S9**;TvFiO?YxRG;aU+0Zo~?oa^7#)IC>=dt0wd&L{* zui#~ds}hPGuy5MG<2|%=5-;IH{L84GZ33f0zeLGPVaDQ13Apv_Z11J%e#%X~Q#GnL zG!nYtGq2I(&#-v5fYw*c61dV4Kcw~^C#c^U@mRLu)&jbvQSU>)k~R{9+3q3#)$7F zIB!HV0P6fJvm!#Pp~nTPnPx~8R=Xe40mNc1KaDgl{;&~Ah z+>m{5UnJUzx7O&m3}PnE0hB9;;|$kYIuY&TXu3OJ<&d+-xthu64jW^7JTgaE?n>4$ z1E6NRRUx(2H~#Ucd5MFCe1-0hRJ5-j58<60_yS}K?|02AI^Dx057D>fqc_*lvdBYY z;n%9Uh|I>kt=xboYQ7+iik2v*M`PA~D;H8OGcJlz5&NN?k$?vgaP9ypDI{IzPLyOf zp)yqdIJ1LVz%TlFTk{%XoByFki}aT|GcL?2?ak#)j&UW8?nrR_rNn|6%?Q0&!SsXa zF#Q$+K8-XA(*Qxontsk**)@tI1*$o$`?HHM8RAZGmIU%^cs2D#i@UtIZ#1N{&csa_ zdQ)^zK9x+?UV}lLo#|9^?iHh~Jdf+}#0|@oH!@_aJe|zJ2`QzwF6)STZ?NX@bGrLm zxQ%@g{}9LJ$3<$>`{R#=bhB#5Y?lZHhZlE!VcE$EiaJ;`0v4xkLt)n>-x^)U#J& z2mt8iCoV{-gMMyI3J+=;Tq?j}oii@9U&}cbTNJu52N41!*l3>Au6ea6nOOqT;bi(u z3?$=yUAYE}0HH~@FZq-*3RhoYiwU>ZkGjY!^6((5(rH6O*@BEUxaMqbU6V;KbERMN z9I`Doj@tGy{`?66oBsZ??_LknybxA^z|y$Hzz`X4%_xt9L+2in;BU~XE+;3Zi~fCDC$SQsg|uU{4X zRqsM9*j86GH_{zbB6+i0%08I3p0(}qU~O76J`zo(!897FT|9OJ%KZ6Kyr&TSYeh19 zVafx7l%|u}=AQ~lX^oOTER_!4Ue9=mJ~L4{T2_j&$#F5*s5+KV)kwl|;2jm`ads*g z)wfCx-4I4Gc+RWoNz{Pe7og&`R}j5Y(|LESiV;v=GqNs;P~X(KOfiR!Om&&PO=1MdIv$o!5g@Ogew=y&rNk?-!fyt) zf(t}{w1{aBY54n>sUKXT@D6ZhOe+jAcj#YvH0l2|vE4DGS-FQ9MVqBBf!oveWv9Vo zK88L@CoHuyC-^F`ozM(vZ<8;K=8$n;%G22jIGDX{q9ilDwEiNBkso6~>(`!WS&}8ysKt(KS^9Ho7rVHA@x*8wX#1xlC75L zDwY%F4`;BP)&FPJuN8l^lkO~M_a@aywi2VOMuGCA>Z|K&Q4^ipc3Y$%ez1sIvxlXk zm|R5@C69}z*dh$-y#i-sd(z%wdjHDdTm>Vz?Zh62;+-TW(vnhag!6!Txye>-xeIIw zx@>3pj$e45pA9Idf4Q?AhBJA`e=f7Nol?Y5%(-n7RhAgb11H?> zTS*6yxRpZrx-@sIEr7V&oKBg!Mf)cPd>G?m?mrjD6$H113dlfjO*hJ`->NGnx+X(0 z?j9p57L6$g<=Mla;Y|5`8Etpf+Js|;lVkbUQzSV+hd|GKG8(!%j#C~QR{vLFUCAVa z$bbMnZi*xlw&N&rdybpq$ZjM;vU2H=-v(s)3c}uL${$d7*uIAHk-cxtRr z=mN(KzWc0O#71Y$Af6qkl4ZK>Y^tnClVSlU9D%F9rzWw{d}w{$C))P8&Fy*efI&_C zF~jFa_K8X17?g_O6i<1k`f|~l_^p3Qd;dDq{_Els2eoRuVM*-dBlQ+! z76POva|6N^8fu~+Zb{=oxI)a)qD2raCP{w{#c=C#<+7jJicop;XNb|@P4la4rsR_C zo<`Ial$`mnbckEt8G4zx(AEE3KxnLO>otPk${g_ZC9=^Ec#TeC|1-pHxGZYNl&jns znDEu9w#j$=5)eL2{~^EZOkCbZ5GgKumGVYoso~N?{22yssC%14doX8BqY%J1D6(Cj zk4`g<@GG;?<84G`6B6IE9?;27nsT0K91O_-j~+)j^aWzks)kUoL64a6rq()icZe{u zS(KHz-gfiH6XC=Xao`<$7S%?Qq4vYv*^9r`7K|3-daxuA!E6m&Gh%ShU>Os{2}h9* ztB@}Z1|rc<)ZATvhDE>Y&7pUu>bX^VauqbsxlAHe+AJ8j=HHR_2o) zQ58s9TBbxB$Gq!8EuDv3?olLrsP}gAMU%^5N7|D-lvWl#L1r6>ZI|r&zRSE@>c~~0 zdDG<$-|x(2M0dx@&z@(c1*@zr_F4m;k_`UoVPP#_n@^5|9G3FMYMY^mwCnJxbotUZ7og_AYa>0~_rSXO!@&^iUh4K&wFMOUc`aOGMbf zAp@7+b$*VtDzw$zGAp?pOUy`EB**NP)@TBeQf^U8=#H0pS?5zHY+K_{v zgs0`=xS`JQmvBy4k5TP6#SoJSO+caq;I3AvYXHG%gg7-bY3_l$I$VDx7LM;tKoX6I z>whw8$c19Or^}<=F7K;O)=~pMYGdy*@)E!Zsus>iDAT*ZlZ5=%_z0%n9s^sG&-AS~ zz|6#5vr*?I2SPQN+IT{(nOPvDuzY>^C{!!4{b-BP55#~l;Jo37VAWQIbKTS?At&tQ z-`-PS!^!xoatyA;MPFYi7xK5(b*+6cAJ&d)UA`WL-zq;iIcpv{k-B+qm-p%_YS?6o zlXLrXEL)}kwt>nmXLK@QJuo&PzFg>}opF@`FG!2IhNH+Xr{JR6%UkNkE-Lt z$#?*g?l1QCd{@PHuPi}T&+<*RN%qL{Pj$;lu(xR#P6-`-EB;j{b7@QY?W@KOG>so_ zQGl-aG2Tykaze%TbB@bJ*18fovj-fDZ|L3V;VdRwu$qEc*)V@FMX`3#y&2?#P^2z0 zV(!**u)E>%)zsJ-j0t%1j9lN%&NbbZ(TE)iG;*5U1~os1+QO5sD8lN*5_nyY+R^bb zIFW};1%>G`<{<8*5;bo~&eT*Q4e~)y9Eu4qytWCEh3Z(5f@yc4e1+Yj z6|L3E*Tdg}2XSP?a+i3*&_oW`hT0&chr>M?4NpZmp1;JEJvB?pq<*5To)yjZD?WZA;|byfORys&K&ZhaobdefOjTJ8&UU)WO7? zsEUV!OgORCk~;-$mAi=Iiq?%tqKH!clK^?IOkzp2#V2tzAN(@WkQoa`DY?Mer&TRM z;au#q*&8v6hyWed@_I3F*#ge*__)u4?TK$CUzyBgA| zBq4R}$@NYf2@lbbA>Sq(m*u-7CUekeY$Vq7C3v~!1`h`m>LY|dX44R`L>Nha|vQUzkaN16eRkq{WIhZ=r@=>qG7{yQ>r!e{pl(E!ys4HG(e>5g@f4p2^#&XUItcv$N#lSGs4MpxPjIUDmmpf)N2B$y5>Y(xygxL zieHOOl8A3cP{K+XB1>brkbi*!@m#PDhVDffY%6pSn|3grA_mVxHz@UB@JqG;;1@mU zTYrc*$whaTGq+#%f(@z3s~M6{5Q(eM-W4yV^-5@0lxiXz>_;cSD(9_>V&SC2T4*Wg zrM&({%*8=MnqAlnsWTD(+hm~dUrl0OI zi&uH7&a13t`dg``x@wAGeIeoYljwWRBQf%OzZCRMxgZ@U zAq~DJiu7M=q>h|idA&z!e9PZVF;}3fuY+#U$Fz$Td;C_~K1GX1rC8S}zIKJQc=ftqG zhUX&Te6}1ks{Mj%Z%i?*6CshBHI4hHd`cpPw??o77e?)0b^t_{mYGN|9m5}uco38% zQsS2~f|PnAs@^y6pT&RdUk#TN*Tj&hx_9o&&jq)4Cr{N4ZYsyj<`SwQA>6Bth(9D$ z>(ng0VPlcT)Ik24U-)};=a%b#BKHEE(Cb#tdoRo5wNQcG%cuc)*@Uvrgm*A%R}dER;Vb(X zo)0o4;urw+c=#onuIJiHNfrWckkLWL%_Y@@6FL<;JZlD9kjpHcy8Y*6%79AeF&Gfq zwgOsQ6Y?_9=L2K34@ylfxV*m5iSbekc;Q^CT8Xn07~;t}?a&`(Lmwg_RLOqwCj?xO zTeTSy-R{YMMkv0+{re=fNq|9kuf2vdv~xqu&G@1ctz#3IuIt4@e-VHJYM-O^<;bO* zqNadGB1odqY5}el7dL?lMBeyd!9m>9Eym zT_PWfP75_mQVzYpBUxS$iMA7^@axPY?)r%@bi@j<<&UKAFr<@mRt-_wEkE@M^Ux6d zFiG&93kkb&^2j2iBBF2&hjmLtV!iWnu9);P{j+v~U)8BIgutlCJU@wF&R)d9__fPU(3Y`+CR+ExmVLtw|7>n#qq2}G^YquMste0dGWp1_u62G!Z*?@ zyh%pqt8MCl%?o|%t3DfC>6Zj(JKN8fxA#64W(5F)I$IeY=qe?1kVj(qZbA1|Vt_Dj zp^4+I_Zf{U96`3+O(O%S#ErzNnu;mf`#bFb%x0HDSA)EHRfUpNZ=sY zNemeO*QSRUbbn@+R-t!-r2@4@7kR-HZJx~C;nu;69~<)CJHz(l? zSzmj2VkO9S5Qf{Iz8Q(uTE^4uHruUoUbC`}*Np;Mv1o)tN4lD!-+J5;Tr4LUiWGCacrMa`JT_J14p9c{$66(sJLTtjcM5a) z+hE>uYkql`TNpa6F9QF+-gEl|8??&utzwZ_hVASlqY z=@B=*=jk@M+L#uBm{Sb{~Cx1EcZ1P#h3*dC&kP`NT&{P4! zwi+8RvxtWQPz;)=59Rw}!*Xc+RU~rwz&NzqKl<5JYj~5-k1#f zSrKL}MaBn@aNsk)UKci%iELjoDg*86K92HMg~yRAs(Jmn_`AD=TQd)dBF0*m zh|Z2Z#t6fOd=t{PD4+8&x6%b(ox<_z7_9C2wL49F}fl~$TY1Ah9Pf2jSM6WxXTNyDrB?u?B9!tVeyLkz%LVZl|Bi8SRGVcrsI20x8150i9- z$beFw&hx&pQ`coRee6<>caC6Xzq|9VL0dZ(Is%6nk7#DE(+6jmigu%+eeUc^Tv?-q zLoR!w>h}DSCbBabHnAtVRxY856{Sr=@z>%Zl*n8mlg{S|%l5Q#gGn?D?qzQQdMv0g zoNXseBKaIY=P4@fY&bq{j@VV3quv7oaVVjFEk$uxvhqoCcZQ=HbZ~kd#Z7ZvZkt&?L z&&K27Ap$1+UhzC_FeyL@67{+Ts~&$Txe0DeQDb=@J{?>yvYbj01nV0WUJ|#@T_=BO zuFScO38>FslinyUvV^87C!?A+ykCnRy2rezoevQ z_pZ$FvxhU;356Ro}V4gXWYe;Bn#vyqEJdOD|Ack`eCr5If(zttsq5y(oI>fDJumW+e zIBj3vWy~fR<$^K;>Cxsyl$?KX(a&y=pCmcE@$fdE77J)?^$`Do=IiUo&$7-1?x(Tr z?$|7^+lDuAR}tHhPkWlA*O-T$D6a(rGIL#b_|a0d@qHJY(^19xi8$1k$!^wJR2Py) zs?i|Y7BO?d*PIJmA(OF%70r|xx7nO=bEaPBKYqoM0tGd#I=I2~cu;hBI1SAcFcl8& zH3wB4Y}v0KX&Yiq^|!NvPYd-$N{0DIx3u9ajfWw&`T35CYzm!37P zt)>Z#Rfe?zAUu-&vpXt$nEm8$4YUZ?rU1jRrs6=U1T?5FV+q47{0;e3xL}G} zYju|Vuh$F;=%zyYVX%?sPE7NnfA}0O6u}fXhaiT2en{WKgB5<5^BO5R4en^xz#=t; z3QsvhIqz(x;9$#KHm?5v?{TP8c~r_@G}3YU4_39j1CjE{HXvBzx<9N0;)RYy2vTyZ z{)vqJ+Wk|!r^>Qzm5G5lSYMD+ZQ_P_?JEh^dJgVoL&p5%&Cx0D8P-=O+IAhK8qKaQ zUYVOk$|e@;Ks-XrB!@c#(OC2&swu9|35*Wda*&ky!cX`rBwCXh)oRnLRy`^b?|q$6 zCAeb=Mc2B4(uizxXx6sApA2gCkSJ%YG>i_op;uVnA<;1PFw6=~yW~2g>)r@c=yCW@ zo=a3E*X1aYnn}*%0$_h%N?oBbw~f%db!z|0_QK9P$rt^f*%&IRB^j-OcP~EX4Oaa& zPsUNSC4BR#5vCE1asdJhQ3UDZR=3LuH*ga`7RJRVK3xNIu125v*WEczEZDLeFlcF| zCMJ`gvtZrAqKiDS}slu2`lnOc^S0`#mlIwk~?s$v| zKL95Tu3Y<{WMm3Twq_)#laEv3?^>bd^PN_}3vb;)gV9!)Nse$L=t%k|95D6H_xi~y zc4#mL-R-6_j_k%-*TBg8e>EkCy8GlI=-5i~!-M{EfsJs+Sdl*PB|6SaI1YPI`M-Xi zmSs`_(t!{!dp&&R;e0g?oJ{sY`*aD8nSfm)n+J7K1;qdm9lfZEJ3=9haL8&5J=CYsROC(pa z3~LYFmMJ|l)mB~w;RJT`?(klpYTIQ%Q)X%*k7O@%$+2ljJ0VWg38uwFCnAJs zf*~nEbb}(P^m6Yt(-R}(Ux9t*>gdL_AI)~7V><&^i!g0iSdHiqeCQk0V%;ZJn5^3?{*1J%$U!UYYz4y{iMal%zeXZ62-G? zyje!EfP0@B5xg2h*w3aP8o%$oytiB#R051B(UdcccB?2loQgfVe)JcuR zmaxk*Rc6Y$uG2>{)~$>#vwM*D+~R)hCo#2j2o|(v64{Tb>%kiY$)FI*xXwEo^fvya--vv{iZiLmRooJJAbJ#aVAGr+!qYXkKV@pm@H~=C< z1P_|BFh{F-R;mHyp&McRg+KaJOruYXHGpP^hK_^CK1N>v2_puNpC-KvQnT9aO z0#iQP6U-lF$DsvONH_ z>UtJs!FWasPH`Kckk1g*nxWq6<<>=3g1m8j7)hgkNh{$T5Y~K)SAV(P@}#&W%oT9N z8Qr-tv3%$`mOqMB*cAsNL4NeA2o70mf*D ziI{NC+py&G>&1IUpQL~=!VRrGl*iV%RPP1|HZVuX_y(IfwQJGf?A-27GOkVUweRW+ z8VTg?Ae&)i6Ex0%J#yyQ6`(UvNZbb6Xp;mD_CzkZKaM`!;*F#x?SsI~+ zPU_LC$uPMPAqfX3aS6z5VOc8P?9?9^_vPv|JhqjeluoGad-^>dS<(z_=8dWmaU1R* zBe6NJvry?sFhYF7r`$iPYm-IykHRm$+yXs*nV8eK(0Id~r812{R^F@*yWW#WW)dIa zX#uUwT-Cz3-4#D&F5IA{U-XwG^L!(n`*D@B0N2X&#Cz;<*;A(4X^GcKb|1w`Gc=>a z1jY+jm!@S%B(sZBuH)Vw{(5dYM5FTr1iiO|1U?nE%Uk2hFd)K zxw>-+HPyxiFxjKz02haZ!0cKETLAJhEJ0kmQDL$Ut~uH`$R}~gr+s-fwCA{)#*l5| z-H~f*wd&fPG+X}jnhr?EZm5{>w41k(UX9?Nb!=65<~m~A=Odwxk%ST<1iIPgGWO{b zpB(}!Rk1<;$DGO|2Zvv;2`N-jX6^9cFO5A)F~txj5`Y8-k3|~=cZW-JVnYu|Z_(J! zwJvbRFMU_x@$q@pcnCsW7WeKtfzA7oL~5bC)Di!FQON|}O%EJ`kQG}qaUmomIbWfc z=&3AS!p!mU`}|ryil}1y*qG=1d?Ks0DS^pB}C|SFBQq=N;&H_fjkk{16ZUQx+`bQqx|Rn zW{xCo-Ql@pvC+{`*P2wdJN}g*vK&LtEs8%4=;Q3}eW)$fu(hudtbL7Z@r^Cp+&wZs z)2kpaF`%uH7{~NNv7DIPa`xLKHN*J``J35oqyt7p{-$>c)JD?&|vpq;}*Q zvuo=@5u7#l-l6GsNpgJOCfI1{Qx0|TZMlfX@8{OZ--Z`jS*{sdkSt{1t1TNY^PAI7BihfZpuT6AYL&(XP zjF(|~gQU_1(>^PL-oOOhSxYxF5tAMIgk$+2LpbQ*U2OcOm!D0Eps5sDSh*1rbe6&Z zKEV~X>?yiRl=op|kMb90c=k;hrK@pEqZ3Q%*ERr9i6iP!cew1M5$XckJ|Tm?s5V6`1XSZ^pVBss9Lc8?IlS6pZgtld0nx zyn%AigRC$o0$zs{dLT{T2P~!|UJ|R2`8vUzg@>S%2M1QxtSU-$F^^HhAyG9arzSjJ zJ`(uWD2|_*>qEXA7AH`|eWQ!SO%*!3pF#&_>(H>!XabL!LhiBcq)EIt1DQOK(|mu* zU@Syjo&;OE-wzSNFnG@hg2$$GE~1yhJ?NwZy1PC@6S7^CLW)C=~9ZQ3n`yyF@c%*&~ZaFLpB^zA{6j%xmdtwe&sQzdf!z-A74t<*paSBXTo z)}!w&`XoYt2h@CD%b&);!yI}li5=*j0=%&eOjL|V@S(w zGSh~zkLGa>JUHpG*~NuUL-UxT zqXVM0jeG1dYN0)qfpMdR0+ztv&Mxv`xALIOXT-Y%Brmf0^gu;BI8)c zcQ(}2sK;CjJ#isaiK_k=i}U5oif((A6ymlTT&n^<;5j#IBH0@>@2`(zm#UD9a_?bw z5b>!*5P=N{d|-PPMA=V`K;6pNRi6)RFJZp`>;&)!YM`*pXJqTQbVM&B@p`m>P92Mk z@+lI)x&S{wz`w+dxNNz|L~?W&qA~1m(@halv2Ai>kiEbllm(1kT3y-Yo*o%~>qBQA z2QD3C3l^>*ODG2(RUCf|=F*zZyb0#=Y)MydF#qytCd{{g%R~%49zLgOp)D_>O&%+| z0%+5}L)kkPOuqfRFkgE6hi9RD-6{J+xlvS;E%-Z#y~M0~5xnl~f}1V6XSMd0p{>!X@SCKCZA#0xJaqzK_YLU0=U`l z5yDXxv551}))E?Qg}G$2#e3(miGC4=g-;AH(H-WGWhrS66anuEx_7lMTfC5g^*mdSBF4?fq;#|v~}ygkQhyc zqnL5>1hXT83x(gqC3)0w7XK7Kj`)YC?nXeMWB3!lGWydsy2_hGt<24_bNb(|sR8JT zZpjkQqR2XyIxcxotT`E$=|FS*WUF5&;3r;q(8y1(6BCCB=9A|(@xfz|1(K9?@lsEy zK+}1oasj>9jYP$67PA?Uw7pCk%E}94+o1^P9za@Ci>6ChIx@g3d($!L-GSZ7o(P7( ze^~wx&zmgk7~L8b~v0Aqz%BOEX#xB z!={2){{G1L6oanzL>!A)CfSbbjhjC654S@Px5J<)(){Gfe#huAr9$5cV&4x~+!&R> z5V@B~@oEJ+;H}Q15%Hw;|6l1VRjMD$b5j_UK-W-%JOSL7!AVM4FKGx}qW1nKSmwNVD2PAI&K87Zf>H5(ws-PEO2{w6-0L`7J3v!%h0XYj zR7`r@A?heS_)`%^>5SW+Qqx)i%)>0=YQT2u{b^s`zcg#WcY}%DgOD>7R_mt7k&2 zxiuYK3@Kh*2y45R!((r5Xmgg7d>%R0E-Qn0 z9j#3xt}l^ha+`wVEU3gg3P6x)UH#=&<-L_5E=wJJUG1OOvuD}FXVal3>&Z4LxXmJY zc4VeKZL1dF^qd0pXG(~AUW5SiE6M|QBZAhqa9iFa)BqL`NiY4R26i^}`Y$T)r?Vr$ zd#;Z9_Ya{d$5xQwJE2svF>qqAqU4~t=OHK`YT#wu;W*yKruI2E)Gdarlxh(p&p&ey z+r%V}^dJ(_y%a~nA$)(pM&kL=s!*8)1fhc3qRm4KB*NYz2mdJ$B%a3A;tL0JkD*>= zb+SCe6h}MxZiV8-8m#0=@aD{!Zp5l|CL6do&uPVK7=qfaT)yN7_>E>>?-`}e*iQDP zgP|!0_NlQAOf-J`R-)J!T<(o2>kkMc?&lKNOCP`^oCQ|11a`B)+*g4;Lpn4{L>-kh z_GC@eechB&JEcl?7+0|vhyq;EafSFZ!1l;K)%YyYa{+s!%LWPrY>d8~fHW1uyNbL} zD)-lEuvBIQ!)hn1Gh#Z+M9ocHsRf=r-}ikza{?YqBBZ-wxBsfH5(CBxRpwY2#*b41 zC}pP_XOZ^jdfqO^Q#@T03y~#WI^+$jSU^vSr>x6AVM70^Glmv0f_L_k)~Xhm<~-Ga zMcDu9;;(Mx_WCnd`ZDL_r4Kd3VYRH3P7a)qI~2@YxCUs*oe$2;ppQW)V!5-ku~2P? zgYuS2ZaEIm^pU%xFYjO-KD1Ol8afQ$7Jc|e{*1}&Fy`GYBr*A^mNH};$o)c#Q8$TY zCO%GG4%KNc(Z(BU8tb>YI@@gC0Y?_atE|8H%Lt|ibgV)b9CKS=OoM^hS<4_SICv39 zseak*3Z_(K7!$A)mBF+J5_08xdP>88*zI0f8qfw4O}HoA#5iX`8|6OSDo*;|3?Z+; zKY+cBhoys$5&jPQz>lCE4YMf6nT;B>GPNiVQ1?eDH)mrS$5t5=OFU~6A3lV0PFZJO zvsQ_rTT!2_I67TYj?8c%n(3E_`U`LX6lslj&~M@ETEDZGyRg6VIV$M6q>f(^okX{w*RJ4sLx`J<`>H|6Ox+!;lq;2gp4 z?PuR{b?83b!pgNsQ0KNIGY0q#NoN}o2Q(NB^!da>UgI5At>$CM^%VwBl4xLJBo_vN7nPW&8gP^bP#8AN*m_1(B@J!7lFWSb z0QJL;LXos1VCQjoglF-|b8{YFzdUHb^zWRCHm&!7WRMlq0*^EYWX2`2x;FoBYc=cG z5I^)Sq9_@x#eznLj-Cj>kzbNW`7rBV?>jMWo)E&?dn94S^vg@A||DI2sMz0 z9{0rH3Q4HR+Nt!Pt>H}N5MaPG-OA0Ixc_a_2nPu>gn zCXE%zdN9$^u>sM~fTBtZak}7|w^U3pV=#;b{*&5UXo<(SagPSPB?X%z%i0U}`fk9* z`DPFVmZDHU12F;yC%KA~ysGmT6pcf#W=vQG=hfa~hhq8mQpOv-;^+Tf;Ec+Yc0JVa zLq%U5YdM8OK2+}7F?CW>di!I3T3WqqCi&Szx7{X>sC9>MwZh1GDa|{MGDcrW`_Pt6!U{|Is3%y6X^9T?R=)j%Q=qEk;iQP51w|B^jIT#7Ce zBLyQ(trl!{?7f5US3evx%#)U(5MD8Yo>LSb8wG7KmW*S*_p&8vhVnoEo6T1bZCkHp zig{KavzPtAa(VE?98x6^$rQ<78g^Zi{blNyqUn!IH~A|At7RYkKI43t^B{w}4fIN! zJSiWfAiJdwX&{#Xk^a5=3unOSm(QnrMZ)-!rxZ@${3AZu_U4wNI~Bf&WOFc^wtPmO zNLTFPM|(ZOpgDfhgXwjjIL7H1SB59|^7ypHX@Y7<#*b9S6Hx5V4F{2IKbvmZMcD7q zwO?6YcLF}AHH)6Q?f;S5iNmhw8E6{sly~%sleG8o0+Zp{A9aSaeGFXXWPIR{VnTIR zRA^fsk0xHKLuHVKxR#kGPGeF^Bmjr!(62wD%DfpjFPQl=Vs?J2uzb~db@`*f&IV(X zT)Fa;nD%_$J3xOc0z|2&moE>{@K!uar34x|Q>74q1*2daYIH_EjS`8$qWgV3$63cL zsL3;&iz8t!d~4Fwdx2($2K#CC!5W||cjqm&WhWEkx=cC|vZ#2aituRKBDp(qz7(aE z=s?tY*!DVEP_1OT8gFg@p|vI?Au&iFjSUlltrJFyzBR(mgL~2j$XWg6K~yKEsx&d7 zGK|s|WQb$nNA<%cJU@ecYY_2_hqt#B)u;lFi(HlKi^&96GQhZ2imGv zhOU6{Fo+PP=@W{$IqAO&!B>S{^+b$HJR2T;xn7|A>dvMxBdMD7>JmZKf+;mt3{b_8`iUiknk zT(4Pxm&x1LQgHnSvZ;U>GyKJSt^*0ypb&}p`JTX47))nHRJL;M2=8YxOH^e;VTsJ- z_(mi^B1l10H~~VMdg8jy$~+B98`Lz#h6BTKQU)f~{X$AA zkeLb|aPqt3SV0cirOM-gyvMbEBqgERSBr|=O74~6__1^ouTNB_5qBU4+(`$Jw+sW5 z5j^5vSyeHt$he$b80!ts8y4Jg722XNs=nzBpP*8>!0*hVxxR)d3$=$Uhm-vYXV`7b z`8X++bcw*yl2rIDK8mA4!r! z;|d08V=lODJJ|-{z+T%6u?3S~TPo0CTQSH)_2!F6GqqF_1x$>-rkr6SfjnHP?O4@M z_EqGE`pR}l_cm2tJ}n4JBj0Vbf-!j~^Pc?Mixb&$W~+Nta9fyjIbejX-NiNT&; zLFNs5RO3=1fULVt674bL|MbMcXXtvp?Snwk_8^ezg?CZuMb;>%TFvO|RDlEZ8S8Ms zy4Wsrz@({)nb~b}6Z3oPzz*o^8piEiuKF0}8*AAz#KoYS`<{jS({$Ya+_5x+pXv{6$`okJ&J=ZdcQqnN z>KDn>|L;xFTDz0?t&ZV@&rRo3U?Y2Py<23Rld!dW3wu!RtoLi=lB5osaIx2<_d<(=51Aa5YHr0 zhxP#ausyL+$l4Ve4dXVPQoQ;HJS8*=&mt^1;21DoJJ8(pxF6)J&>SZz>nU%w-JfL{ zV)}NvhZL5Su+vJxiDWJWT+u~>?un_y`T0^mE5GI_)TTcxLAD$35uA^@a1<#%vf{A^ zu1_AHYgn;_$7ITQ>E^rB!V2Q=_(B@|ueNHW>wfzF?RPVr@f=7c0k(yLW~FZxhmQb< zUgaF~!`Z!*QKn*Zi5q;*((IN^(H)1wbIF2?DROAK`xRoVI>3OI>++^)IRVsbn+#GXK{ZLF|C*2nFinc}& zVr$U%^vD(0xMYawU7_|KS-F>sMjV+d+4iB=uQu=o)tiaB%9?J>Eh0OF(0YHr=Im$7 zMfzei9aac*9iDgxq(W22!1%4^gk){NAEXoq-p5HBkHtEjz+>Gy(F|R#nrB1 z2B6M9p2j(`(E%PG2Q~#AW&whx!>gn0gNH`XUI7u(sq7^;pUdDQImIHZ^OskuEKp$_ zjO%t;KU%})%AV>;oL6NYeRIl^ce0{Fby29j(Ng@=zj`!oFbmn^iYaRnE|058Q!60{ zx#lse#Om;kcj)&`O_NvI###5*1M|90{NpK8A;H^M+r(;iN0J@a`!0 zaxW5lSXKWNXKI89nfCmSxeQ*~Nqj3X7ia4fu9Pj$#1%+hg12f6|Lz`Xa#>=_18LQF zbW2yfyRm^9AwLfe)CKh>|<+omix9G{v$Y8Xs0bcu(rkOvx~S@ZkQv7 zfvfpTjc&e3{;osZSc}(`M&WbhOyg6CECtj9Go)e+6pJxj02nq)c!><>=%E9-f3B=c6 z!ZRzMZbC3-Sa35T()OK$oehjOLbdWw=2F?>5j$FDD%|eUab1no3X4Vac}HBrzYXcotk;T#0m@~mD~cR@S-qE3=*A9$Q`>Q zaP_mSs)2HJ8(3FT_W>LfZ(-oJkE2v{?k)6oX3rgrh*1+;VQ$Njt8Q0$uK`L@W#$U< zftR!h%aVupPpE~u{5m+lwsooNOiA13t|KV^4`Ki~2~muFESq(IGi*oGbw;#`6*AFR z{2sx6QbeApVJT*$#E@bV&IW*Y*nDS>C_sG5Ez;BN|6h;rH$4ra(mP;~`TC`zqP

Z;q69XryD4#CEaF8s|IVo)-FCbSvXXy7w(E1(M<^qQ9C<5L}ceI}~EzMnD^; zS3Xe&RW@gIthvInyntBP7t=CND>i-|s(@|8%Y{aB-v;N^MI$^^b!7yhaTtx6HQ2Pz zGDfX35g4PXW!LmuNQu*vdHKMJVz6PuAszxQ=5fbuE2y8Z_blR)4kRZLyaWJL!WiFtHrYg1i4SS70z#@*v{GxUg zRK|J-FN-{!@Np~>`tbgNIJljZyB1Db2HsyUFwj(yWb}N2eVtMkZXTgD)1^v~U_;9H zYyD7hCgqWc2sH6AZ4)HrrWk4Ay4!DI90fjqpFbP%A{z%~@3dBW$#jWZ*;Su^1pSUr zwM%GS9Xq8ol@@p38MJ!Luq(PpX;9gqM$s09c#S%GLVaTF(3#|+wqG56-VxzpqQE*; zT>!FlVXJEYO+6_o_vvLc{@ItbV;ll~x;EH|VnGOQT~NhwR*MH76ie&T_S(VL_P;-S!jURO?!$$#XNPU?D(y4C@ku}EVlP-AjpK~n13Ws0&g=Sz3wi@a&d zDkrIkkJ+q=>ce#jW751wYRqV?B>c?NVy0U35gbjaH9oDu1{ ztYe*flB5M&-Sn}*!bNGtz&j@Ix^b;wUI zpqx={qz ziV(%h3G!%w4o6=PAKB-VfI=%-j`vAu+Sccds+kb!di}m5&r)x>20LJ#XuIzoqNs^N zylX28A?NFpdv>}N>1Vm3UfSl4WPK`5MpHK6BR~l63|IRli?-}Rv6QY{%^fwxRcUQhhzn`5JJ@r+K8k->t4T-s_QvR1?ZJ>>_bAbjA1^D7*T zm0CqgI9ML##wKTy0h4krb-YP%Q^*U4hMyur%FBneOVD+42;b}3KJpZsjGh;|tQPvG z&ogaa9`7-XXRpP(Ky!#`n)JAr<`fF7TY7JVx1RO*QUhTR`cvkdnTY*;BoD#q9Ku=Q zqTEb5=umXa{@`8Ba$V(4CeyuLUDrn-m%CGoe*cV12>MeHs9j12=dkjgNGEv~& zA=D884$QH3kMj(WmSUa~UswYU4*KRoz9Z+>X}e1Nt98qqq*?nf$2#T>gT~L86NL7etuLR?^c{z z8PE|av7XQAw6=c|j#p-Q&>B3XyV-{Jv3u4w=J2Ph#s`j^|IB_eS=!b^%m|l|sk;@m zM;Ls@1X(N*^-%h(*K^Dj&JJHqTav?^+L|jYlan)~X6ziksPuB*cdQbQiJ>!H`iW(WJ*pZr;q zE}6)OqMWqp`Ff9w- zt)UdbI#&8rZp(z+RJ~&#E%Ut#m=XqlKnmKug9R3W1&3RbQ^iXSaF2x@d6aKmOBQb$ zUW%CQa`na~l=bXxro&O;3k!``?i)XScs>xY$eq-TqMIH{{LyY7>FX^D(j57UyTe$>~6ZC%3LO9fxTP(7L~J6N zt+$+txYEmco$i)X947ZL$xzaes7F|kk5-)R&YM;a2Syr3%-p zpY2tLG?!Dn){jL>JYxFNs#U}3LOl57Hw(teGgbfQvn0Y7;jZyyO@iuZvGl(hl<-6O zCiz0G^3`2PS;@Xvw>%06qlUD0?unAY|GZ~}0 ztDAzz++;#rnkqIZXP?V!Wc+R~$*pIWPWYpaL8mosx6;68!K%ue;r$q?&6frOrS8m< zv5h5Q+f|u_LeK%lsoH)h{UN61krrMVya+mCQWW{YpwH3;5x{*PGy*eyZho)bm7MY5 zh6*2Im6Ju?-R-xDxFh4$P*_JLuGD|KT10lL;RsSfy|fpr6gu3*BW5-I&X~J0KR14= zSsTkVHgF&V!p6l2w*nlKZDx?QGR3(oGmatsZyyDbEcAHNdmk$gmx8%VhA?W&!@fGF3Q=vh?eWjJXJl4TtT%c8;rxJDqk>S0YlxOBp;K|0ycBS1{!vo2!gPSfKi$1>O5AocI8Wb zLT|T~R$CV029-&Em#BRGRnzUhlFW z{dzUT2&9wJAX?C!#Z19Vi^njqQQwpPE!6-qNa@!M0YlrsM2UGB!EUA!X2gn^m(Ra= zGO5{vGin^9-QkoDEEhEZfB`g}+(T)Ww{gKYF-QE^E83n31AnmPgpT8q*Zd&`WxW)Q60+g1fTIx}qGK0k z1^CYbPG5|+ekb2iu_hp;&^-em87EfaJI2VIzXUD#`pL9g)+V{(RMN>?lOI~i99j6* zS+uGLb>Y?=(jB+4q=+x98Y4MyMZvsk9S?FT$L<*s#WCalyctwp{7#d+i~PN`xysxq z-4^|)KQMzk74;4iDgezes6Y_dL!2$runupjLDDSZMB4WXBJCs?W;mvZz}1Rf&GYE| z(wO*=uu8;Ja%i5h^Fb|sCjFDz{@=SIa%we`MEedD8S9;u1^pfxJGVg(jBpqBDNPv6l{CdrLLfM-yA%UO%>s4sYEPo7A~wTk=Qx#{8U zh}^?7%s;x2C>fY$z83SjZF&Ya+zQS*5$4-r>BcZ?Me}~fq}h$jGJl6L0;H|ujxAxx z$viq zr>yN^a8>iJ)0MfUU?cHYt2?C{kb#WZTHj%lJw%5NIGqP4;dkqusT+g(h8$_ry(*fU z2bp>NOX?fP&S9dv29UdCWpP6L?9p(UWsh^Ar8b%c?Il<9`Z#Bv7^bppz~6x%$F{f_9o#ocPsfO-I=2r%lnh_sPey)6)Zz2>NuCQ~ zcCS~(Nph&wHDLT|JI%bGJ0>Y6`SZ-YDCzqN75??=uy_tO2PnL!#u?{q$Mg;MC-Cwu zd&dFXB5}++A2$wjQ2j+ub6JH?Awmvl{x`rSNj-(R*;0?lCaj`(I>l}DUhM-?OAbr^ z(G8<`0oaX;tG#Rlzpf1%JB~9&{GWkwg-!ZnpNzO$j-piGs;csGXdeN?({SeQ zR5Bh-BmjDnoxl1kU_-_^bwj;dI`wT+F%{U$rZ0+*Ps)@N0Zc#|#;De%Vj@uC!g5&x z3w-B{4CV?fyODr|&AiK{NXWs}1b-!+{8%4BxMdNCw(UjD4J_C{GhM@;<#5M-vXU8L zaqj)vw>A?Ki7xEwiSH%EdrKv}ZiNJB+D$xsBzj93c^&kNxPox0Z&@Zd5MH zdJR>2F70fW*-RHEvctskS}qg~8#Sfx?ggW7TQVz^ZCexM)1jkxt^ofTa_`wkMMs)%vL%dj+7)zh=yEeXSB4%skI%lx z9A6D>_zA_VAdo}j4Mz|m<2b#`McEjXkrNyP4^o`^q@;}@6ddZ<)E7rlZIo5dLbm%4 zb9l$Bk`H%a*(q8;DN}NP!;^Bo`B`+R<308Zrw9uNb?XQ?MUA`S*SdwYp*nEBQq?p) zp49CZKSxS!4*E)Z--xGbDY$#;ey<4GIHgFG^+0Z(?Au@jNF`e=GX|h^pu?l4c-i|s zU`KXtsc^m&zM6k)2fW2F@gUOv9ab);QlMD%TpT37r2@!9O}Ig6_-|Oh2J=74n}vXW zDcsFCv2jL(lx+7vSf=Y^f+4a4Z4Av=ax2%A>b%XjVsAY(yY~6+kk!JpASb5J@Z+VF zaSR9Mn4lYVI7#dtx5G+A!&TM8%DTxzGngYepoU@cYyJAsMV5 z$dDtYM&FMeD=w|?&oKC#qt6NgH!X{Or$cW)Y7Fk9aWOwlFY{+nD8B;Mh+D8q0zg0Ivg4Y5_1&L~?9 zRNg^L$nRd#u^s^sx`AFWSOXPeHE@6@^(3(B(5mmSq*75PQLl%5*kuFll|S6L`-5SX z1^f2Oh`}tjp&VW%nv++EX+I20z4o9hP0>%G(?P){gpj8;KRamz{GfU=x+*w%f-}~@ zYcf6JLn{PQjbh4}`-`iStu3$%I?xUYC_s2K1c5DoP_oXKnNr!nuUR)~Q%tlCl1{S1 z6k)6B;rVi#jnO1_9><;j!ipyza5Jl6rdi%#C4N&K3Bhgpc^c@xckc6Ps6@Gx9Xdrc z5S7?qo9a{6WK7o8O zZ`CfnDOgf^(rn8^?BJYB}Qk*@uV-e>degDz)q1 zu7VCes5OVULsOZeISy6=8+ZNzqnzzqPyzLrcF)O;cEXFnAyJU}+UhU{4My+3lW3PX z@ED@*P~pvl6`4Q>0v>2LOtLWvwga_w!?34s1T_e`W2Z2CaQZ{+)uw;NMCe^jIJu1W z=D&?=6hF)%VYXDrmxQ!AOovkE>3hMKhJMfG0yREC(7A8D!HsDI)nRTU{bPkt=><50 zRZSDIDU!8_0d_-}F$eTayaIi3Mnp{D0MrZq#7~P3R}U`PqZuMH(V~lLT;8-(dpS5^ zK&b8e;KTA#*Sy0^%js2ek$h}w85uBEUBN=K8qI~9O)CnJmB|#NkAW>x)-i^W8wt}) z{`!7~Sx)|CIgYFR)X%iIur=Sc6Z7Z+%3qz)c~dU?DXkVRGLSYtQEf~^Wrf(#Pk(N+ zmgCm~#|HzzIs3hk@S_cFlGL!D2ty3~sO?AcP}Ke@W^!|0W;`}+k!O&TR0YISZ0ItS z2YT3+($5~VkPe)*m}JX^uv6I+HPvs1-qV^ddY+4{ZStkA>oCQI=hg3df$xRc=gLBJ zBV|xcKs8l9(BZGcE`y+Rq6gKZ-)dJl_J^M~32kSxBJjl&FIz?;u*Q7(vEgk>IeypU-GqBdrHm`T$(U)4%Lw!k>6X#qtvVL zzcXi2j9<{*SgzU-tV%n|ymFl;I{HE^5dhGVmXsTqa2`X5lbyZCFT%$+5MtM~dp$6XwJ$L{R%h z;kJ?%Rvv0@3-2O3&rQeN@5t=v&5jj9BLz=>Dakf~a@ik^V=oc62#Y`fuRPYL8<2oq zqs_9<<&}Hl{&js-DndqZze*Z3(97M|NM}>xNA-)eyIfME8FWz2!)JhXu#U6ih%|8) zpk`&=OGNZvDT~q z@0j7$3hF>C>0R=gi1LwObs!=zUMGELHFY z9KL753vh;7PNi6pXfB5cxrb1myW6_5;$WS*a}g7M7rWwGDws#JcPs$)uCgW~i>Xb8 zhBJ=Mbz+Wdq(H1lB}LjY@aZVQ2}h%30m8z|T=iYS29nzB>t4`)9hxk}xDM>$Op zM}YT8Ig4@rs5e=xw%UC00HuR=l7~g>CeQeDo?@2E`&0tZ?(5N-v7ypoN@e|mW zX0WHH^scnmYLTnrkZ$mIfSR$TL}{qp33wYi9i!4jZW1d_#o9U~fTBrd1Slew`zfY9 zK8mWBpTrh*I7gvnuc1Q~WwGIV>^OI=b^rT5)Q1$Pc+nGsjzt1nSd($4w zF+gQ21zUYBMNw485K}Yp>HZnNA?k1)Gw5mqNsV^8q2*<*XvCaK?K#&Uv2TKfU8t+Z zTFex}7NoivC9WBs4+f-@vWAMN1&&UXWLya{5UK%Y!CYuKRua=@9y+koI-EgU$;$|P zEagxn;s-#Oq4%w&dX7CFV~oWMf=TQZz`xfApQiA#5XjPDy1CUX4t0Ea0b)6ov4`1$ zUqdv2+(1q>uF9-sejWmKBs7W+v9+Rq4edtO9LmP3 z?V?Bp0Jj;EQZG9k^6AZ&yo@a0&h0?x^K^^Z^mfbL2Fji)DYSQvF`-f0j}Fbc^F1TK zVnvoSQ<@?2Ul6pOkXc7-vA~6_6G&LBl{z0bMS|OKVX(x;7Yiw8@#iH0a0#@S&_2al z_Ig@+P}LBk>GQc6G(i9!>J6M*_D-BQA;pOx@8?o0u_86uO=`jrzWVB`8bd!RylT56 zXIZpwTxHyY?{w3RXKx6)(e40!*1m8VkN~>Y!;eJsndZWq5 zSUWuKR}j`A@XDkxVafOdBTA2^R~23V3k`2OsKAlV(_b<28O-Th>2n{D;j1)(+_e)$ zJb~T+oV=LL^%*FZ?4g8Gr@6{n?LBiU`x_b{)9sJqB;K+@(FCq9B%bLp-uC2_!kU$L zM1EOhmiE_8Jgd>)oW)g4i%o}SW0*<)#*a_Hq@oBYk(eeU+S`o{(6?E@_M8RrlOw^u z^0G7Ejb%^M=AAx%;-u^@zQW(wXS+>U&LE=;2RbC$##+6(0fh8u_k&PTgo!`!@q8dZ z%BGi`)H631h<7Xw+@kJ$)`;!b&bKs&Ay~5uXjEhS63RK#{JDu!i!^R`lDlCYow~&? z)w3FY9cM5=8xG0`45)D8>)tg_m-q-1k{}2uU*Q6wN}ZxT$fB z!qfb~v4lplj*<`6j2Y5DO!{r2G2VJOtT7g_0e*|jwXt24c(oXn>DA2rQ7V^*jv2dy zL=3cR4!iWXwS%sMIPNQY3o?idsk%UF)b>5%`UoBIxFkztjd{rjv3fKDMSwqYG!j7E zc31r~7kQ0Pr0jk+2@B5OmJ)}!NxS{}>21H};IKXc>yT_Yv(qi4HuYkyf&UOsbm7J&9viAq$_DadvGpkyk(EjIZ&g809>LUbP@DJ=`B z7B7X%KZmkyGCSs_xtWps$=4aEG879_!84z-c^Gfp@oVSlts*>atDi*v+l@hsXUsz& zTGXuv!&GWU$S(E>6;A<3yFZNF?5u*taNWk5cB-KA-3Vi^9lm4h3RbEDr?*dKvUQ!T}^@G@Az}AtluDZ9n{W$!M=#E-63=+PXToF23LrvcoaUyqFe-UQ}hlB9t-%; zOXZ!5oPXikU)iQG4&>o;a(tTZ&P!4&ylzAKjG7p;R8qC*)RcWV+Q|w}V0Q!Zzyfo< zK>pc2F|H1hOE8o{E0mB6I?c??qY!(AIn zGV^bMu=PtJ4A$0f)z1?h*4pMgb$>N*Toj(Sg!Sc!CicK`5}Ct?ti5#)=Vj;zU&F)E zU@pdZ%?_I|+{=JHx+K=+mMH#%fPC@$W)37$R5d3>!D; zVL41E;~o!uJ-prSd&@rKCaUJ>(KV7k8NgUg11sYkMiu*yqRVctxs${@{MpXE5i%V# zG)+4AuHSddxBLvmC3wq%18J5b7?xmEAOYnwe` zYzSbXg+}fF?~hjs@44iw4>ZQNN>KZ3_+cAJn0U`FHULdK;MAYk3Y#6q4zi}jcs~&x?(*Jz^$HkLmz2_I2wh<>n|B;|6mmZRq)S!a*{*;MtGYZ`!sy+@k19<>K zCmc=x*i=S{eJA-jF|PU$EORylCtdL66#k9nXvLfRr|z^&5AP>8|3eV+QM2#3~lU84hoXp!XG;6muY~_^7t=>j)E8xh2nmv?Y@bb9yGL5@IgoKW2&bcb{ zHA5j3%%zOUxvc*U?2d#w*PHS&0oxsJD%b(ut*sXW{+1~OHRL%^>O7gSL+<#^w9(Z_a%bkCsWN# zbdQp38D1us1w_44E=#F}1x9LYWzf~2ZLyT-zr{DoAhhGr zq~COYBh7zVNnIQ}3<5-|be9n>j+uhAn9x?;sML_IwqR~SN3Z8fT7sMBlkPZ(Fmu0BH;!+t{8)@J7J`%4|Gt z(uhIJ8;9x=Dt0GWP>L-U>IXdiWNVt~Yt*S6tQNCc^e^2X64aA&RS6~{&WjOpHPZFq z9R1$n$zsX9iihJQb&n#nBg>jOT6>oC&S-w2jMnTJL^QL{Cloi#Jls9BrYAsWmHIcI zeVT!Esxwc+11@qESh>GMN`851M2QBCe&D!-r$|hM(%K3FHBz`U&o+MuKM>9c46)i=}XcmRMZ96M+P!1`t3gj~|AZST*< zhlre%0Z}*_kU8c&9?VXZplwn7TUkaEagO`XV!CkVA*bl+2#KXi>P@M)6|o^1n_p`s zghUBoO{~fbWN07gw8>`vhbnHg$H_Z5Lu6KT@ZXvk`pW2g zrTLmarA(LBm#*2OJc8DzqX0XX;x7ewfM|N&rf=OHetyXDMuf}isFTky8w@u3#{OqYaNTZp%H;tNTVV#PpL>$KHiTbl5{5n4ke1;Y69PgBwhy5eHd z4F@7eUD9D~z@u?epQ%8FC>uO?g5kfIf8Y(-P0eEiKad5RS;iQR#yk2B8)-LzW81?f zBnXjc=>tm*Q_)8IRFA79We#Na^qY;Zfam>-jzfumEpFTI3&HIiQXDqS(jqV1o;D7M zYVTsmwlUAle#7p(^tS5 z@L<`sh#&QN1lZF+x%rof8DB4OkYgky=FD~bT*Ej3^U!9& z4GAogUGh`LF5uU;R-mu6Qf`kO>egMN3y=yj%7fC3hv$7MQq3Zu$?6t}lff5JS0n?OXTd#Q7hMc)zMPZ6> zVx7QBgoCp9|6Bk0WhtZl9n%X^%6U?HpwlByzG$uiS^h9q|6*!OUrAL|>X>aZS`CAVF(jw%$CTmNL{ z1sDx5Hu`Y~&E19qYo15>Nfa~_Q?LbgOaPD6W_ocvKpY@d6<|^NtuaQG?4QL4+DmRqXC}npjToDb9k!=>i zyLG965ZV0x5}KiGSRi{V%^46U!SHYLo428YvUZV-#PsS9PV|-|XA`Ft78D7h?%LAe zb01$*m~z~`b$M-Jn$&?p#~g^`-xnRp*?HEmzTy2&eUJEWzBND=?UNW@3)+cv^z)zB zvurSzs~ivQv#R75Q@)gzwZ{K8XWAH%ufz9TssALt6jQ?-jPV1)@ww;3uwOGbKHEmW zngpZEmI@6rsX9r%oBsJ{*%b3gsJ;hWbJK-=L9#Kj&=<9t#CShx$?RVs;NMI+y!SUo ztwzzd#t5HnKd>%;>Qc!z+Kxx#%UOw6F`h|f^-6p z2{Z>p32Qpxa=iH3C=<;#0KsseNu}~|TED!tX&B}5nonPtnsw3HREPcbW z&Bq*3oUuiO$y~~r!gNC28EEbhD)1}@LlJjaTje#)NMadcgiCTSfzEPoqO#8mxV6ms zN?lQ>HBq*+y&KI1!qhHL^ikXLYv9AMUN4DOO&uz`pf@Q&QEJ7pcL0FVYJlb|Cq335 z5_yQ4D^4_1$BT2G@XNL-clXvubN3MvAx3}Sl!L8McqWaImL9-k5bD-wHZ8nS|FuGC^k^iH)UwrS*~D(&d#9f)4cmgTkLwexCy)b? zg>G+DGL9VSee=1_auL=SXVyXN%YbHMvc6o5nZUt*cXTIm7y9pZ9M>tQ4}P26R~cvo z4TS89GJE?cb`*33@mRZPR+k6UKi~z zI-N=r;~d?H>uGy5`S1~P`2hnAN<#F;w@rlqKDV`t1ha`8VjB1CwBY8zz~E~5N49{fIb?O?GKO&rMYapbzx$sDL!K)^py#nc`yRPF8SJP0_Ap$4pC@#&;T zoKjXD!}9E*iTKH(1=39-!TSupIG5x1dO_psD;gcbCom7+r$nh2{LcD%ggqbm!j8)z z=)^YRSh0fs?0r9CU&cO0L<6ffYNkL$&-j6P{8s0jxt(N=Ci~lmZ=Iy=hy22MdqZAY~MPbnJx|DC#`e7QT6MZYxJ zSPK99|DRaci6)dGTM+v<0qDOhOShwdWq_D9=#S6iGtLQ)V$Iwm6wZ$5s%1&8z0|=p zy)P#rM}|wUTw?mMh?p|Jk;8N0yD;PB%DQuQDTH*|&h&*W?4->J#d#q9$!@G;QTjm< zsplH{$1-T)zV+LgZ{T3wY9lL3-xx^rgQp2%vfV|fV;)hV{5x~b)W)JmKRS@;eouHH z$?^bp&zJ~D4h!{-z(c-(!NjQ1SfwyUr{YIn+yg`-R1e>^ej~Myy}bmv*lH6<>Ln0Z zXauUp%WRkbi;4j4G$5xVQj(*i5c){Crgfy7Q`^jM`YAQEuS#C=JUh1|d;U1kfYmg{ z!R%QQh9X>+=*2*g8a%ly7GJc(_h;2dU2&&TVu+JY3o>kv22g8(i5Ke&guTky&nKi_ zr;Rkb-)+ryc^Rx=B@OW;F(z9pjbBbD9x7Q;?7S~q@+&F=b45gU`0^sx9IVx7X4g19 zae}6$05oW+H>f2oH1zNw?NoFqZoQ5fo%H^B@_#Ie({`Z>q@?nsk==WDO)5LV4d-c7 zWhicj)nfl!6O3K@RS-GweIeg~-tDfc#d{OWH#u0?1pSBSKGohsUN-s~J3+D}jfe!N zg8$tH7qt?CUqK*WM< ze2nq)#I`)!YcHy1WvusH2#=-1K2q-OF@nk_&b|%?MTsQ^*{%eNDbnJaZr&}e^%5M$&U%uy{P%(-Sf(RtdMQhx1 z=;+zV$}BmEZXOwEKlOR^0?-}U9(Iv&~u&TJ3JU7w4a9)cgXR~1UogwhM{=h$&E9JyO_@{< zv#ZOXR^K2jZu}IFRoUgqQc!)ESj{bCP-I6rrmq;Y7{5#vPP?xGlUl67=t1IEXHEuS z2F9Ys!tSq-#P^^P%Q9Dm+z(B@op)nDIw{Hh@4nHCDvb5z#-+z3PA-PRnT_IHM^1SS zpCKgnar<^CW4(Z5vVb&{S%*{^w-x^cy>3R_;aNaO;+x4 zpwtZ{yO|?%gzZt`A*q&`u@W)ET?Hj;jXCJ~spIfgdKdr)+PnnH zWV55(%bGQk*N;iWsDGjI#S!S2!t^j_30-3h%wfC$v$667bCF0NV^9M~m12L;6wa?#v#b)N-?}P(RS{t?O!z6yC)#ed!ERRPTB0H`N8Q4I2tEYidFlV>mXOlLpPMhf znd}10%757y9T;8XPaSRHaYA>Z=*a5t<7S#Z(Kr3_Gw*yp9CsXo=LQjU6uNV$tLTKf zc*QSmC+*SFc)H+c`uu9k6!jDxu1k~5!XYL>^klZ-ZFt77mbgwaCZCeOawOWuJh%r0 zq0X^tCIPMTqx8E~-|X=Y`>;o$`k@st@@kka^?@QzSE7^niZ;$@>MaYIzR-JU#DSta zDeDB$R_2b_e0*Nht@rVP(tOaW5K6ub)rj1Mcin%2IJQA6>a&<_HPy46>PQ{!Sf>?X zMtgwuXq?2nR8C;dtb%7S%+o`0Ph74qQzg5g)d*GBu$>B3A(x6CBVw8C80qzd*xKtZ zk-rOj20F4bu};2*4d5B5mlqOat14#f=oKO159IRf9aY=&ey+(ITiNn}8KCDU9Kwo5 z@K7QFn5Auc&@eLu7?iCKJEdnF*Y(|)?)s5t(qtm{7T?v~0ft^Rc?H&yRa9Q0i8F}X zH^V_Jy0JX9$yk;C!**XkhsB5@A8|zA}dZ7A=2mwoe^EPuIr3A|5x}vnvtSnR6_4XDU6go=hk> zmh$l`iJeQ_-$zZu*%s+(PtEq41JH3TuWp@3CiriNjhV_A5BKCTmxo>P^nyRJ%evS| zj6<%+`?4wcFENx}Izi{>M_mEXsQ6=a)O{kp$NBl05@?lIS0fZ{QDF}~orKtHW?D^M z|I)nu2kt2R{h|7e>KrOzZ-;p6C^>}RBKQws`r&*-$Uw|fK<7@v05wO6jJ~~2h;GcZ z84DPyrNaEzKjoFJg6f3DzhNjTb@OqgY3$UpPaA+2%Kw3t*Vb1i(QbCE#ZLB*Ij=-j z%b%`{sAf)i3c{M!>q|4#p<}|IliLmdoG=*_p1i$2j+c)1`e@@cQ$bPb#t; z+gSxeRSW;N{Y^LC%1CJ8Y9e%~+iozq!-{BXun}xi_f=CeUa7%MC6hd|f3Yz!Xp55w z^9QspUoFq}5VL2&kok-5^l@{XHoG}$g4Zr6Vgp+}1ElwD3QO268L@g_&@1NlS8s_* zHHW=R4)^M7ZZF*Ri-JuQc#;5mTjoM9j20)Ff8N@QE!ZEYF4*DYr`XG4ZRJzV4RL0+ z{dzG9Mt*CTxPp!3uR4Z~Vd8^2nPBI8UHLiL2lTXRl2S&-FX)b9SL$QAId%}&`GY!p zW@ql~(T;BId=%QQcd*OyGI^CZaP!#P{}TKCq9)+Z#NxpxK}P9@>BC*WT9?QBt!R_V zTghEVHk0fpXw$MNPe#C=;8k%-_Wqy#2K^thvQ}v+3KoNYT$dadz5B4rP}a-QJ3u>d zCN}Thls0g?K?kqqmX!3A`z*ypQgO|UAA9fg!2jGL_(+2(C)15urZUknSdO@YbW!Xd zdARBAyLEYB-(8+Goj%-TiM@ZaW1E&oRW_K{3-LaZsWZ4nfmqKbH=^UON+Jy798LzE zg08wr0Nap&!t3}zJW@0{502{zbum}2bz3?!QC&5RTbHdon@5==b7>PcD8_Mn5>43n z7xLK2!{K9-6i2E}@r^re4l#bncK-Kc9QiH-FmkYXswlJYdClrNcg5pV#=Q7p-hbBVY;eSQR+E2yD@|u@OahS_v)v4aOgR!E)K9 z?wF*kp{bHeFj~IuvSI#J0eR|wfdz?NhEOz9)@lBNi(C(@Bf(Ko@-$?p%NqkVg8m#e zFXrw#_ed5)9DmPpop=RQE6J0fVzY<_kpTMJbf3MC5aRpAG`oJyYP!U45LmlpGAC}d z**8TdV?})`jbS{Y6vAi`>dAL!ytKa$X^7~vZ`B(*3-BXN+{uiIpy8qJO%3q8VbTy| zCf=SR^ghF4b%}Ne@v%({_eCJ2d7Z{TlgPQ`NYW$T=9V^fQG z4ON*Zp=i`%Vql7m0rDxR%5k};*K8FwNgbKSgtJ_1wtcY=f_p9G3Wyf#h zye3rR-tN~~(oKhUfuD)Y)DFLz6KrM$D+c7;jP=v-PhZhzpc@;ql7emi4b)$GNf{6V z)kRGT0OEHFjeq1>O6LG)l-eqvcr3&LJu9cv5SgY{9K?bAhCeLO!Ta8Q*|A1aOj$un zvb55(Q#f!Q{W24Gi&+4+EM1S_c z_^@iS+LYWLx_2qk-s;HQl3(>D|B9vELQCCea7|?E$kTEHZV}5M96}W``raP$qmZXo zdY26&Xbx)eEZb5wtRCm_D87+m6Y9Web&BPK;IlIN8~)k7yB{BRa(aZjBgBgD#0W0L zwYDq^v`GM_bI0&t*W%2R_PO-+GZ0a4b0F)`#h2z0?de)??e}rnH5yGTb7p^-kUs6o z0IrfNT=JUt-)EqR&Jr5ojzji8jSO^J?z&|x$?{~SNu8&6xGWewR8NhO96HP=rzoQH zGkPcL&G6=F;rKruXSayC>^)r6EtKcfI8*}fNrL|%M3oLu=}!SATbye-?)+{VTE8Rs((5S*p~-!UzODV7`BvgI2NRH;9HmJ$Nb_>BRY zuc&cI2EmOcN^yH`HxS8FQ-YH{r2|q#T>lg(I&lB{hI)~GE-aRruMZT=BR|__ihpQH zfnv#V)*B#tUWZT`8wbeW`LuQar1@2WoaMr)2xWy$`SF!!ahU%odE^-DpQUa5o8uYv zmwi5^aJ5os?731$VT2^;)<=fHA$Mb|5it^7I#}`Z&bma+9eY^jg(;rp5z83ML6{xe zg}X3g{%C{?a1irj(Bg$HY1-I-K%P2I`?u<6%aZ@JkfM)*m2eC~8p~ATvUyCoCi|~t z!ia`h%0FwP!i0(MtKq37G&Eue#Ou;#k)L5{$Hz1*Ora$pSuEW!CA2OC1j;!9qHWcs zCzekQOC!}PZBk~L3geY4fu<(O%Wbt4^!Q}v@IpxFvR~glOG95t>UoW$f2+yQcqgdD zSbY(6XSPygCazOyj+c|X+bfO2dzdymCaCtfj;A+p3UwP^3=FG+ituk2FGa;-|8YS4 zgzXwhxla5!l%vO|puW)3GAc=_YJP_5!}H#jS7E2DiRq*)itqs%77wSc89h6m;-C0T z{23bhH|n!9i~c|@7LTpM&Ts#S?4`fPWw!=S3Bb%d)eA!(0z(4q zS~q*vCQ!R9uywC@{xwQ#01@4_6*eVj+Z9jxXhPUzWk`kb8TqUC!?`^a%~N4Z+L&hy zHy9bBrGc9gjD>cYe7+ZhF`Fd{;TQSgc9;t7TLXo{e(&Y7I;;#F$tXhZeUlI)1!~3!&?h2^^R}JB zDL0ZxMUkTPN%Vpi#sF2HJaX<#B}};qEnGVHItQaLhsNVY60*4Eg(8Ih0XTLJMaWNM zLPygLJ4qXwG)5McswFl@2AcB-q0WIYZ3ZFw5pv%`!DSVJs>C(>DgLI^N<+vRF-W#1 zUC-!`9MWeP41IV|{Fu3G^2Hc4p<^L{h?j}hdiwKwfxtyJED3Kk8#cVdcvg_Atq`ru zY(g5NvoZoW`F%C~1EtYYLd<128awdmGnTP*jwCCd6@7hM(tv-2zVoyH54( zKQ_mC3juF&yqLv%2Kknf?c1B|P9b>9Fq^%K5H+#)__WJq6lkKqZ_SrCUaHE!vLhHa6PH84&m8Cknvq;_d07i}Mt}%-!>vPmErbhBYxM{TXV$_s|H65+uvy$LBMi zVVf`hnl};{+>34M(*l$Lo?)_^^Jufzu7TRG zFj)_8U~0j%N1MGpVHeKTcSeP%IqZ&xp^RP9I4W{9VipK>9I zZo>owPOWo$SCKHI&!dhi5oHxaz-FUqCT7RFOp1|ARbFnCLF&PO!Mh_L3+5`eQXU}! zV?uW%(3`1<0>Hzur9Ld{W=DwYKMhev*yEB|K^4nXk&XKW2#WL&`e z_?m~2nC-U_?84g|!&#*DUu$Sf+Nr$c!7+ z689ry0_-))_~i9Tn*9Sdm$I}+(!sIGZY^5VDVr?%vj@dJ&SS6nJonuUg^WudMHE<* zdCU@K5K5hG`_`OXjXfT%0?F|!6NUO#GxA3N?~Xx8T^T5$W;gcP>yu9NJcLL-0}XZQ zrOs=ymWMmalglezxIype&D4A9$3JYw>4j|NLr)tvk=Hx~jr)9~s92_Q8n}vZ6Jw^( z&=Jhz#?GXv=`y&UG^=eBx|i|VPHCfQiW@gq3A3o84co4~3XMAk@y@YI6@$KP{G@sI znV0uxdGX3WgT`vI3Q<+jks%GW+MRPcHmDl56!66Q#TwQ@V5Rm$LM9J|YeYtrlkn+l zcF{_C9#Rs`9Dx0C47x&~I`!@W`&YFGyh+)Q7|Kgk+FwWpR6I!4QWH*gXx_NBBjZDG zWP!}D3fbLXKvH$|%4@)$@!Dn5n}tXcU=?Ta;d@u<9#V&HxfLimA7#Y?3&=e(bTcr~ z!C4WqyB!F1;Z#P2hgzbz2_$F8a7ebnBJNn^lQ(cR5JYutQXVAm+7$xjpgRbgU+2|1 z0ul`Qpq)+JP4{p9AOWv4( zTJz!g003g4#mb?D$v!d0y~w^kv}LIcu?^oL9ctg+<8p#!+>N0tPmV5Sm_&Lp#=zX7 zaA+XRK_rFV2o_bYAbsv2r}ob$uko5e7wb>6Fknthqa6U_Cgb&f)K`Wh>*zhkp0Hxa zlwQ0fsg#iW$ zr)olkO2*^n3bPa8cOVq`O`SA&6yV!9gbw20OB1R* zO~!Qe(@5h_TSWmPurjO?myTmVjS&#&PHj0wbGQJLKZJ}!)TofH(*mmt03fe&KH1|k zrdZH>eD~4YJg9jfWEenXU_w@o6i|RtEh2|lc2u!o1509$%&Nk(ScI~ILEY2hR;bd5 z2_}h@0Nvp9q^Jl%Qss@ROVUUH@7aqzOA9x+xF5*eM9TN8f{8)K1|uk%N?#N2+SV-0 zAwKt0I)hG7&p=d!=dq8?iFT9S)FdBSHlOQ$`7Um&Ze)$3M`UqunCJLxyo6^-80Cd@ zg%9kl_N(eLn3Lsbe4%C1%&C~#@9I4r?0a^*dgVE<4{&6V`;I#x0n87U4?!J+9is@D zmq5iFdN(3c)+lNtbjFA6Eo=VifyV-<1^#aN&PUyu3CQUQVYj^UiK8+Z9VbTASECe* zjno8x3tZ=DKt>qhJXlS~@jhXZZ$oNmM?g7f%Q^YC^3_U<7ZeJ$(MH*pYlBI-PrNWW z{~XFnsDeWEU)T3~gg zKk|e-zZ7X0;=kgOL7mckH10-5n4HPnRwHXS84%%aQw>Z*U>UWBUmo~|L`9bSB#6>( zwU?E|uJ#eT+Ga__eF84^WUfdE$nc`*%k2q4hgCPp*{#0WOD9lAEM6Y{nzn!9Q_#A* zzFwR-p)|Yl^CTBUC)4e?Sw{Al}z6aMR-8=sq+}KqA*NS25Evc2Vv` z=HTkFt_TVoVDxmELg=f$-c8Sf^gd7$H8U9XM3G(ECo4Hz^#tm#eZHXR z+1?Y?0DxL*?4fKhmv6xmZ^&quT^SL~zC+|E+s=T)6YWBW^mQ8E{;>VWVek>4-2^uaX{ zG-sZ==eXdj4w{q~p~T?)on9dv(Ibzs3yBnZ_^cSS8hWvbeK#;Nv=xmOeHoacf*eXY zV}?rP)kbK1lN>)!D=h7y;J@R`+klPXyDv&h`K(O;bNFg&y|eoKR)9bAu^t8l1VM`Y z$3zgNp=yQj&qy98O)WfMy5p%T1OJp@T0K6m((RKnG^epXApFfo?-AFs4T!}*xdU8V zaU6k#8aLt#5+Y9__=j7!XRxZ7rq1t zFZ{|gKT6{qmzzPTTsV@&4)W+vb*Zel3lf4wb-8lsar@9n2eOgs$V3P+%YP#> zq7VYgxSi#qNVNV;2lok)(wXR<1;vc_>B*>I8SI00jUIM}Ie9mQ6$MXE^3@@iW;f0C zfq4Rwyl}xRn_H@zt2}@#Ds1G_o<%FAq{I2FIXuQHNok`F)|Bfl6Y{l_EXJU6B)?Mz zSi(8sb}Q%WX7Rt%NJVXrg{^*`go%vOGTg+>pz<|3dNB4C(Q4O^Y*H=sc1W2r%K7l$ zE11gz@Nu3qn2mQO9iT5!Kr^p!5~^5g{t>0Ld0j-YCs!tJo2->KO;*7p2JNIgkHRP7 zQI(|4^5Z$skgGUgc`x>X#xyxdsDyDW4CVpLBrhZ8$$f5hCc}B%A18U9U-hlZR#5$m z`^n1~L*gI$cU$q>p5+rDgFQiN{XiibxgJW=%V*Lmz6DSBp+sWfjr^dpX_S$c?I8RWti8^ z%Qn(q(a8k9#F+Ap=PtTg!^*%1_x=JL+X$6ApX-)m*l){bQnY zl*eF<)@S>Oa)M^60`rGQ8A>Cl;@s1-QG_r^m}zjX>Z;NenuMr zqxuTrL)5rK!hl;M&mwk%C?c}NVL_!OWIj%)A)LgY>5+_blPERY5a=I(K_Enxboi-G ztRz`gVG`+6f(v=P!tS-R_rs6L^7JCcZD(dtHJ9n|dZHB_EZ%~*)||k7MkwOPCKkt= zh;Y`O#+MUg@6HMZZBgH!CKQS7FC!=4X>emT-OlR;?)SS_I3 zW^TcHM;mjz?EiHdMoUYa8`fQ?v7cE(USe&LFH%xekz}&Y_dhLw!y{D`Gp&N6*?K84 z3u%U3pP{mWN-9cD``i3x*lM4;N?|Lw8UgT9OajA4szn(RFP^mhgr}*)r|JpKd`Aro zI?pYqH^%J8Z))LvFObmgsA`kBkjGwB&466>Nz3qc^REgIJY8#UtgICPCliDlqFJZA zA{KWlSVcB@dpA*Gn@@h)75Kp@PU7G0K`Rzo`@|p%RBON-@E#y!mif z)%fXn+nvnwwdlsG6Y;`Am-*5ojyg#lMe5?G9-CFAGQzcsCyMG3LWE%RSpE3(cGqO97j>Yb_t4IEj4UiNK=^Apupip zXBjxHSj{ADpP=PsfGq@%Bf#;SqYcLRKM!+H-;Z?9RBOiz@h#FT z+xy`ZNde_&`Z8A!Ck*;A@Tkf`Z>Q7cJroge~YkcF54t zS&~y0Eqdz(`5R2LH!>Qo%BXGuCUG9``~VwYYLL!ce5JnIH4S6Nc3ve4XDF9XmAl8M z%7399h<%}UrQ`!0_(hheF(ZFMW@B{13tv{6?jdcZqu*G4H~o{lce_};!b>v)G5r0O z9~KY8FX9hs#ooMGpIkXq;JA!#s?u;2#x69>cC)qtq2@n8Mf9Sh;s!4*ohwO39zdOt zWQE67p*w8r)2R?F#=966j3vUjzP?WJ2ALd8N=>AY&&;?0X}G+?=r>M~n*(Ij)0@yL z(_a2zSdjilmpUmxR!k2&1PLO9`D<*z9WESOVQr%!& z0x~v~>am`*)>1$V2E^3e{9wCziRP|h4NZL#9v@W93K9Ri4*1HjO z7t^53Ab+kI#Xw$1$jp1fKh&zFEXuYe`^Wg@x}$ThV}>dQiHht>)2`3MStg0b-qYy9T<7q}a zjh_by3oUKGF)4my7$-SF`wFJcMu%;`fN?wgH^S>@>#TbM}(fo)6UmZJKVZ11Ri)s2Ls96B^cAMv?JZ#%)lTQ&hnZ&>R8h)?|vNFMU^j2E!$iTI7ipX0l<#lyhcN4Ig z^Kn8R%!y_^js9X`K}qS`btGoN<;0$T@mY**Q1-o>Uz7zVIOW;k1-z_E2NSco7P*Hn zn5r?yTcu>))h-o?`XE!OgB#O_JyUu2;Np%a>Dck!1m^0WYcPd_YtdT7EcHz`+i@FMVY*8}ud{2~I zr%rp+gXw!Gri_y{Y7RL@v-)18{^~B#*Iia6TiQu@J_+sM##UWKO!amQwiRBE72`T- z&$9P#FtvJ1{?|1(i%cqu31vFm9_RI^cG^DZf^YudB)(BxY!1uRC3!q+x2ezobWGHn z6t8fD;JE`P)wLtK* zrs=Xg()BGe$>0jt;BQvuP%$AP9hHV1iBf=q{=R!R*|Jzke+7Cv0mj;dbOGSw+D?AL z2YD8Z`lY_lq3{GJf;uBLk8;0J^=VMfoD5>Eq+J8L>NcR@D zRCrtd+#wubx0pU<9ObPupA+|2TF?*eix{IXtTv8PaWo!b&$Ov{G0cg&%6B_$NqX01 zm*U=BX2pF)V@CvLXRRR<6ginJU-^>>9Wu!~CR_-iFWyP;D(A#kdydA55Qm$L2WXCQQkVK;g zu^lBCj2xcmP1tGlX|J~vN6~#(LdeG%4qcFnoI-i^4q9uoDcERM`XFIfNU5yQbICGR z`FN6hKm?9CR9W?=!ty5PXLrQY7S?1q&}$u!;e!P*W*?oveuuz3M&t>t{=D!sqR0n zjiG^C}hs&+&eL4`I_+NUc$0bBSq=lc@PL0b~U+LQD-XRUFxd))^6>V zyq9&tMz|mK({fjKK)k zg7gJd6PjIk-dU-JEGRSK*1^KM=UCO0PK1C3JC0*7Agn^A3;$zAw@Gr4Hj+TBiZNBuo*NsaRtF^^r{Ta zX@8!m@-J^W@D(a5Sy=((`!rUdZ?UR#UYk`FhP z^ayj;Z0R1nkk>M0(;(l0-M`1Q8&>4mQwpaZ7G?40P+l%&R#vO-5K}}}L+k{`Ae(QT znUwB{!vQf8J=rpk8~=}JxE)=X{me_`VK6}}>Z9U2_4+k&$dbQGU3imo5aFcLD&rXQqN6sFeRc0m<0Uz4xu&#@Z^Z@2p86s7Y&Jf=8Uo?)uQ6jRP zVdHo)9+!%W*SQ9gjl}im$09*?r|zCiUq_?73U0RN8Z&$n;KzX(mfB?{0JFucz>6XL z9CUz8$XXY{YC;S`OTndw2XBTcxiJ;_XK%Kpxs z+cJ*F+A}(3{konF4eRKTmdhDOry=EM6$d`IIcU9l5aFazvLjn0%m^gH_AivlgwVF= zg$NpM@?{ytQkiu(*%_d&g+0#f+b|T}DaxAz#LW1S@YpnXTDEg&oW|ul69hXXA~*5( zUdJW+k75A*Rb3|f`WOb>TRya{f3_U?^o)!$3fB?N2}EOT7Vl5NmHP;DD3uhvw37-W zVAz;fmGxVee>l*6;2YJf=X2VK4{=1pl=jFAH@6^t)>N*P?Fr|k;#EB(IIW10flAe$ zuM)IQLDx$2y6rSPtsY4+$3K{K2EaHw_WS}^`i{Pe2}ZHVb18giP`KVIOxNHwH`E$5 zYPmbq8ZvZHS*aGz<`Go%d)!*nH&{lJ0lUXlq=A}FUOQvC+gMj#Poqi~Ut+!J`a#y+ zT~_ETw?uliqDNTWd7#HuYs-!ETv*p4v+xpAW_xLZiHuXL_AT*pmycpk>a$t0oIo>B zKzzF*VJ!Cg*GIk&4bMcF{l7xqqUcoaL7A3=D>5I*UL-9e73v3hLYnI1n#F6k4re4U z$+F;wE_G601|NE28*OqgLB)Yp5mrzK?v+{!^it+*_)&au>jCvORwxS-3wdy+6ELPu zB0jH7!aE#iD74+v87n}!VQ->oVDL-KfU?-Z7HnbclBszXJ*s*|ATu&BIATv7k0C`V zodD@u1>9yP{8H#Z9g=%2^o|cmjaJa`yT4ly&1*cCDwEG6(VS2--EG87t(KwbY_ZNq zjfe1o)*o(%JJ`HFS=KNk&`G(v^E1%DPRwXZYrU;i4cfz1U3Qf0rkrOh5rho_hDmXa z3^-SeI(D|^>@k2MsrB{(4I(;kWhEXwqA~_Nm9Anc1<}e4K>Utuf{tC#N1JlPpsCS^ z2QDDj2kq{n`f6KkTf;c+B|0u(Z96Mf93=SGro9~^^<>TJ3bha4wN^S+yMIJq$+04(oZ zQ2a_-5erbdRM+)YS8jw`g#ycPI^80;Bc)6)IMP6!69%LK91=EcwdCEM^Kn;RPh0Js zoICb!1j-5Q4ASI&63RWrs@GM4|I}>yTIF{Rj6uqd=je;?vv_-Lx6-eBj<{2d-lzsb z#lfQrGJ6rt^y+Vi&|A;54`4H2{bgNys48y@^LPAYw@=$h6ga5Hj3|lC%`|@-0y7Vz zpPrX6a@ZN?CsGGU37Oy@mRsB-lSpu+!=97eJos7E%j(YJw5#>>hf}X5!_j*@_nk(YAIYL(o*9N~rnqyuKiFwzab?+^!Twj%rZO~m0{&Nm=EpQG3Qwbt9(t60Ua>W|x zuh^~vvkmSi`%I2f6Ve9DRmwV4nz93E{A((FJ%X+qTKUeAF}9+7JT}a5$C~F1KD!14 z&7!fKMDIKg9*MS zy0yWmg+s;{x8JqKtv2ujzJ#W*mIB7*+XT-n@oB=DtlZKIcrzLhj9P>R%@V*td=~z+ zp|4G*?C1}&vyR8-!Vc&sgW)db3oc zFqaP+jqV+VW?H(a*VllGI#0O0?Ez3|+D4h}fdla*pSsc`JyTL$9x@D=vj|-s)Ib+3 z4~nt|;*IgFj7RTEOlWq=!4qp>BH-9aoD>$F@49GYRE+W;8tbUWhPFr9J_%@bHi*zw zQ*_Csx_U1gK7>6h2T6bd3Zb3|-b$n|De3+?*~GdV(OX|xiz{JyI+z3d)N{3DB}+u9`$X=f~1NLZKS55(|5)r0>js7q#n~t?tEA>?Y^BKwm22C zobMfUatY5W4Nq7U->%=&lu`{>urjCNPck6I@0viWIlh5M%_kox+LD1DspHX8KwPXz z_TDAiIvCjAfE%4OBikuIC95FF)wgzrR#KU`p+S*+!Lj@QL`I4kqeq{#fVyi75+riO;vB8z5koP3MQsBYWhdY*b36U=#TM4M{`-qLEV8ANTN%S* zIcqK2X>B1g1j(krEOMqXh^+0Bx@{Zg65pASxG6#hZ2pLv(JIw4GAp>oz|?ci?L^hY zpQJr-2u%wNd9vZ<@kjQ|0#!PD}|Wi)a!Mr3^1)PRPS>Ov7^rG~zmheEt* z3kyQ{8`F#)Yk)T)k=$l_LUB*IDxZAN@zd8Zf2dDz0i<8W+9F;48S!r}Wl`C9Zvd6H zZWf7tCZE-n@iMqhlmrID_0@E63@GuJymO=gV?T@UGxkpq-^1cu&dkS}n`EAK~CHZZPqBq%ta7}}PPNkbeS7xt!o$UM`_K!#E* zTV3rSza!K&Um}Zdcvb76fRsrkv*%X%PI2sIm-~mgeiziLZw|WDiH$?oTT(`z62tE` zqr_wh-@@BOY?Z?`A|SkbP1qNeDJcv&_ycfHcdgUhm=d8@-n3K$9Y|vzBFzS|+fr4) z6Bm4y;b>yYktaOZ;0)!X3k2Gh+zSmZB$%<~b5z7emHnBz?4(Oc*AGM;f;9Z_s1t z-=UJ}yK0_~QKSITLRN;jgs>!!?x`4Tu}@$q3#??%r^LDR7u3TcVA7pYC20X{!bN5$ zTq3KcN83>ewM>GfhN!d~f43rn+frnvidT*`*AWPHumVxVar2A=y8j{U6#}kVLP04P zdVfFmSWQ#m_6Bf(F3UQhRWJ`Zm-??+kZZ7K7zfHe0FF(M{Wgm&d4QWnFc<6V*G6J@ z0tpv)RIHVh!z#9KcfX{tYBMa||2xolOkWz@&<|D(Yb)KUe+hyQO3hR)~g`d#ja;$y7Daq%@$tSWtoUO^*p zL?;E8P>VzvjGGQDyS${2$xE;hy`1Ns?wc{i^AQ9yCrCpWsc@|&tainiAy^R8w@(S` z%0dCXP8<}u7kx|CX#ssBs{l}waH$Mztj5$5jq9J9kQ~D$(O;qcBiwIK_)9+?7CcHd zgb{O%$+3yLHSre&M{$eHeF+Zcs=Fzo)BxD#gd`6!YvRtzdYt-6L*D1{giHHUo4jf6 zvGP4#%@?|U<^}SKM6KRwALHaXx~(67nEB1hB4i~ z1|M}xT)&!%Rpj9S54t<8N)p^{PT-8SnyzMi_qz-89wlH{iHyMnEg64$#HJ;~hZM5( zX4qevDO%gmuK?V7}k!;*!*^rYRLCGeF|4jzkOPH;%* zPNr?g4UlSe9C+T(_6#~X;+Ht=732ez6(y-kWGdv(`Ubo9Uh^vdrW&}((Em`L$J^xI zz1itWI4E-%TPi;CSV>o@R9Z@X7e7j=`dcpm*8K{?`ncE#>5YPy9`SUNUg7vP%zJ>t z`uYIS7mjtyZ}IhV&g}t4KsN^gGL0K4e<41k*T7Oyeu+1tx%@`ss zys7tHdfRZ1vL-O!I%9Ik#PKd4WV-t(x;_WxodCLa%tf1Q4JXGh8h_MrahVzo5sp8iR6DA>&g&Cp%N;}t2` zi>7>-g6x`cL^AaV%W|^KmCjDP?3(>{FYPMYuWTK7IjhRk4cXOoN^^fd^JAF^uV!I* zSPpa5mzNpo0riBREh2mpio#0dOEJ?<;5wD-2dT@Eo5N@+ffeMtFUfo*zAgV7^7rNB|;i=i}HSwHa5Ik&g>Q{T-}VP@i`|8xN%_e-A=^{FFRmCJvljXNF{@ zOlikxk3+oMw*lz7V`>q5O9SD!m^pkUZgzeaqgNa^<=qQ}R4my=cWHs8xrzDYHayxZmR|0G*ZX1I@jZ)$&lc60d>giaCXgL}uoU zTGhV4Bi!OuKInqo7<`(1y-w*%SJ-U1x^?>dT2#>#B^ePWZLWCLVE>?d$k1y+PP)7BH-G(H&~Bpm6&L z*u^sO;)g=uIit^P#ACOSRvzdXTL!p6={K+y=Yc4LT!`j15~(n%F0ua`47_KW-gU^TVfuJp zYpZ{)PW8};5AR?LBJYBmg zzCfz%TpZSWQtSRuX1{U`FHyQ~gD<=d6tPuU!yQa6c4aFB`6im0+G4POSH*rIBCRd* z#IW1R=swB1=?KcZlMN#qi7K^71X0rRMMz6<1P7-ya1-+xxfpEFVehB5B)t$far~f3 ze<0&R-4!LrBywQ=ZYGnWvpltF4LNqw77?pK@58(^6dR5O3i(F{-0;!lnnR;;OemAP0A4tN3T=@v|pn#YR>T53beQM z56I^gxUCziwaAzF02d0+1T|&tL(dqH0hNymJ)U-t5Mo0At|PRFCo|w$wY9i(gb#Lk zHOfOjIkA}8R^vUqsYArLqGgZ}mPIC^|6-5uZ6343$S9C?MYtZSHLkkhNSr0!V}0A) zP>E3Y{o!ugkAU5$*!yvfZbw-IZYesQf!!6Dpod5jIz}$kL6BQgGtUHF;pamj@a_t; zh*{2ia<(4tBoWVr*G!)rcMypHC|uf+LLpq6h0k&<@yl?+Xo|MUEnfYBw}4N94!w2A z7sd%>xY0T&c`7k737Y*)CsC1_LP*qFO#4o@H+WrA^n${ra(r!jj5dC7vJ#`XjS_w7(OQzUm~(U_`v1)?AVIj1$^pby_dcOcL!9c3LNjg@~B9y5-G~}TW#tP z^Ec?xzgB;09_~&Olv@eS6+cdQk;dHp~Ifh>X}rFvLYEZnJYy7M8^ z54;~~NZ9}+$-__2@F1@l#@ysl^az1%YOHdeDI%Qqg)xr#6g7vWJJx0IVAyf`7Bcw6 zz~JbSs6q)a(OXlZ@(kn5*^1RyCYB^>4TONWa|l;xAsNGe#)bBN6=pj@-SjxotLty8 ziGb?mGvU(Z{-}BP>(dT~>b<~WqFV#WD_{QHaDJ<%j@EXa+`k=0$+A0$<9?qSj9ggte~J8m%L zpldg0EnP2=WEqzrPKH;b%qkI7xT#yL3OF~P>^iblD(aOAFnBJMt6#f5fSd6ge;2rGVNpcrIf30>nZ;c4(Ij@A z_{Xz)TOnK)pXQC5@FrVX-%2WA0e9EYpGGrn%@0FbHU2+MgRFm;@x5)av|D2O>D_+^ z?ac;cCdCI$5YL@$q~bUvNj#Ju=%&hUT`UFmaXv5&u0e~6`QfsIj;@cTAwIsxq*Iy? z7rHcO*M!?-yOUw2U>}|oZ1?!*pb#JU?RK{xMpx#(DmP>q5bo}&Dm{8+I#Fl17ipwHGGa; z^cNk@Gxdx^O>sg2%^=7q9`^v!uJ&;+QyfbGR{U8c7Dqi$pCB!QU=`YH-`NBx9wduf zAKHS~@Lv`tJ2m51OKp09+6%zZ2dSYuXOG$Lrrt%AF8lM7 z8Q9kJ1B`#`d7)S0Aw%E=t?#`~djf7+VX=asl!>E==KLMUDQdHU7cSsr@~mP{Ye%4Y z2|u8rDjoh2q*tWyDk;M(D(E@U9LY`8H=>J|dDUa!u)tb!A z`Gs2YC|_xg>m zQlK*_I+QEeD&%H`O;WiJz|J(pbxzC~>325o72niKjzzx%nqlV&F-R!8(^}_q*Rd)* zyP)bdzmAd9FJ>bgIy;S&!umLj^Xu4y0DP*C4i3#r?A68Q8zy&0^vIM_9=o@l?{Gmw za-RSFNRBDpx!LhwkX^51Tde&;Dj(Qw%Y=ND6sRC44rtCgd|=3{mNZhd22y$=%t|Vf zq*VZF`@nr8@T4&S_%m492x;`xo=H2z%Xr1+O2e@%t_Tg<%=O`JXmDMXb_=eA@vEpf z82?ZmS-A&V2m9#6j{Da&W+oq?IllA4Pp1~WUv{C!cij5j4j^$dlf*CJpjk^tTI4~E z{<6Q(c#0hdFz6L4Q0EZ6;Ffw!ylFjvhI82>lZTN27QZf51fs)7sIP8Sri-J1m8W%6 z$CE+=Qo6ta@>56$G8@y_! zCohI^sb3Y6dG@M0AZ};7j<0QAo&wTY#Mm#gce_a{5R1(TACeH zE^RL)(74DpiKwmDr;38%-Rgn|UDly19lfX_IN%4VH(g(~+@76@5JP5&Vgq_rVm5aC z7kW->-W|{VGj}Z)!Oedz|6-yP%2l5R|3GZ%%%>C??HPDF_6B?9`k>W@5%`Y%8IY3L zV;R6w)b4CvlGGyv98~`8IYru}Z+2nk>}3n&X@QxEw?l|j6*@+3IIf6TjJy0?Af+B2QKF|6wUwD`#Nka%VCBXgwwh=F zJNWCV{fkvMmjii&YNZE`Ov_vww*_PMo*XG=@P%w4HIV)^{&i=JdGEmoo>kspdo(X- zW%UVdFRmwmw|U5@vRM%{zZ`J8IeDTO{0wM@wq8An9tND;pR*qQyie<91Cln_!s z?PAz~@KEm8PLC)nkLzwVf2fv*UZw+`kDv6CnhV~Oqsk1+AQLF9lxA1cW=N7${n_eo zVgX5g9C=eCzec7BVv2&EFj(Yq16VvuTceg~Wkf!&Jp+v$F^$^<^KV~9WlSoO4V9*#S36HStA)Yfem+X(P;Zlk z=!(z~WvuBw@(RLoeGkhJHug{?s4-2dQ@vA4?-`_*YY8+c?j@{n?=RTXV#=JMxKOZK z?Qg5agTgw2x0Js>z(P$pAH38WCs7t)TJfnlTaKSu;XXf{dUSB$=*r(%u1Q;=(9SFw zy*>+HOC>PiYScx_-m@8u1p2^b0XF&+q4OY8IRgGszGo55Dzy5I$8&UfUm#xE+ul2k z!fqY}9|II9fH%1M(FllsI7rS4QQ~i@MH4YC!1_hmM;r?k{At!pr$ASTbk|{94yiho z?(ukzIKv0HHd>97VU~B)GW>I7HhR{E{1iT?Pr0#B;$_5pQZS z$?Xdd+m1;9_xcZZ-2OFQT<99RqE%N6t}BDSJY>$*`>XKaL7X})Gy{|O$Z<_>$iMhB z;h1mqz(l{z_7Qjcu5%wI1_L09L|tkr@pL$Eh`#OK6gFqiwL?&M;{XnkMTdAB%=Nty zEb%FD$3$`PjBULcWDl|y8s6ZfpbWL#- zX~0MKDbJsn0=^Qr^t1UVZP_QIC7>#g11 zP3vsH9|Pw=RsTEJ!7AWXW>SLB3hJmH(^vCGmqPvH)Z;RY*31T~gdq`5%yIP44@l9? zjp-3$uh4?}+s3Z5mMNa1T|akx&=;+>vH_3#_03HV(<^^VY zA=ku97rWVB8W*q!|2s8CZrDnAz_>?Ja{U*Dp>e4*%7%*O5fB@tfp*=B2M+5bU8R@R755k7yT1tK2{Bo`abA@P=&6~zvTRpV?+^~&aWniUcJ?e z8rONMt}81aD4e0e;b_#YFJfpo34oKDS>Z^mwo*a^zJ5+7-dJ^<#5%v(oPRxzDw4*8 zb1il3_}(W`b~@%Y2fo@xATO{)_L|!meIK?r0nsN=V`wdX=4I@rr_+u&)w0}@w5Bqr ztH>!XxDg3J_hc$~|NN-!&w{**p>Rs<$(y9n#d~Mafmr3h_VN%UWgK4n9RvE4cG-S6 zbac4quVH|oEm1!9i4$M(n3^`bb()~-NRmktafRMK5t&c7pyFE&#YYFyXy*`rx^J4! z4K~U7BYDFE*66KL$f=`Y0~uSdBz?$k6r>k7)=0Txn%WdV-EX**T;MP5nZ~v6=p*T4 z>(JU()Lj`pZhNc{*jx_RIrP~iZoe!c&y7Q=kw#y?h&Vufpb{C7;1UgP2F*Lj<^#|v#qB3Z*Q^(Uo%9_tnc3?VK4n2jicGGviyy@u~WYgRbY3GIz@_9Ml*SDztRz(^G}%&qMREH zUQaYaK05xOCNHv!X-{ZMsM-CN3>8|Bcd=~Obg(6W{qc*Ii@O3qaprjdufVEPV0RIK zAOu)jK`@ilX!s?rC(7N*3u&%6I&c#aSGY}74;;!nYDu4QHh4_gcxj>mUb_34NeP zh`%S8^B+4v!pMH+qR)#ta3afXyq{g8<-!zibQmIXtUn4#4IZG-+r!y}JO8&~$3@kk zrB^i{7sKlZoMZGSNvLaU3f+8EJ8m0KjGH)80JID~(%$M;Hwfes!jtn)(X40 zVKyOZ%*Q`B?Qc_pApyiTQY}}&f!_>2uTJkoH)dUT z*}hQLUGpFCBNFB!vjan%kA72u6+m^BG03FUs3mV zVc57hXi%j{r>34;(7P}d(J)ixhT134IH;cJlC71$|87a4o5q|)e1$ddkuoQIIC_Va z#+C1dkb%fxi8pGJJaBw~=b2i7Nlh4EWnf~4Sg<6ae_} z87+Y|yc>(asL2&*=p_nj14>5ECcpXWc(lp#ukK=Kqyfp`imEtze%4K+dEeFrjvP2$ ztf|DzrmwuGHAR9I4l_@DKZXH14_KsqsN8h!pl@#RJahB=T7*69Xg4S}-t~(%+`|QN z=xuI!!UU0}PtdN&GmWS-I#r|zTQR_1R&O8LKN-bdrfRmddRPtjz5qI84Kl@cW0Syp2%#qRN)@_}>9ON|%;r@Qw*306E!It{ zBQRNhU;Ha0;hEFa-`$YV%%XT3jELVTBnF9N$a`|iTkjJH2_&n$!?(eE;#iIdTlnns1rLLcOf3!N zTY~4|&zPn6_@Pj`+Z@vGD`$^X@oJdLylCT1JA$ZdEnMq3v2otD)cB*g(MK`1*^e85~|3%sDBhKB}?QwMMTL z{-WeWw8aQ7PH)VZe`oA-io(ev2D++4!aQsNeK{08kJ}M9_o^#QQ@J`*C6wO=X;}7Bp4U8!8CY+uiHFWW&qvu#_n zHEJmU_%He{^AbI-in|h~VLlZ+I`gd~ezo)1R|LpV9t-!|UhP1a5G(UQ(-FNsUkf(A z1;1kQ2gxOt^pAfc4S%J(Of`MNnW6e=qyj%7(>M&@dMF#E0YLg9<;;HTnpjG5y*=Td z)e{P=wIVs5hYWn4_=Kv*;H{&llfVGO_PQ~tal$?~jkH_>kNq$R|MV{1Rbu~LMMe7! zp_HeoVJnBg7hWMTbn#BRVIimib4Z1oT>q2(qPtWJf_KQ%lqk-X3SeZ@mqPI+3`ggQ z{nH%7D$pe(YSx;PHn0Kk zb_;jkembje`xpL<)}cqS=roR*Z?}lnBqJrb&Qus8!mI(DJpoz#Y8}cC$JaWy_kb@83eMb?0*KEz^Yc5ZlhJd6E&6W z0{(o*pMoX*S=pZRBFlL0q3>qn z+`dP=xpO>feDDT(v8ZN3Ux)Pax9;KrkwP-k(snCD)Ds=tC!)ooM%o66@S`l-=LH1NDq)&_kyiwIUoUfl<_= zS-9LNyjL90jk?NmJC9t=NhRso-bX2J`uxZgoBefb;I4^;U5Xv}R=hOP{nh&mQSCz! z(-2&RNS>o9jQ`l3OSGt~s#hJrfa776uZhQ9)!`C8jB*vRU70fUe4_BNovKPTz~hKEGh z(Z`hZPmRhtYee)yfrDIj9aA|}`iBdCPlaqN1S&w>yq=HmA)o5^T*PM{Qm;4A{5<-` zFx^@|)|3^>tC+};kJH#@{5DluCAspWn=pu3rorR8S~Gn3R3}6#CH%^V4he=u@lwYM zZHQ)ukx{8q?j+7Z4p6xIH%&i2mLYu`d(F?3Ad(Cklu{uoN=s_VUG8(&u0JKU=ehG+ zEqH=a;Gsx3fnt-tdxBv;fd|En$s~AG5J*5bHzR?x3RCgoeZ6QxBL_Sjq$<2F>oaL5 zv!xn(2r3(=86ktNFr{tKOxKb`Lv{kLyg15!p6^C2cz4`R;6T`&Sf;r^sI6PTWSbvA zr)}0n45Z)X7nPjFHT69V#rgl`AwNsZn$>UhY_WIt-(kzUzHCEz9J|U|eS3AP)Skk6 z1d>>@#OD?`EvuHUGc235A^gkedzo0e3pgX@e*J%j&yT4Gjn!zlM-^jw%6^zEcCj?@ zJ$OH%QosZa3Whn~r%BS_FYx47H5WjB}kMa2{R0o0VW>idDw4N|sn7{#1AZ|O@ zErA}}czs1#y4uH37!?k^Z%}eBz0jev_P36_#ahT_gcQG)4S|A8*1s!1oLk;fGl=c+ zRIysV2>b*06O|Y#-n`4#9~UKqZrBFN_6P!-u96sLY)g6oi+0L?;$>_n9SV<#vRu5b z@~2Q&UC7YP4kIgXh;)pOLqw6v*_-zLC-C?9adGs3H5SQ1PALhun77@%SMTo4M;L;# zd9pLIqX@=8r>dheyyEpf2a9y?X|(hP&M^VHUR{<9`w5659~JKoIIC z5P)nE(>S1!L4wxfC3$5WtnOY*d}MYBXu8(6j80Uq3cnWiC*U0{uR_^hIeP{gk5%vU zx8VP(MzlZ={>CMDc275$fH}3$o9?K0eL=>4iY)4}R^dhVqq7LyfXNS&$yajc{Snk? ztQr-xefG_|gnbeY9jP&e25Ma)afiaYCFEZy^cFK`oi&m_U+);_pChNN50G7XE zDyCJcEbj={D6$6yI}SvrY|{wk697nVsIbG}VvfP3a|sMw11D+_NmL?-d1ix5=v{Q? z_%aUl=nAhRgUu`dm4v74)I<^*V>ACUg{;~4Vk2o4JW$SM_@YH-&PPk-_jq&Cdlypb zpN@s?e`#8uwNRDOB9UYZk~_*e3#fv_`G@!_6xdvQ*I<9-lDU!67@!s1tX%kLvWFLl z?E_ekv2mYIfb1s1%EOT_;66zK{Z>r!v=V&%si3EXh&;$34l!dw)Jkl2F_H?tS+Yt~ zw!SJ9iyocLuTy=V0~>ng4-rLkFTrG?slrOLm=Y^~1KAiRY8_)H{H*CdT58DpCMDRZ z*=fO`R^pd6u5ySer|mcrPxEdU`7P*+iBwga@(qa5N(dc|(Uxyb^}r)g?vNn_V6L=} zHiabtkn87V?y^wgbINiPB&yW&tddc}Rqn(Z%|sKfuiia43Zw`DWILV?SpoQ^SkVw1 zj0{n!yN)Gyn4ut}DuAVIuqC8l;0c3fCEyW_%H?}Z#%c?O^)GiV--!d?fU^gV(a+i3 z221Z|0{c9=9N2d9{t@yW|I_tSr`3z4Ty*80#fQGF8Y0ymI<`y!(3^pC6HpwAVOw0G zO`{aMWD~fG%`jOogOx)ZSWi*|M*xe^!mA^DhTI7|S!HKl{-SDC!0vGdrq&OuR77hw zMV#cWP^(3eJ2A^$=r+~qxC98@DD-~i>O5ERX}i-@A=q_DqE9(|6d-WZ%QN+&9)x;} zmc_i^#4x`x+)!}RL8re`74|Y&fJO+K(FR7}BWsQ)*PfG%7n-$H%} zb`p1M_~npT;tOVhmIsxrqW7nX@CER_tGexu;sFDAFs&4{>P|z0fH(rd(pOXN!-U<3`qie`x6vHtG$kjkiYpMfJ2zc%H+0b$u}(m)S$_B= zpRmPf+vG%qL;(XC=I&d!LV6TPOivM{WLoqbYAZ;{v!21)yOt^5NtqzXS9O?x#@EEY zM(`9+qfXt0ut)P6hk_X8fo9oI)7 zxXEXjlFP}qVEhAw#;i>Y?&MZIxGWcJ57D;p2CweamX-+xM`YL1`#<8JAaHs+rN7e} zF50+lHXX8gP}Cuj5W;+1AHdy50lM`-!}D+Fy&!>s$Zqm@t7AHKT+Q=Jo{lyM?uX%LqOT%1;U+H#|@Xn1JB8b(r(3gZP-Pa();D-S=$ok5@15k&MVG`HS9Xs~pGA%=6}#ucT@M{{ zg1Sf%KcLJ59VuX=o5dv2=vG&NykdeCA37H~v#- zcA#k4EWix#K7*Wxr#shfg=u`_D|iVAPftiXcR+Y0KA)z?T(^p(@4L6vfqws{xY$(T z;baYe1hh;%3NPYHQ1Z1P_@BQ&rcZ7TIB$ZJFTBXXu42{XleX4Z*dPEk07(oHYmBY% z-g;c?BBJjPFOQo=h2IWjLH@#BhVFt!UP$afG6IpC7S74HkPn_}_KnWDm{%jyJkOt1 zfhzQm1vS+mz^&dwVrBlr=A(`aKb~Yi*n1MoE*=vWAJvgey{6k$6I#9#%*LT)v=5c? z;gbB{BPBi>ivxMCvY`R~%=9u1l+f0Bdc*15N<`*YMS66gT`r)O8=+z4LUz|bf>Uie z`LidpA?vm{X)EMh+6a5%QbK~L&emiZ{iAF|NrVoAf_H_9z8|`RKGewhXs&<&TR8@2 zWtarQ0`K9lRWE>Ymc3F~Npro&{O8MU$YBKXOSouUkk`;OpNfR_qK9yVrHMXaKa>99 zW-`frak8U#qe`9|(eX1GyGbHvhAJtv3R~haKLx7QfRmWWi#2zW@9*ji8&8AEU_z)H52+VCa19%vsV8lmxOEZxa;O3qwc(|!281UZ&#qM4Gw zr1}+*obq@ur>$2M2o#gcDb}UsR!E>;=if(?gXYh96K@W3j!F#MonKM~G!zL^Ui9m) z<>ktineE05va0rPx*nKt2@H9QW#aoHHxLobMt}$QHyG1q_xfTiZr-H$ym+)NaWLR8 zS$E@@)W=G$4u2guZBkpaYYhSCiCRkp9>#9Ufx|luT?Fp+$G*X_8?odzE#&iL+bb7j z=5UC*b3?phQM=Gw%HUQh_^N_wvDQd*ui%oFY$Y$$90`b5hm4`Zz1O z3qgjWvjEFn<*elIT#(5>zWM#-H$QV^*dp6q4YIBXM#oP*^+e(K(;2`m7?)0}0it+1SSdzuP zB9JIujSA(ZH%Yp((P zJJ}U2ydzPE<2p6{&}JLp0s>Pll^3>A#WBls5md{Qm0GEPW@xm^8uzco9%? zi(m{jLzQ{kUjsBFOxRtN+lPOmNaK8pj5m|2z>Aga3RjG*q3eMKuTUQgo zOV_cez5^)5Oy%M(^f--RV95GpeF#V^)X}VpA7Id#*36O(CH!z`@F@~E|+1n&v!X1Dz2AF1YElY+sxKQ9Qj9=>;;&*TwC#N(s! zDtSNEhenVY3wC1W7v9K5DZ(G+t%|AN)n({$8X})%1b(N`jCVCF{?1#HaD29}wu5Ry_4$ zjhP``@6$AMA!WA@Hv5lK4Qh^|tnCA?6zJ?WvkTU&nh86E zgON+eqy51)DiZu@04mLMm*jUaq`SkyVA8%UMLDC%6@skfK!CCATXSquCSXevIaJG4 zky9`PIS=LfwJz3R;c#(D4t(;aaU;$tcgK*lJNOW4uR4z~4 zVYWzW6^jpFg&tnj znC-U$vp>>rTN{Gz;G2IY3l7^I>44>_mt!R&tgDkarw?T&cCOKeknayDX3tIh!{<&j zla2GsYuJRx;sS7vRKvL!o4AUCA$=C7d2)Z$f4}Jd5=G0Ul-bq1C1xwiRc~J98e3`3 zE?V#Stc4ttHJ3As#%hZ3O_j}amfhFrZv~{t7YfRq0it)k)6LP z|dnWZIEGEDkQ+qWefDwd9MP3y{C zt=ceERIoUL$G{1;PU23zqdbky&wGT6OQ4(<7@Zh43-53*Tb?9 zD0b1ylb?gX{-`qIV3x1dQU5mfhuSTDA**MAxkljvIy12%i#?2-H0$nrjvKMPtLZ@` zRL4Sl2`7>^F1_)x?Z+lKnq|q1sz)Il#IHW}cfW%_!RN6t!5pK|#qPzmdC;s3&6k_% zIgi_nDj#s(T=1Suf1*1hpqWw3Z?H_cKFlRilUD8X7au(E`ap|6z(BYvE;LpoZZu|shBz1CF&y+Xpmo(+HG zC@LAHlPNnzZq_V?M*GHs(=`dY_6Dh71(N?8!01|v#scyMH7_lE2tMtg=@gbY0N=uhn7kvHc+wK}r! z0{)U!1&TrL4ic?OaddcMP%Q~UP^s%EhWU%h%~keMK!5Y0HzeQ&;4Zs6qZ}vEJuLc+ zDR8Uon2-d-EZ)!UPLg(D9LqCC_mxx$59j!hQgNi^H?*N_>UAyE6i04G?`%eWo12V; zfl=lHQsuedjJ+zS86a$bMC-sW$P@{H6%~W&-)Mn)R2t{cO%d+_+ubJZ?yvseAEJto1sU3$W<8C`qe1zr_c895M32ujvhJ0bK(rO{HJ_ zppC4;oIaU^Y(VSl+O>AE)$M!pbTRiY*|6Jinh2B@w;1rlE*#81?T&K$@I=XGLZ`zw z_04}{$3HtiFq08+Qmwk=ZhhFM@{B~3prgWb2*v~Vb<1PsQXvOLPy=$0&N08;zxx;q zA~8lk#=h<-^T|;Dj1=7rBiZ{k15{NKsq_irFKX+jwcpZw{~iisFKbkEj`#5opU}lc z4rP2a+W;ZTr*ikMxhSN{C?}_p{xw2=Qh4udw;vtpYpYJ;RX|Atn*!62mloYHI_Jol ze~*e(6ejc%H+cpapnOHTV}ue*yQ4nXbB_l5+uJlC)sh3($th$J^y&e{k>hV#;*%xP9u9 zPScq2q^!Ql`5zLkQyS>`FTap1yc!91y!KqSCyKY$QcRWP4h(`Q2Dn;e0q1qc~Ai&T+K1x!}$h37>P?NcSqC5l5fNHxmY=wb~}^PqYh7Xmfaw-yn$8r3Lx7ge>!~yy zzeTe%J?Uyablr@Ul_=j~%)V1Eqt|hM{73xraF5X3X z>e?nK`cd;!3Way11P7&w&1;9?oXa_tD(;h}mcJ3#WFO-Dp9_+em2j1CAAAYSmEj^ou=P!;M8S;Y?JS${vlqaq!Ah~=Wl zI!*An{>hq$bG7V03NxC{0aQoaxQ$~0 z9xNoH;k#HDfM356MOkwS!s1Z-im6r^KAVhikcD#GF-uI*AvI2qU}qJ6&o6`1e?jY| zTn2&NE&l*W*^}E=ibigu+~3On0Ov}cvi(F11Lj}9GI=poj@6xN>|u?0+)KOv~{jE*jQneotV zJ~ysO`j)yGU+|#-55<9ihTVWnl~B;9a8Ck;&+SHJ6+0-FaM0@Bcsknf4SDEkY5pj4WkOmKLKd zqqN$REJ=1X$`Ykgr(<4rvdbE>OJyxZQHVk*31L!*EM;ka&oh&Fy}$3z_xAn%e*gUb zc(}baGv{3Ax}MklTF;r@UUijsN}u0bohf^fv-A0r#i`|YMW4Rh2>t%*$OD7U);|XR zFjc$uR^YjG^j5tCYs}^pthui_v`yHi>!XXNs?W;n&c^MJ^ox(^W8eIZ?V7!pS1;@n z?t8fEaecO9kIsvz*J(S;L6#KK ztMi(=g_e6p_Bv%#>)&Ug&#!GgO>~E@*>S`)uA=@}YSr4^2PU22*B7g*SDk&pvm3Qx z?|~wt1p5VBetD`h8%LDK8*f^pH__9&{hsAvF7*Q@eDXVS)bh1|FOA+C#!bHQ%Pl2N zf6Rqb&wOr6S6w@o^YYB>UK!USj=V@IpOYKk`cR#oQRaZHL1FynL-HqAjQX7Sc2ucN zoqKe}ww$58-J5sn#*Q~y-fsU!2aBiyc zly1C$Hk-%i=EpMYcK0qdTWV5!<*dA)m2c{ghl#mC8guS_-r9<7JG4{lpBr;GIGs=x z={|baU8hGW)*2~?z2c; zvP4$uGt7CUFrju^gmbaJSG&bQN&BRqt`*-&Q2W|iXxpOegfx$LT?^F7pZ zH?zihldhRs6?Ibaoa}JNs&DqDb1GIflPotIE@%-Rx$)Gk&i8aK`%f|4_9Z!Z(8uhD z^X6{fYCi7V+~})$(x=I@M(xNwJLShw*U}-6>@Cx}cXM)dZhl4b{dluysh0<8#(sXO zZN9WTE-w2~yIqy97O%Q>^UA6vEi+_WT!Sp%nYy<-yX)acm%?{TJKE2Bd(&5|_;K92 z)`3G_#k4n`#7yXt)4l(IBklvucZM%=-dbR}->zotYX4)>-S4-ugC@kSPjx7)+S7E@ z`qtYoIzE0qznsT^<N_BU@0U6+(y@2UV2!ZP z*~@GCw_azu`c@O83;SO$?=o?Vr!YvZRoiFVy6+pgBWsJxzTx#N8Sk+HKMKv9_xzL6 zU2q`$l--1-;p;ne%#1Xgcp+E+@vE&~Nq1_U#vC~7C0#s7oI8Di&(6^0j}z0g2KxHW zI66?WWJ0@`A78|sHomyOR=>sLilcdz6MvKkpFENjbow7J75Zl$2d|iK`L%A&{9#)y z<~Li^;##kLx01G*o@-|9+uNqA=H>+>BByR@oAuoCn(@n_dwrbc7Ns2?O-y=sT-Gb@ zzF0Xy^aMZgo>r%qSc_)r1`Uh;edACEvfM+`wGe>gVJ*HRrjoIFR;LdB3K9R1c z^V{q>I{%c(zM2Qj%owqXZ}pBrJ)8AOU-0Q4C$m!q?Wdm+P1Vk*xG0vz?7hCa@AMtT z&SvVKKj%%&IW(zeP_*{)?oylWch;_2Kh9vfb#@;gpZT|%zb{_P@7&vBP~|@vL(G?y zG^>xPv6_8is`pNsN22E|1p@c(c2=|HF7TW83P0suLTd z?>!v&_C!M6x_gCwTU9g->KrahziQ}|9z1M)Z+5xgNxt?&FaHT2)<@>K?CCS>O0wRd z3!Ojq(eW>g3pw_A`nb=dZ+2$4uU2bm)br%lin{_<@^bNX_t8EfL){0QdnvdxF#B=a zi+2J)UT$S@&@sEK`(3|2PJNwjADZHOZdtqdf6|>>G%*+$dv0G^n^mP71M5x?`u^cq zz5SyeyF>gx?x=U*RkZA1v{y7&T%Ymvvt8n?D5m!_-3P~f zBaWJnn8mjDbZ95gD?Ke7@Y+{kai*wgvj@G~Ta5m!_cLBI{Cb=9OH^-`HdA@(@m0>7 z{O-ew7yA7*`}cVJ_JgcSW7eKN9$|q&w|#QI&th|W+)7-1??>*eO1CvhA06&TsbpV@ z@8@!IUa0wj?(R>+n+Uuu2B%Gyg|65zO?Q3YmK&y=tLT!eX1VsliStvg3G;KSCyxCQ zd&q6o_=AJr-uSwAchmJPUbbF6EmGxWuIVl(=K&>oUwpgVN;-6>S+rgAuCKe^$tsxq zaE^xd_Sts=Er06F?&PR;X0vxvamUApa(wKI%s(I7{YZQ5o2vTU4Y5bNy;gm8>f|N4 z@3Q2=iGy#%CSEoa`@hYMp5e_1>~?8BHh*^Ln#z=W3q6_Q2&;OSL{!`)BH*YO%KAL6Q#lN0j zbR~P(xz0!8b)}`x*l4qu!~1i`OeuA?VvKt>H`V+$sz5JoYo`M@Z)JbcFPuGR_^lOL zGe$b}u35KUw|mPr#j?0x7QYgn3=4MZncaEd=9d>gKYh^m7=B68<*Oo$&lqPgI_nX>+|#!Z@kxzU+VqtJ~}k)YRnq-^f7HO7m9XTJU?ajywCoq zr^~(gg>#olw>f`aGw-H~yiL>Ny;sIKKe|*{xu}!Z&b76drLAtw&YqXL@wKB@|EhvJ zo?|Nls|)L9Gt>Lbshi{U%OSg8`TEOj*8Vl`_Ff!$r0`{NY_swS^KYG>+vda3b{kZC zg-)q9@YHys^7LiGlcL(IQ{;LzuZkl+eCpJ5QqA7YwI8y)#&p8uPIlTN+vw)^x^)|xVB==$;ONNAAM@^`D68<2eVfd&wIVD4}Zd2-wxhdk-8oit_+-% z(yZT%nvSNI)T*xN4eD+j=)3p%tJ--s+lqF#%NUZE_`0m9OUu^g_sfkxpMCK~@TIoZ zotkG?%~n5Ow$niC;dpK1QT*crr0R9iANF=K>o)%C4EpcB&%Ld;z92bwey8NqS_y`! zBW;dFYYaG4v+I>@6Z0g)!ae4edT%dm-t%Skd!Acx$czg^%F5>U$xHHC*UEnH>j&cN z-=uxZQi;hFI~Rgn84c#`f(}1KajrU#~s7>cp-! zSN%Uv^YOCNH$Jg=W3Q~N>Wh8)oSl6wXZITq}X^;_26e9%AOZEER@DJ?=b`_Edi%kq-%wYerzkKW_`*7wh^I&)#o{>SpO+L zv90u+yJOU8o`>tDHfNZkF2c&BZbyr6-xCisuS~7)tbKFH+y(7>G3%E0C^hR+lKgq< z!%_3s%~|_gds2?}ve}Zm?KM|Cv#PArwkbJm>~s9g!S4(2B@B{19sb7QQuYbA^=7fD zIz8?QXYlNp86yh=FWRSGS=axmaKx>uv?en<4z;$MIpOM!)3YC5G~cvqTf6KEp9OcB zw(%Q<9b?1VN2;`3Vp4G?YqVX!gtiNx{7PPxZnl|!f2|;-y{6HUWnK062?orMy0HBA z6yd%-QTuA_yu~M)Jqxedqp{CaGNkj`{)ajZj_NYGxo76a6Dj?)Yzo`2NKGv~8z9eU zyWmRZ39sB*ftlpZx&pQF{VNY^O{uF7UE0gpvi`e6+xb=@sMUf^S9TZ0-Y5=t zp6gBj_Nckb^e#D}SugvQ51SYwc8ni6++8={GUuC1-xcCvGuG7vT1Xal+PtrA%`wZj zEnTd(Zz;aL6K>=lntMD z>b%F8=j{`|Zn|g}z}InUZc&{gnCbZ@=Ti%L8dDYmI_Q{Ng+BR`EPEjS3Eye)`yU>ih@GwAxm7V!s}3y5+>!*2^r6Ts)U=&NJne zI;AezJN@12Q3qz)PhDQ)Hd)Ydiq^xkFJsmYblqCJ=E$QJgPvTg95`Jo?Ty31H|j?! z117T0b3>+@CW#B4w2rI$*=O6TE4P--JN3P-^kcyBJ)4KVU9R!z;Vwt}qNRQ(jq4?= z`rUk_KXY=Ap7+%@j~Ha(QgF%o@Q^QNFFS43d-le+GGP`J}9xt(pUsTjn z-*fbkE0gP(nYK%}$5j0sD=d05>G0cb=XPFL9erb%`oOVP+dT>wu^R3@Ppvy z%4}4!*!<4+g143n)d#^_KR*EZg| zJh@HpHg1y#$E2Ry*<2jr?(XyB(lcS~mNN-*Q}2fZC6~XwEMW7g;Phm^}T(k5M))=Y0HRJ-ByLZmwkPd2N}W&&PpweLfE= zyxivQAunUSH>quG`Ra3?jBcj3Roi#Ny?=@Oj7X*t=s!o`W;#NaQ_yA8|%$Ae7|p~cf6>X^2XM3sl}ntCAvOym3gNh4d1DKxFJTWvf2wA-55!y`>T|NP#=wqNtT(~iFw zu5oSFo4C_WckCY#^rQHny@IasIxC+_UM%l-{hGF5;_g=c&HHTbe&w~^h5IYK*h#0a zts19(wQ`HBnacCqUiU?IyN*v>?tS6fJHAJZ*9FJs$FfH~9wxHxexGk(&6!zo*a4U5*u?tZdwzX=;vR~=ZIo0+BB zdH&p<`v)%jI&tdB;qTma^nFzxTkg8^Ae+V7?4!R*ec#ico=HNFi6h&0PwXmp*`HOrA=Xko@U_O3ql>k8y*s{1TU72@ zTXAq$&mNLNvPWqfYZa$nAM$>B2VMVSy?Ke>C*%G9 z?7Hjv(!NdjFn>$CZ{ZVWztdjvHn7HEt@?)ZGhz-|lqKHW{LfHFcH)uJ=tMt$j~BN$ zUS%}O$6mj5Q$wxB#`=uuq<+l~-(^0|Io|Yyo!x{3u5IeF4S$U8QW58w*+yi#T`f_% zd&PdekvExXXDzkv3_ShOIX-X6gyXM+_;^ zO&c}V-@@YMM*q{Dg%OA6ovrEBdFHzlmuqv3u5Y>XdaLP0?SI^7-t7C~mDl{``>l#= z^sfn5blTRzqFyqy)8J=Sj?M?iu5(P*FH7`TqZ`;<*3R$U`$ctC`rQ)FWw>=1u~2&L z-Ja;gW*rVhjeh8TXxoI?+Pm*F1AkhTZ2cq**wLxez5P~eJm2+Ld#l5#O=s!fJ-VYB zyRdpyRAjeSq4nR@Iu*IK>|LA|*2>4NtBa3wFARlC`C7cXZgX?WM`R)+5y&a3#GTds4X z_7&C0>7pec$Y>OGmv~_vuclW6g(Nw?)g>Y_u&++0tvG%gpzaFE94Y zYi5{d9k-Wvf!FKya_5wOE$6;)3ksa56?SuK{MCLz{`v!=&K)*<^k{IYUF=DN*)4{R zAC|LX_@_0+>#o?{Z{Mrm)?M-^Tbw_r70tiZ*M@nSbT+ki{*IHsP852LoZwZXw<)Fe zo#B-A6?=y6aY~fWoA&zCsG7h+pTuQ57xkO1)i>4bX61@AY>NlUI+|UbyG{M&GvIZ1 zw>C{Zt`B?a-FD@*lWpd=+H+Vf?`6Ht>a$DVnx_C1-GVy z@Aq7v9AjoO_v$mxux$@_AKBqD#Pmc><>*b5W~m6@M*W)YStJiz*r6aZR`B$kyw|B= ziMltBo-BH1uH{=eB{ce(Y@e}6A{sjHqmjPv$x8+6o%(M%@%@R%qEls;4*tp)@%IhT z+cV(n(Fzx5HNWrOTJAiRTI-m!c*{AxWRHyF#W`c*GO`MM+u3@J8*BSzL2iCnMeRY= zXiXFIu%oJaCo~UryQlK;q^sSbH=7^6TD^7wxw-?^>5K zro+8Yk@wtQ`wpm?lfJ^L^^BS!;{#S5T2u6^yV?xR*T)l_-`*SY;!8l2jFsBEQ>TrZ zAJpA)p;eZ8<%@^)Ml(Nb@QIf6-F~26*ghq4=+YtPvuiTK+WFL!)~?hDF zmMbb=JW6kB|IebhAD(WfdNs{zRef;m(+{_=n8Z6yYtm_DWXx{a%-&-XUyfPu^Tv3- z{95&tlK300kDPl*Pxfkg=)#ZF@tIFb9^YN`_4;=6YiS!j)uU_r9^0aqYoFu(>d}}X z*VQxHbjCLkyi%kznQgjV-*az#K*UX!r*C}kuwv4Nz=LFKf z8D=)BTf}>|+jhm^P-sZsE#y^G?4v+}AVM zP@=l6$?@2T=pB0&KFP=s4*BTk@cQ*gudgSi8zaZAIo!XxXS?36Y0j0gEqBIleZ%waCvrWs zV{q$Yy9N2r3ufOidov*|>Q{Y#^IqRFhiSH!(e|NjSnBU6&=f1f9 zi}p>L-s$7UGtZw|zAEurliI&zeNbqqgXe)BKAP^# zKJ73z>#nvsCewH9mv*ZLu2sA7tNE!9UUuagtJ`U+KUt8iT9X^~ZQ>;_{)qLR#`f=f z%D2;^^Y_|)X1q6yS>E!}jyKQwr&XO?F05*so0*b7|NV#fp;In7`c}5moo733U;2`Y z$kLDdn-ukYwAOI{sr?h}-^Ewu&Y!W@qigf;+FuSm>8vF=KjOfIlaFg>?KH4huc^&T z6ns+aGRdHSnDc^E=6c^zZzKIq$|gkinOA>!f&Pe?{F?@6?k^oFeY+-ZTzUS3{d0=~ zvexc@^ms-SpJ_+GeQ4oqHS~^UT*&II9*+h&{hD6fD`9fRbFcdaFXf@mrlZ%LNDIoH z?APC**~-~158m6*_tn#Hy_R)9J!9RoFJ{`Og$3D_Jzuk@DDnTr)UZNFIulzN&6ro0>8EaP+TkyrD~41PLYzwF&- zY>SBre$58$e*FDGqDIuPkaq1l=!jEC2L7;2_Ns5DwKU+vhIV(|THl={+H*tK_u>Vw zf4=!=6v=wG_RtrsZu@Heo0%_oExbQ`c;EBG7`5uWxjokGceE`(?wg*oZ>6boay9+u zuwUdPyi4KlUOL8mTgd2ZWhcWXZ8;Sc`$&J+mpxr4YP|AXQElLLG~iA5H6L7m6<_GH zt^U2|oNIQHCa&A8V~3o(HF=(Dz~QDw17CNJ(AHg%J&*psNFifq)j!{vn-Y2Rs<0?` z56|b(mRsvh9mK!p`3-P#V)nMP+i@?YXu}v$(<}SNd>h>Jk?8#O#z?HRu3#e?z@U)`%?B;75Gue-Q!=&(&g)#uhi8-ujo1L6)D@(;-lXm_hR zCZE_jaj~w^#v@m)*O@8f)4fdB*`009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< 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 z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^qj1n!>to!fU0KVt7~&VML8`j^vh{jMoJY?8)iO46;8@i}9XZnX?9 zl`T8G7PINRuQ-}o?z8m{s(FFIX}+cN z#||{i`DjQ{f7Q2YcF%jzRGR*p`V-SBHO2RCch`-n{;AP9y@UR#p;x1?TLwd~^nT<| zQ9p~k5A7giTVOD&=+(}K?yl5K^>%#UsOI%$_54D}L1N{B!Bk)I{69uV0)uJIJ%!cx z`T>i7c=3n{oFjG2NK2?(BKfBm`GF>`!{?Oo|i-*F8 z&PK}y=1AW`fPtis5Gg)TQIh`pE&cqrZ%Hq&bVf5?u5d=DG>6VaQ=)%}_C-2Ai^U=@ d;wyA9_J0i-(GmSZ$k +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +FILE_OPEN_FAILURE = 1 +FILE_WRITE_FAILURE = 2 +FILE_PARSE_FAILURE = 3 +FILE_READ_FAILURE = 4 +FILE_CREATE_FAILURE = 5 +FILE_CHECKSUM_FAILURE = 6 +FILE_COMPRESS_FAILURE = 7 +FILE_DECOMPRESS_FAILURE = 8 +FILE_MOVE_FAILURE = 9 +FILE_DELETE_FAILURE = 10 +FILE_COPY_FAILURE = 11 +FILE_POSITIONING_FAILURE = 12 +FILE_ALREADY_EXIST = 13 +FILE_NOT_FOUND = 14 +FILE_TYPE_MISMATCH = 15 +FILE_CASE_MISMATCH = 16 +FILE_DUPLICATED = 17 +FILE_UNKNOWN_ERROR = 0x0FFF + +OPTION_UNKNOWN = 0x1000 +OPTION_MISSING = 0x1001 +OPTION_CONFLICT = 0x1002 +OPTION_VALUE_INVALID = 0x1003 +OPTION_DEPRECATED = 0x1004 +OPTION_NOT_SUPPORTED = 0x1005 +OPTION_UNKNOWN_ERROR = 0x1FFF + +PARAMETER_INVALID = 0x2000 +PARAMETER_MISSING = 0x2001 +PARAMETER_UNKNOWN_ERROR =0x2FFF + +FORMAT_INVALID = 0x3000 +FORMAT_NOT_SUPPORTED = 0x3001 +FORMAT_UNKNOWN = 0x3002 +FORMAT_UNKNOWN_ERROR = 0x3FFF + +RESOURCE_NOT_AVAILABLE = 0x4000 +RESOURCE_ALLOCATE_FAILURE = 0x4001 +RESOURCE_FULL = 0x4002 +RESOURCE_OVERFLOW = 0x4003 +RESOURCE_UNDERRUN = 0x4004 +RESOURCE_UNKNOWN_ERROR = 0x4FFF + +ATTRIBUTE_NOT_AVAILABLE = 0x5000 +ATTRIBUTE_GET_FAILURE = 0x5001 +ATTRIBUTE_SET_FAILURE = 0x5002 +ATTRIBUTE_UPDATE_FAILURE = 0x5003 +ATTRIBUTE_ACCESS_DENIED = 0x5004 +ATTRIBUTE_UNKNOWN_ERROR = 0x5FFF + +IO_NOT_READY = 0x6000 +IO_BUSY = 0x6001 +IO_TIMEOUT = 0x6002 +IO_UNKNOWN_ERROR = 0x6FFF + +COMMAND_FAILURE = 0x7000 + +PERMISSION_FAILURE = 0x8000 + +CODE_ERROR = 0xC0DE + +AUTOGEN_ERROR = 0xF000 +PARSER_ERROR = 0xF001 +BUILD_ERROR = 0xF002 +GENFDS_ERROR = 0xF003 +ECC_ERROR = 0xF004 +EOT_ERROR = 0xF005 +PREBUILD_ERROR = 0xF007 +POSTBUILD_ERROR = 0xF008 +DDC_ERROR = 0xF009 +WARNING_AS_ERROR = 0xF006 +MIGRATION_ERROR = 0xF010 +PCD_VALIDATION_INFO_ERROR = 0xF011 +PCD_VARIABLE_ATTRIBUTES_ERROR = 0xF012 +PCD_VARIABLE_INFO_ERROR = 0xF016 +PCD_VARIABLE_ATTRIBUTES_CONFLICT_ERROR = 0xF013 +PCD_STRUCTURE_PCD_INVALID_FIELD_ERROR = 0xF014 +PCD_STRUCTURE_PCD_ERROR = 0xF015 +ERROR_STATEMENT = 0xFFFD +ABORT_ERROR = 0xFFFE +UNKNOWN_ERROR = 0xFFFF + +## Error message of each error code +gErrorMessage = { + FILE_NOT_FOUND : "File/directory not found in workspace", + FILE_OPEN_FAILURE : "File open failure", + FILE_WRITE_FAILURE : "File write failure", + FILE_PARSE_FAILURE : "File parse failure", + FILE_READ_FAILURE : "File read failure", + FILE_CREATE_FAILURE : "File create failure", + FILE_CHECKSUM_FAILURE : "Invalid checksum of file", + FILE_COMPRESS_FAILURE : "File compress failure", + FILE_DECOMPRESS_FAILURE : "File decompress failure", + FILE_MOVE_FAILURE : "File move failure", + FILE_DELETE_FAILURE : "File delete failure", + FILE_COPY_FAILURE : "File copy failure", + FILE_POSITIONING_FAILURE: "Failed to seeking position", + FILE_ALREADY_EXIST : "File or directory already exists", + FILE_TYPE_MISMATCH : "Incorrect file type", + FILE_CASE_MISMATCH : "File name case mismatch", + FILE_DUPLICATED : "Duplicated file found", + FILE_UNKNOWN_ERROR : "Unknown error encountered on file", + + OPTION_UNKNOWN : "Unknown option", + OPTION_MISSING : "Missing option", + OPTION_CONFLICT : "Conflict options", + OPTION_VALUE_INVALID : "Invalid value of option", + OPTION_DEPRECATED : "Deprecated option", + OPTION_NOT_SUPPORTED : "Unsupported option", + OPTION_UNKNOWN_ERROR : "Unknown error when processing options", + + PARAMETER_INVALID : "Invalid parameter", + PARAMETER_MISSING : "Missing parameter", + PARAMETER_UNKNOWN_ERROR : "Unknown error in parameters", + + FORMAT_INVALID : "Invalid syntax/format", + FORMAT_NOT_SUPPORTED : "Not supported syntax/format", + FORMAT_UNKNOWN : "Unknown format", + FORMAT_UNKNOWN_ERROR : "Unknown error in syntax/format ", + + RESOURCE_NOT_AVAILABLE : "Not available", + RESOURCE_ALLOCATE_FAILURE : "Allocate failure", + RESOURCE_FULL : "Full", + RESOURCE_OVERFLOW : "Overflow", + RESOURCE_UNDERRUN : "Underrun", + RESOURCE_UNKNOWN_ERROR : "Unknown error", + + ATTRIBUTE_NOT_AVAILABLE : "Not available", + ATTRIBUTE_GET_FAILURE : "Failed to retrieve", + ATTRIBUTE_SET_FAILURE : "Failed to set", + ATTRIBUTE_UPDATE_FAILURE: "Failed to update", + ATTRIBUTE_ACCESS_DENIED : "Access denied", + ATTRIBUTE_UNKNOWN_ERROR : "Unknown error when accessing", + + COMMAND_FAILURE : "Failed to execute command", + + IO_NOT_READY : "Not ready", + IO_BUSY : "Busy", + IO_TIMEOUT : "Timeout", + IO_UNKNOWN_ERROR : "Unknown error in IO operation", + + ERROR_STATEMENT : "!error statement", + UNKNOWN_ERROR : "Unknown error", +} + +## Exception indicating a fatal error +class FatalError(Exception): + pass + +if __name__ == "__main__": + pass diff --git a/tools/python/Common/BuildVersion.py b/tools/python/Common/BuildVersion.py new file mode 100755 index 0000000..088609f --- /dev/null +++ b/tools/python/Common/BuildVersion.py @@ -0,0 +1,10 @@ +## @file +# +# This file is for build version number auto generation +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +gBUILD_VERSION = "Developer Build based on Revision: Unknown" diff --git a/tools/python/Common/DataType.py b/tools/python/Common/DataType.py new file mode 100755 index 0000000..5d49afb --- /dev/null +++ b/tools/python/Common/DataType.py @@ -0,0 +1,535 @@ +## @file +# This file is used to define common static strings used by INF/DEC/DSC files +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent + +## +# Common Definitions +# +TAB_SPLIT = '.' +TAB_COMMENT_EDK_START = '/*' +TAB_COMMENT_EDK_END = '*/' +TAB_COMMENT_EDK_SPLIT = '//' +TAB_COMMENT_SPLIT = '#' +TAB_SPECIAL_COMMENT = '##' +TAB_EQUAL_SPLIT = '=' +TAB_VALUE_SPLIT = '|' +TAB_COMMA_SPLIT = ',' +TAB_SPACE_SPLIT = ' ' +TAB_SEMI_COLON_SPLIT = ';' +TAB_SECTION_START = '[' +TAB_SECTION_END = ']' +TAB_OPTION_START = '<' +TAB_OPTION_END = '>' +TAB_SLASH = '\\' +TAB_BACK_SLASH = '/' +TAB_STAR = '*' +TAB_LINE_BREAK = '\n' +TAB_PRINTCHAR_VT = '\x0b' +TAB_PRINTCHAR_BS = '\b' +TAB_PRINTCHAR_NUL = '\0' +TAB_UINT8 = 'UINT8' +TAB_UINT16 = 'UINT16' +TAB_UINT32 = 'UINT32' +TAB_UINT64 = 'UINT64' +TAB_VOID = 'VOID*' +TAB_GUID = 'GUID' + +TAB_PCD_CLEAN_NUMERIC_TYPES = {TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64} +TAB_PCD_NUMERIC_TYPES = {TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, 'BOOLEAN'} +TAB_PCD_NUMERIC_TYPES_VOID = {TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, 'BOOLEAN', TAB_VOID} + +TAB_WORKSPACE = '$(WORKSPACE)' +TAB_FV_DIRECTORY = 'FV' + +TAB_ARCH_NULL = '' +TAB_ARCH_COMMON = 'COMMON' +TAB_ARCH_IA32 = 'IA32' +TAB_ARCH_X64 = 'X64' +TAB_ARCH_ARM = 'ARM' +TAB_ARCH_EBC = 'EBC' +TAB_ARCH_AARCH64 = 'AARCH64' + +ARCH_SET_FULL = {TAB_ARCH_IA32, TAB_ARCH_X64, TAB_ARCH_ARM, TAB_ARCH_EBC, TAB_ARCH_AARCH64, TAB_ARCH_COMMON} + +SUP_MODULE_BASE = 'BASE' +SUP_MODULE_SEC = 'SEC' +SUP_MODULE_PEI_CORE = 'PEI_CORE' +SUP_MODULE_PEIM = 'PEIM' +SUP_MODULE_DXE_CORE = 'DXE_CORE' +SUP_MODULE_DXE_DRIVER = 'DXE_DRIVER' +SUP_MODULE_DXE_RUNTIME_DRIVER = 'DXE_RUNTIME_DRIVER' +SUP_MODULE_DXE_SAL_DRIVER = 'DXE_SAL_DRIVER' +SUP_MODULE_DXE_SMM_DRIVER = 'DXE_SMM_DRIVER' +SUP_MODULE_UEFI_DRIVER = 'UEFI_DRIVER' +SUP_MODULE_UEFI_APPLICATION = 'UEFI_APPLICATION' +SUP_MODULE_USER_DEFINED = 'USER_DEFINED' +SUP_MODULE_HOST_APPLICATION = 'HOST_APPLICATION' +SUP_MODULE_SMM_CORE = 'SMM_CORE' +SUP_MODULE_MM_STANDALONE = 'MM_STANDALONE' +SUP_MODULE_MM_CORE_STANDALONE = 'MM_CORE_STANDALONE' + +SUP_MODULE_LIST = [SUP_MODULE_BASE, SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, SUP_MODULE_DXE_CORE, SUP_MODULE_DXE_DRIVER, \ + SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_UEFI_DRIVER, \ + SUP_MODULE_UEFI_APPLICATION, SUP_MODULE_USER_DEFINED, SUP_MODULE_HOST_APPLICATION, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE] +SUP_MODULE_LIST_STRING = TAB_VALUE_SPLIT.join(SUP_MODULE_LIST) +SUP_MODULE_SET_PEI = {SUP_MODULE_PEIM, SUP_MODULE_PEI_CORE} + +EDK_COMPONENT_TYPE_LIBRARY = 'LIBRARY' +EDK_COMPONENT_TYPE_SECURITY_CORE = 'SECURITY_CORE' +EDK_COMPONENT_TYPE_PEI_CORE = SUP_MODULE_PEI_CORE +EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER = 'COMBINED_PEIM_DRIVER' +EDK_COMPONENT_TYPE_PIC_PEIM = 'PIC_PEIM' +EDK_COMPONENT_TYPE_RELOCATABLE_PEIM = 'RELOCATABLE_PEIM' +EDK_COMPONENT_TYPE_BS_DRIVER = 'BS_DRIVER' +EDK_COMPONENT_TYPE_RT_DRIVER = 'RT_DRIVER' +EDK_COMPONENT_TYPE_SAL_RT_DRIVER = 'SAL_RT_DRIVER' +EDK_COMPONENT_TYPE_APPLICATION = 'APPLICATION' +EDK_NAME = 'EDK' +EDKII_NAME = 'EDKII' +MSG_EDKII_MAIL_ADDR = 'devel@edk2.groups.io' + +COMPONENT_TO_MODULE_MAP_DICT = { + EDK_COMPONENT_TYPE_LIBRARY : SUP_MODULE_BASE, + EDK_COMPONENT_TYPE_SECURITY_CORE : SUP_MODULE_SEC, + EDK_COMPONENT_TYPE_PEI_CORE : SUP_MODULE_PEI_CORE, + EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER : SUP_MODULE_PEIM, + EDK_COMPONENT_TYPE_PIC_PEIM : SUP_MODULE_PEIM, + EDK_COMPONENT_TYPE_RELOCATABLE_PEIM : SUP_MODULE_PEIM, + "PE32_PEIM" : SUP_MODULE_PEIM, + EDK_COMPONENT_TYPE_BS_DRIVER : SUP_MODULE_DXE_DRIVER, + EDK_COMPONENT_TYPE_RT_DRIVER : SUP_MODULE_DXE_RUNTIME_DRIVER, + EDK_COMPONENT_TYPE_SAL_RT_DRIVER : SUP_MODULE_DXE_SAL_DRIVER, + EDK_COMPONENT_TYPE_APPLICATION : SUP_MODULE_UEFI_APPLICATION, + "LOGO" : SUP_MODULE_BASE, +} + +BINARY_FILE_TYPE_FW = 'FW' +BINARY_FILE_TYPE_GUID = 'GUID' +BINARY_FILE_TYPE_PREEFORM = 'PREEFORM' +BINARY_FILE_TYPE_UEFI_APP = 'UEFI_APP' +BINARY_FILE_TYPE_UNI_UI = 'UNI_UI' +BINARY_FILE_TYPE_UNI_VER = 'UNI_VER' +BINARY_FILE_TYPE_LIB = 'LIB' +BINARY_FILE_TYPE_PE32 = 'PE32' +BINARY_FILE_TYPE_PIC = 'PIC' +BINARY_FILE_TYPE_PEI_DEPEX = 'PEI_DEPEX' +BINARY_FILE_TYPE_DXE_DEPEX = 'DXE_DEPEX' +BINARY_FILE_TYPE_SMM_DEPEX = 'SMM_DEPEX' +BINARY_FILE_TYPE_TE = 'TE' +BINARY_FILE_TYPE_VER = 'VER' +BINARY_FILE_TYPE_UI = 'UI' +BINARY_FILE_TYPE_BIN = 'BIN' +BINARY_FILE_TYPE_FV = 'FV' +BINARY_FILE_TYPE_RAW = 'RAW_BINARY' + +PLATFORM_COMPONENT_TYPE_LIBRARY_CLASS = 'LIBRARY_CLASS' +PLATFORM_COMPONENT_TYPE_MODULE = 'MODULE' + +TAB_SOURCES = 'Sources' +TAB_SOURCES_COMMON = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_SOURCES_IA32 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_SOURCES_X64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_X64 +TAB_SOURCES_ARM = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_ARM +TAB_SOURCES_EBC = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_EBC +TAB_SOURCES_AARCH64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_BINARIES = 'Binaries' +TAB_BINARIES_COMMON = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_BINARIES_IA32 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_BINARIES_X64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_X64 +TAB_BINARIES_ARM = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_ARM +TAB_BINARIES_EBC = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_EBC +TAB_BINARIES_AARCH64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_INCLUDES = 'Includes' +TAB_INCLUDES_COMMON = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_INCLUDES_IA32 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_INCLUDES_X64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_X64 +TAB_INCLUDES_ARM = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_ARM +TAB_INCLUDES_EBC = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_EBC +TAB_INCLUDES_AARCH64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_GUIDS = 'Guids' +TAB_GUIDS_COMMON = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_GUIDS_IA32 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_GUIDS_X64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_X64 +TAB_GUIDS_ARM = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_ARM +TAB_GUIDS_EBC = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_EBC +TAB_GUIDS_AARCH64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PROTOCOLS = 'Protocols' +TAB_PROTOCOLS_COMMON = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PROTOCOLS_IA32 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PROTOCOLS_X64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_X64 +TAB_PROTOCOLS_ARM = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_ARM +TAB_PROTOCOLS_EBC = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_EBC +TAB_PROTOCOLS_AARCH64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PPIS = 'Ppis' +TAB_PPIS_COMMON = TAB_PPIS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PPIS_IA32 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PPIS_X64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_X64 +TAB_PPIS_ARM = TAB_PPIS + TAB_SPLIT + TAB_ARCH_ARM +TAB_PPIS_EBC = TAB_PPIS + TAB_SPLIT + TAB_ARCH_EBC +TAB_PPIS_AARCH64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_LIBRARY_CLASSES = 'LibraryClasses' +TAB_LIBRARY_CLASSES_COMMON = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_LIBRARY_CLASSES_IA32 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_LIBRARY_CLASSES_X64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_X64 +TAB_LIBRARY_CLASSES_ARM = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_ARM +TAB_LIBRARY_CLASSES_EBC = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_EBC +TAB_LIBRARY_CLASSES_AARCH64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PACKAGES = 'Packages' +TAB_PACKAGES_COMMON = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PACKAGES_IA32 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PACKAGES_X64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_X64 +TAB_PACKAGES_ARM = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_ARM +TAB_PACKAGES_EBC = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_EBC +TAB_PACKAGES_AARCH64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PCDS = 'Pcds' +TAB_PCDS_FIXED_AT_BUILD = 'FixedAtBuild' +TAB_PCDS_PATCHABLE_IN_MODULE = 'PatchableInModule' +TAB_PCDS_FEATURE_FLAG = 'FeatureFlag' +TAB_PCDS_DYNAMIC_EX = 'DynamicEx' +TAB_PCDS_DYNAMIC_EX_DEFAULT = 'DynamicExDefault' +TAB_PCDS_DYNAMIC_EX_VPD = 'DynamicExVpd' +TAB_PCDS_DYNAMIC_EX_HII = 'DynamicExHii' +TAB_PCDS_DYNAMIC = 'Dynamic' +TAB_PCDS_DYNAMIC_DEFAULT = 'DynamicDefault' +TAB_PCDS_DYNAMIC_VPD = 'DynamicVpd' +TAB_PCDS_DYNAMIC_HII = 'DynamicHii' + +PCD_DYNAMIC_TYPE_SET = {TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_DEFAULT, TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_HII} +PCD_DYNAMIC_EX_TYPE_SET = {TAB_PCDS_DYNAMIC_EX, TAB_PCDS_DYNAMIC_EX_DEFAULT, TAB_PCDS_DYNAMIC_EX_VPD, TAB_PCDS_DYNAMIC_EX_HII} + +# leave as a list for order +PCD_TYPE_LIST = [TAB_PCDS_FIXED_AT_BUILD, TAB_PCDS_PATCHABLE_IN_MODULE, TAB_PCDS_FEATURE_FLAG, TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_EX] + +TAB_PCDS_FIXED_AT_BUILD_NULL = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD +TAB_PCDS_FIXED_AT_BUILD_COMMON = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_FIXED_AT_BUILD_IA32 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_FIXED_AT_BUILD_X64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_FIXED_AT_BUILD_ARM = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_FIXED_AT_BUILD_EBC = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_EBC +TAB_PCDS_FIXED_AT_BUILD_AARCH64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PCDS_PATCHABLE_IN_MODULE_NULL = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE +TAB_PCDS_PATCHABLE_IN_MODULE_COMMON = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_PATCHABLE_IN_MODULE_IA32 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_PATCHABLE_IN_MODULE_X64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_PATCHABLE_IN_MODULE_ARM = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_PATCHABLE_IN_MODULE_EBC = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_EBC +TAB_PCDS_PATCHABLE_IN_MODULE_AARCH64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PCDS_FEATURE_FLAG_NULL = TAB_PCDS + TAB_PCDS_FEATURE_FLAG +TAB_PCDS_FEATURE_FLAG_COMMON = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_FEATURE_FLAG_IA32 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_FEATURE_FLAG_X64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_FEATURE_FLAG_ARM = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_FEATURE_FLAG_EBC = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_EBC +TAB_PCDS_FEATURE_FLAG_AARCH64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PCDS_DYNAMIC_EX_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX +TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_DEFAULT +TAB_PCDS_DYNAMIC_EX_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_HII +TAB_PCDS_DYNAMIC_EX_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_VPD +TAB_PCDS_DYNAMIC_EX_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_DYNAMIC_EX_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_DYNAMIC_EX_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_DYNAMIC_EX_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_DYNAMIC_EX_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_EBC +TAB_PCDS_DYNAMIC_EX_AARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PCDS_DYNAMIC_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC +TAB_PCDS_DYNAMIC_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_DEFAULT +TAB_PCDS_DYNAMIC_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_HII +TAB_PCDS_DYNAMIC_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_VPD +TAB_PCDS_DYNAMIC_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_COMMON +TAB_PCDS_DYNAMIC_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_IA32 +TAB_PCDS_DYNAMIC_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_X64 +TAB_PCDS_DYNAMIC_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_ARM +TAB_PCDS_DYNAMIC_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_EBC +TAB_PCDS_DYNAMIC_AARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE = 'PcdLoadFixAddressPeiCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE = 'PcdLoadFixAddressBootTimeCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE = 'PcdLoadFixAddressRuntimeCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE = 'PcdLoadFixAddressSmmCodePageNumber' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE = 'UINT32' +TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET = {TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE, \ + TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE, \ + TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE, \ + TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE} + +## The mapping dictionary from datum type to its maximum number. +MAX_VAL_TYPE = {"BOOLEAN":0x01, TAB_UINT8:0xFF, TAB_UINT16:0xFFFF, TAB_UINT32:0xFFFFFFFF, TAB_UINT64:0xFFFFFFFFFFFFFFFF} +## The mapping dictionary from datum type to size string. +MAX_SIZE_TYPE = {"BOOLEAN":1, TAB_UINT8:1, TAB_UINT16:2, TAB_UINT32:4, TAB_UINT64:8} + +TAB_DEPEX = 'Depex' +TAB_DEPEX_COMMON = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_COMMON +TAB_DEPEX_IA32 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_IA32 +TAB_DEPEX_X64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_X64 +TAB_DEPEX_ARM = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_ARM +TAB_DEPEX_EBC = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_EBC +TAB_DEPEX_AARCH64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_SKUIDS = 'SkuIds' +TAB_DEFAULT_STORES = 'DefaultStores' +TAB_DEFAULT_STORES_DEFAULT = 'STANDARD' + +TAB_LIBRARIES = 'Libraries' +TAB_LIBRARIES_COMMON = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_COMMON +TAB_LIBRARIES_IA32 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_IA32 +TAB_LIBRARIES_X64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_X64 +TAB_LIBRARIES_ARM = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_ARM +TAB_LIBRARIES_EBC = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_EBC +TAB_LIBRARIES_AARCH64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_COMPONENTS = 'Components' +TAB_COMPONENTS_COMMON = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_COMMON +TAB_COMPONENTS_IA32 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_IA32 +TAB_COMPONENTS_X64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_X64 +TAB_COMPONENTS_ARM = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_ARM +TAB_COMPONENTS_EBC = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_EBC +TAB_COMPONENTS_AARCH64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_AARCH64 + +TAB_BUILD_OPTIONS = 'BuildOptions' + +TAB_DEFINE = 'DEFINE' +TAB_NMAKE = 'Nmake' +TAB_USER_EXTENSIONS = 'UserExtensions' +TAB_INCLUDE = '!include' +TAB_DEFAULT = 'DEFAULT' +TAB_COMMON = 'COMMON' + +# +# Common Define +# +TAB_COMMON_DEFINES = 'Defines' + +# +# Inf Definitions +# +TAB_INF_DEFINES = TAB_COMMON_DEFINES +TAB_INF_DEFINES_INF_VERSION = 'INF_VERSION' +TAB_INF_DEFINES_BASE_NAME = 'BASE_NAME' +TAB_INF_DEFINES_FILE_GUID = 'FILE_GUID' +TAB_INF_DEFINES_MODULE_TYPE = 'MODULE_TYPE' +TAB_INF_DEFINES_EFI_SPECIFICATION_VERSION = 'EFI_SPECIFICATION_VERSION' +TAB_INF_DEFINES_UEFI_SPECIFICATION_VERSION = 'UEFI_SPECIFICATION_VERSION' +TAB_INF_DEFINES_PI_SPECIFICATION_VERSION = 'PI_SPECIFICATION_VERSION' +TAB_INF_DEFINES_EDK_RELEASE_VERSION = 'EDK_RELEASE_VERSION' +TAB_INF_DEFINES_BINARY_MODULE = 'BINARY_MODULE' +TAB_INF_DEFINES_LIBRARY_CLASS = 'LIBRARY_CLASS' +TAB_INF_DEFINES_COMPONENT_TYPE = 'COMPONENT_TYPE' +TAB_INF_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME' +TAB_INF_DEFINES_DPX_SOURCE = 'DPX_SOURCE' +TAB_INF_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER' +TAB_INF_DEFINES_BUILD_TYPE = 'BUILD_TYPE' +TAB_INF_DEFINES_FFS_EXT = 'FFS_EXT' +TAB_INF_DEFINES_FV_EXT = 'FV_EXT' +TAB_INF_DEFINES_SOURCE_FV = 'SOURCE_FV' +TAB_INF_DEFINES_VERSION_NUMBER = 'VERSION_NUMBER' +TAB_INF_DEFINES_VERSION = 'VERSION' # for Edk inf, the same as VERSION_NUMBER +TAB_INF_DEFINES_VERSION_STRING = 'VERSION_STRING' +TAB_INF_DEFINES_PCD_IS_DRIVER = 'PCD_IS_DRIVER' +TAB_INF_DEFINES_TIANO_EDK_FLASHMAP_H = 'TIANO_EDK_FLASHMAP_H' +TAB_INF_DEFINES_ENTRY_POINT = 'ENTRY_POINT' +TAB_INF_DEFINES_UNLOAD_IMAGE = 'UNLOAD_IMAGE' +TAB_INF_DEFINES_CONSTRUCTOR = 'CONSTRUCTOR' +TAB_INF_DEFINES_DESTRUCTOR = 'DESTRUCTOR' +TAB_INF_DEFINES_DEFINE = 'DEFINE' +TAB_INF_DEFINES_SPEC = 'SPEC' +TAB_INF_DEFINES_CUSTOM_MAKEFILE = 'CUSTOM_MAKEFILE' +TAB_INF_DEFINES_MACRO = '__MACROS__' +TAB_INF_DEFINES_SHADOW = 'SHADOW' +TAB_INF_FIXED_PCD = 'FixedPcd' +TAB_INF_FEATURE_PCD = 'FeaturePcd' +TAB_INF_PATCH_PCD = 'PatchPcd' +TAB_INF_PCD = 'Pcd' +TAB_INF_PCD_EX = 'PcdEx' +TAB_INF_USAGE_PRO = 'PRODUCES' +TAB_INF_USAGE_SOME_PRO = 'SOMETIMES_PRODUCES' +TAB_INF_USAGE_CON = 'CONSUMES' +TAB_INF_USAGE_SOME_CON = 'SOMETIMES_CONSUMES' +TAB_INF_USAGE_NOTIFY = 'NOTIFY' +TAB_INF_USAGE_TO_START = 'TO_START' +TAB_INF_USAGE_BY_START = 'BY_START' +TAB_INF_GUIDTYPE_EVENT = 'Event' +TAB_INF_GUIDTYPE_FILE = 'File' +TAB_INF_GUIDTYPE_FV = 'FV' +TAB_INF_GUIDTYPE_GUID = 'GUID' +TAB_INF_GUIDTYPE_HII = 'HII' +TAB_INF_GUIDTYPE_HOB = 'HOB' +TAB_INF_GUIDTYPE_ST = 'SystemTable' +TAB_INF_GUIDTYPE_TSG = 'TokenSpaceGuid' +TAB_INF_GUIDTYPE_VAR = 'Variable' +TAB_INF_GUIDTYPE_PROTOCOL = 'PROTOCOL' +TAB_INF_GUIDTYPE_PPI = 'PPI' +TAB_INF_USAGE_UNDEFINED = 'UNDEFINED' + +# +# Dec Definitions +# +TAB_DEC_DEFINES = TAB_COMMON_DEFINES +TAB_DEC_DEFINES_DEC_SPECIFICATION = 'DEC_SPECIFICATION' +TAB_DEC_DEFINES_PACKAGE_NAME = 'PACKAGE_NAME' +TAB_DEC_DEFINES_PACKAGE_GUID = 'PACKAGE_GUID' +TAB_DEC_DEFINES_PACKAGE_VERSION = 'PACKAGE_VERSION' +TAB_DEC_DEFINES_PKG_UNI_FILE = 'PKG_UNI_FILE' + +# +# Dsc Definitions +# +TAB_DSC_DEFINES = TAB_COMMON_DEFINES +TAB_DSC_DEFINES_PLATFORM_NAME = 'PLATFORM_NAME' +TAB_DSC_DEFINES_PLATFORM_GUID = 'PLATFORM_GUID' +TAB_DSC_DEFINES_PLATFORM_VERSION = 'PLATFORM_VERSION' +TAB_DSC_DEFINES_DSC_SPECIFICATION = 'DSC_SPECIFICATION' +TAB_DSC_DEFINES_OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY' +TAB_DSC_DEFINES_SUPPORTED_ARCHITECTURES = 'SUPPORTED_ARCHITECTURES' +TAB_DSC_DEFINES_BUILD_TARGETS = 'BUILD_TARGETS' +TAB_DSC_DEFINES_SKUID_IDENTIFIER = 'SKUID_IDENTIFIER' +TAB_DSC_DEFINES_PCD_INFO_GENERATION = 'PCD_INFO_GENERATION' +TAB_DSC_DEFINES_PCD_VAR_CHECK_GENERATION = 'PCD_VAR_CHECK_GENERATION' +TAB_DSC_DEFINES_FLASH_DEFINITION = 'FLASH_DEFINITION' +TAB_DSC_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER' +TAB_DSC_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME' +TAB_DSC_DEFINES_BS_BASE_ADDRESS = 'BsBaseAddress' +TAB_DSC_DEFINES_RT_BASE_ADDRESS = 'RtBaseAddress' +TAB_DSC_DEFINES_RFC_LANGUAGES = 'RFC_LANGUAGES' +TAB_DSC_DEFINES_ISO_LANGUAGES = 'ISO_LANGUAGES' +TAB_DSC_DEFINES_DEFINE = 'DEFINE' +TAB_DSC_DEFINES_VPD_TOOL_GUID = 'VPD_TOOL_GUID' +TAB_FIX_LOAD_TOP_MEMORY_ADDRESS = 'FIX_LOAD_TOP_MEMORY_ADDRESS' +TAB_DSC_DEFINES_EDKGLOBAL = 'EDK_GLOBAL' +TAB_DSC_PREBUILD = 'PREBUILD' +TAB_DSC_POSTBUILD = 'POSTBUILD' +# +# TargetTxt Definitions +# +TAB_TAT_DEFINES_ACTIVE_PLATFORM = 'ACTIVE_PLATFORM' +TAB_TAT_DEFINES_ACTIVE_MODULE = 'ACTIVE_MODULE' +TAB_TAT_DEFINES_TOOL_CHAIN_CONF = 'TOOL_CHAIN_CONF' +TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER = 'MAX_CONCURRENT_THREAD_NUMBER' +TAB_TAT_DEFINES_TARGET = 'TARGET' +TAB_TAT_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG' +TAB_TAT_DEFINES_TARGET_ARCH = 'TARGET_ARCH' +TAB_TAT_DEFINES_BUILD_RULE_CONF = "BUILD_RULE_CONF" + +# +# ToolDef Definitions +# +TAB_TOD_DEFINES_TARGET = 'TARGET' +TAB_TOD_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG' +TAB_TOD_DEFINES_TARGET_ARCH = 'TARGET_ARCH' +TAB_TOD_DEFINES_COMMAND_TYPE = 'COMMAND_TYPE' +TAB_TOD_DEFINES_FAMILY = 'FAMILY' +TAB_TOD_DEFINES_BUILDRULEFAMILY = 'BUILDRULEFAMILY' +TAB_TOD_DEFINES_BUILDRULEORDER = 'BUILDRULEORDER' + +# +# Conditional Statements +# +TAB_IF = '!if' +TAB_END_IF = '!endif' +TAB_ELSE_IF = '!elseif' +TAB_ELSE = '!else' +TAB_IF_DEF = '!ifdef' +TAB_IF_N_DEF = '!ifndef' +TAB_IF_EXIST = '!if exist' +TAB_ERROR = '!error' + +# +# Unknown section +# +TAB_UNKNOWN = 'UNKNOWN' + +# +# Build database path +# +DATABASE_PATH = ":memory:" #"BuildDatabase.db" + +# used by ECC +MODIFIER_SET = {'IN', 'OUT', 'OPTIONAL', 'UNALIGNED', 'EFI_RUNTIMESERVICE', 'EFI_BOOTSERVICE', 'EFIAPI'} + +# Dependency Opcodes +DEPEX_OPCODE_BEFORE = "BEFORE" +DEPEX_OPCODE_AFTER = "AFTER" +DEPEX_OPCODE_PUSH = "PUSH" +DEPEX_OPCODE_AND = "AND" +DEPEX_OPCODE_OR = "OR" +DEPEX_OPCODE_NOT = "NOT" +DEPEX_OPCODE_END = "END" +DEPEX_OPCODE_SOR = "SOR" +DEPEX_OPCODE_TRUE = "TRUE" +DEPEX_OPCODE_FALSE = "FALSE" + +# Dependency Expression +DEPEX_SUPPORTED_OPCODE_SET = {"BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR", "TRUE", "FALSE", '(', ')'} + +TAB_STATIC_LIBRARY = "STATIC-LIBRARY-FILE" +TAB_DYNAMIC_LIBRARY = "DYNAMIC-LIBRARY-FILE" +TAB_FRAMEWORK_IMAGE = "EFI-IMAGE-FILE" +TAB_C_CODE_FILE = "C-CODE-FILE" +TAB_C_HEADER_FILE = "C-HEADER-FILE" +TAB_UNICODE_FILE = "UNICODE-TEXT-FILE" +TAB_IMAGE_FILE = "IMAGE-DEFINITION-FILE" +TAB_DEPENDENCY_EXPRESSION_FILE = "DEPENDENCY-EXPRESSION-FILE" +TAB_UNKNOWN_FILE = "UNKNOWN-TYPE-FILE" +TAB_DEFAULT_BINARY_FILE = "_BINARY_FILE_" +TAB_OBJECT_FILE = "OBJECT-FILE" +TAB_VFR_FILE = 'VISUAL-FORM-REPRESENTATION-FILE' + +# used by BRG +TAB_BRG_PCD = 'PCD' +TAB_BRG_LIBRARY = 'Library' + +# +# Build Rule File Version Definition +# +TAB_BUILD_RULE_VERSION = "build_rule_version" + +# section name for PCDs +PCDS_DYNAMIC_DEFAULT = "PcdsDynamicDefault" +PCDS_DYNAMIC_VPD = "PcdsDynamicVpd" +PCDS_DYNAMIC_HII = "PcdsDynamicHii" +PCDS_DYNAMICEX_DEFAULT = "PcdsDynamicExDefault" +PCDS_DYNAMICEX_VPD = "PcdsDynamicExVpd" +PCDS_DYNAMICEX_HII = "PcdsDynamicExHii" + +SECTIONS_HAVE_ITEM_PCD_SET = {PCDS_DYNAMIC_DEFAULT.upper(), PCDS_DYNAMIC_VPD.upper(), PCDS_DYNAMIC_HII.upper(), \ + PCDS_DYNAMICEX_DEFAULT.upper(), PCDS_DYNAMICEX_VPD.upper(), PCDS_DYNAMICEX_HII.upper()} +# Section allowed to have items after arch +SECTIONS_HAVE_ITEM_AFTER_ARCH_SET = {TAB_LIBRARY_CLASSES.upper(), TAB_DEPEX.upper(), TAB_USER_EXTENSIONS.upper(), + PCDS_DYNAMIC_DEFAULT.upper(), + PCDS_DYNAMIC_VPD.upper(), + PCDS_DYNAMIC_HII.upper(), + PCDS_DYNAMICEX_DEFAULT.upper(), + PCDS_DYNAMICEX_VPD.upper(), + PCDS_DYNAMICEX_HII.upper(), + TAB_BUILD_OPTIONS.upper(), + TAB_INCLUDES.upper()} + +# +# pack codes as used in PcdDb and elsewhere +# +PACK_PATTERN_GUID = '=LHHBBBBBBBB' +PACK_CODE_BY_SIZE = {8:'=Q', + 4:'=L', + 2:'=H', + 1:'=B', + 0:'=B', + 16:""} + +TAB_COMPILER_MSFT = 'MSFT' diff --git a/tools/python/Common/EdkLogger.py b/tools/python/Common/EdkLogger.py new file mode 100755 index 0000000..06da4a9 --- /dev/null +++ b/tools/python/Common/EdkLogger.py @@ -0,0 +1,383 @@ +## @file +# This file implements the log mechanism for Python tools. +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +# Copyright 2001-2016 by Vinay Sajip. All Rights Reserved. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, +# provided that the above copyright notice appear in all copies and that +# both that copyright notice and this permission notice appear in +# supporting documentation, and that the name of Vinay Sajip +# not be used in advertising or publicity pertaining to distribution +# of the software without specific, written prior permission. +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# This copyright is for QueueHandler. + +## Import modules +from __future__ import absolute_import +import Common.LongFilePathOs as os, sys, logging +import traceback +from .BuildToolError import * +try: + from logging.handlers import QueueHandler +except: + class QueueHandler(logging.Handler): + """ + This handler sends events to a queue. Typically, it would be used together + with a multiprocessing Queue to centralise logging to file in one process + (in a multi-process application), so as to avoid file write contention + between processes. + + This code is new in Python 3.2, but this class can be copy pasted into + user code for use with earlier Python versions. + """ + + def __init__(self, queue): + """ + Initialise an instance, using the passed queue. + """ + logging.Handler.__init__(self) + self.queue = queue + + def enqueue(self, record): + """ + Enqueue a record. + + The base implementation uses put_nowait. You may want to override + this method if you want to use blocking, timeouts or custom queue + implementations. + """ + self.queue.put_nowait(record) + + def prepare(self, record): + """ + Prepares a record for queuing. The object returned by this method is + enqueued. + + The base implementation formats the record to merge the message + and arguments, and removes unpickleable items from the record + in-place. + + You might want to override this method if you want to convert + the record to a dict or JSON string, or send a modified copy + of the record while leaving the original intact. + """ + # The format operation gets traceback text into record.exc_text + # (if there's exception data), and also returns the formatted + # message. We can then use this to replace the original + # msg + args, as these might be unpickleable. We also zap the + # exc_info and exc_text attributes, as they are no longer + # needed and, if not None, will typically not be pickleable. + msg = self.format(record) + record.message = msg + record.msg = msg + record.args = None + record.exc_info = None + record.exc_text = None + return record + + def emit(self, record): + """ + Emit a record. + + Writes the LogRecord to the queue, preparing it for pickling first. + """ + try: + self.enqueue(self.prepare(record)) + except Exception: + self.handleError(record) +class BlockQueueHandler(QueueHandler): + def enqueue(self, record): + self.queue.put(record,True) +## Log level constants +DEBUG_0 = 1 +DEBUG_1 = 2 +DEBUG_2 = 3 +DEBUG_3 = 4 +DEBUG_4 = 5 +DEBUG_5 = 6 +DEBUG_6 = 7 +DEBUG_7 = 8 +DEBUG_8 = 9 +DEBUG_9 = 10 +VERBOSE = 15 +INFO = 20 +WARN = 30 +QUIET = 40 +ERROR = 50 +SILENT = 99 + +IsRaiseError = True + +# Tool name +_ToolName = os.path.basename(sys.argv[0]) + +# For validation purpose +_LogLevels = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5, + DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO, + ERROR, QUIET, SILENT] + +# For DEBUG level (All DEBUG_0~9 are applicable) +_DebugLogger = logging.getLogger("tool_debug") +_DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt="%H:%M:%S") + +# For VERBOSE, INFO, WARN level +_InfoLogger = logging.getLogger("tool_info") +_InfoFormatter = logging.Formatter("%(message)s") + +# For ERROR level +_ErrorLogger = logging.getLogger("tool_error") +_ErrorFormatter = logging.Formatter("%(message)s") + +# String templates for ERROR/WARN/DEBUG log message +_ErrorMessageTemplate = '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s' +_ErrorMessageTemplateWithoutFile = '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s' +_WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s' +_WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s' +_DebugMessageTemplate = '%(file)s(%(line)s): debug: \n %(msg)s' + +# +# Flag used to take WARN as ERROR. +# By default, only ERROR message will break the tools execution. +# +_WarningAsError = False + +## Log debug message +# +# @param Level DEBUG level (DEBUG0~9) +# @param Message Debug information +# @param ExtraData More information associated with "Message" +# +def debug(Level, Message, ExtraData=None): + if _DebugLogger.level > Level: + return + if Level > DEBUG_9: + return + + # Find out the caller method information + CallerStack = traceback.extract_stack()[-2] + TemplateDict = { + "file" : CallerStack[0], + "line" : CallerStack[1], + "msg" : Message, + } + + if ExtraData is not None: + LogText = _DebugMessageTemplate % TemplateDict + "\n %s" % ExtraData + else: + LogText = _DebugMessageTemplate % TemplateDict + + _DebugLogger.log(Level, LogText) + +## Log verbose message +# +# @param Message Verbose information +# +def verbose(Message): + return _InfoLogger.log(VERBOSE, Message) + +## Log warning message +# +# Warning messages are those which might be wrong but won't fail the tool. +# +# @param ToolName The name of the tool. If not given, the name of caller +# method will be used. +# @param Message Warning information +# @param File The name of file which caused the warning. +# @param Line The line number in the "File" which caused the warning. +# @param ExtraData More information associated with "Message" +# +def warn(ToolName, Message, File=None, Line=None, ExtraData=None): + if _InfoLogger.level > WARN: + return + + # if no tool name given, use caller's source file name as tool name + if ToolName is None or ToolName == "": + ToolName = os.path.basename(traceback.extract_stack()[-2][0]) + + if Line is None: + Line = "..." + else: + Line = "%d" % Line + + TemplateDict = { + "tool" : ToolName, + "file" : File, + "line" : Line, + "msg" : Message, + } + + if File is not None: + LogText = _WarningMessageTemplate % TemplateDict + else: + LogText = _WarningMessageTemplateWithoutFile % TemplateDict + + if ExtraData is not None: + LogText += "\n %s" % ExtraData + + _InfoLogger.log(WARN, LogText) + + # Raise an exception if indicated + if _WarningAsError == True: + raise FatalError(WARNING_AS_ERROR) + +## Log INFO message +info = _InfoLogger.info + +## Log ERROR message +# +# Once an error messages is logged, the tool's execution will be broken by raising +# an exception. If you don't want to break the execution later, you can give +# "RaiseError" with "False" value. +# +# @param ToolName The name of the tool. If not given, the name of caller +# method will be used. +# @param ErrorCode The error code +# @param Message Warning information +# @param File The name of file which caused the error. +# @param Line The line number in the "File" which caused the warning. +# @param ExtraData More information associated with "Message" +# @param RaiseError Raise an exception to break the tool's execution if +# it's True. This is the default behavior. +# +def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError): + if Line is None: + Line = "..." + else: + Line = "%d" % Line + + if Message is None: + if ErrorCode in gErrorMessage: + Message = gErrorMessage[ErrorCode] + else: + Message = gErrorMessage[UNKNOWN_ERROR] + + if ExtraData is None: + ExtraData = "" + + TemplateDict = { + "tool" : _ToolName, + "file" : File, + "line" : Line, + "errorcode" : ErrorCode, + "msg" : Message, + "extra" : ExtraData + } + + if File is not None: + LogText = _ErrorMessageTemplate % TemplateDict + else: + LogText = _ErrorMessageTemplateWithoutFile % TemplateDict + + _ErrorLogger.log(ERROR, LogText) + + if RaiseError and IsRaiseError: + raise FatalError(ErrorCode) + +# Log information which should be always put out +quiet = _ErrorLogger.error + +## Initialize log system +def LogClientInitialize(log_q): + # + # Since we use different format to log different levels of message into different + # place (stdout or stderr), we have to use different "Logger" objects to do this. + # + # For DEBUG level (All DEBUG_0~9 are applicable) + _DebugLogger.setLevel(INFO) + _DebugChannel = BlockQueueHandler(log_q) + _DebugChannel.setFormatter(_DebugFormatter) + _DebugLogger.addHandler(_DebugChannel) + + # For VERBOSE, INFO, WARN level + _InfoLogger.setLevel(INFO) + _InfoChannel = BlockQueueHandler(log_q) + _InfoChannel.setFormatter(_InfoFormatter) + _InfoLogger.addHandler(_InfoChannel) + + # For ERROR level + _ErrorLogger.setLevel(INFO) + _ErrorCh = BlockQueueHandler(log_q) + _ErrorCh.setFormatter(_ErrorFormatter) + _ErrorLogger.addHandler(_ErrorCh) + +## Set log level +# +# @param Level One of log level in _LogLevel +def SetLevel(Level): + if Level not in _LogLevels: + info("Not supported log level (%d). Use default level instead." % Level) + Level = INFO + _DebugLogger.setLevel(Level) + _InfoLogger.setLevel(Level) + _ErrorLogger.setLevel(Level) + +## Initialize log system +def Initialize(): + # + # Since we use different format to log different levels of message into different + # place (stdout or stderr), we have to use different "Logger" objects to do this. + # + # For DEBUG level (All DEBUG_0~9 are applicable) + _DebugLogger.setLevel(INFO) + _DebugChannel = logging.StreamHandler(sys.stdout) + _DebugChannel.setFormatter(_DebugFormatter) + _DebugLogger.addHandler(_DebugChannel) + + # For VERBOSE, INFO, WARN level + _InfoLogger.setLevel(INFO) + _InfoChannel = logging.StreamHandler(sys.stdout) + _InfoChannel.setFormatter(_InfoFormatter) + _InfoLogger.addHandler(_InfoChannel) + + # For ERROR level + _ErrorLogger.setLevel(INFO) + _ErrorCh = logging.StreamHandler(sys.stderr) + _ErrorCh.setFormatter(_ErrorFormatter) + _ErrorLogger.addHandler(_ErrorCh) + +def InitializeForUnitTest(): + Initialize() + SetLevel(SILENT) + +## Get current log level +def GetLevel(): + return _InfoLogger.getEffectiveLevel() + +## Raise up warning as error +def SetWarningAsError(): + global _WarningAsError + _WarningAsError = True + +## Specify a file to store the log message as well as put on console +# +# @param LogFile The file path used to store the log message +# +def SetLogFile(LogFile): + if os.path.exists(LogFile): + os.remove(LogFile) + + _Ch = logging.FileHandler(LogFile) + _Ch.setFormatter(_DebugFormatter) + _DebugLogger.addHandler(_Ch) + + _Ch= logging.FileHandler(LogFile) + _Ch.setFormatter(_InfoFormatter) + _InfoLogger.addHandler(_Ch) + + _Ch = logging.FileHandler(LogFile) + _Ch.setFormatter(_ErrorFormatter) + _ErrorLogger.addHandler(_Ch) + +if __name__ == '__main__': + pass + diff --git a/tools/python/Common/GlobalData.py b/tools/python/Common/GlobalData.py new file mode 100755 index 0000000..74c6d00 --- /dev/null +++ b/tools/python/Common/GlobalData.py @@ -0,0 +1,132 @@ +## @file +# This file is used to define common static strings used by INF/DEC/DSC files +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent + +import re + +gIsWindows = None +gWorkspace = "." +gOptions = None +gCaseInsensitive = False +gAllFiles = None +gCommand = None +gSKUID_CMD = None + +gGlobalDefines = {} +gPlatformDefines = {} +# PCD name and value pair for fixed at build and feature flag +gPlatformPcds = {} +# PCDs with type that are not fixed at build and feature flag +gPlatformOtherPcds = {} +gActivePlatform = None +gCommandLineDefines = {} +gEdkGlobal = {} +gCommandMaxLength = 4096 +# for debug trace purpose when problem occurs +gProcessingFile = '' +gBuildingModule = '' +gSkuids = [] +gDefaultStores = [] + +# definition for a MACRO name. used to create regular expressions below. +_MacroNamePattern = "[A-Z][A-Z0-9_]*" + +## Regular expression for matching macro used in DSC/DEC/INF file inclusion +gMacroRefPattern = re.compile("\$\(({})\)".format(_MacroNamePattern), re.UNICODE) +gMacroDefPattern = re.compile("^(DEFINE|EDK_GLOBAL)[ \t]+") +gMacroNamePattern = re.compile("^{}$".format(_MacroNamePattern)) + +# definition for a GUID. used to create regular expressions below. +_HexChar = r"[0-9a-fA-F]" +_GuidPattern = r"{Hex}{{8}}-{Hex}{{4}}-{Hex}{{4}}-{Hex}{{4}}-{Hex}{{12}}".format(Hex=_HexChar) + +## Regular expressions for GUID matching +gGuidPattern = re.compile(r'{}'.format(_GuidPattern)) +gGuidPatternEnd = re.compile(r'{}$'.format(_GuidPattern)) + +## Regular expressions for HEX matching +g4HexChar = re.compile(r'{}{{4}}'.format(_HexChar)) +gHexPattern = re.compile(r'0[xX]{}+'.format(_HexChar)) +gHexPatternAll = re.compile(r'0[xX]{}+$'.format(_HexChar)) + +## Regular expressions for string identifier checking +gIdentifierPattern = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$', re.UNICODE) +## Regular expression for GUID c structure format +_GuidCFormatPattern = r"{{\s*0[xX]{Hex}{{1,8}}\s*,\s*0[xX]{Hex}{{1,4}}\s*,\s*0[xX]{Hex}{{1,4}}" \ + r"\s*,\s*{{\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}" \ + r"\s*,\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}" \ + r"\s*,\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}" \ + r"\s*,\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}\s*}}\s*}}".format(Hex=_HexChar) +gGuidCFormatPattern = re.compile(r"{}".format(_GuidCFormatPattern)) + +# +# A global variable for whether current build in AutoGen phase or not. +# +gAutoGenPhase = False + +# +# The Conf dir outside the workspace dir +# +gConfDirectory = '' + +gBuildDirectory = '' +# +# The relative default database file path +# +gDatabasePath = ".cache/build.db" + +# +# Build flag for binary build +# +gIgnoreSource = False + +# +# FDF parser +# +gFdfParser = None + +BuildOptionPcd = [] + +# +# Mixed PCD name dict +# +MixedPcd = {} + +# Structure Pcd dict +gStructurePcd = {} +gPcdSkuOverrides={} +# Pcd name for the Pcd which used in the Conditional directives +gConditionalPcds = [] + +gUseHashCache = None +gBinCacheDest = None +gBinCacheSource = None +gPlatformHash = None +gPackageHash = {} +gModuleHash = {} +gEnableGenfdsMultiThread = True +gSikpAutoGenCache = set() + +# Dictionary for tracking Module build status as success or failure +# Top Dict: Key: Arch Type Value: Dictionary +# Second Dict: Key: AutoGen Obj Value: 'SUCCESS'\'FAIL'\'FAIL_METAFILE' +gModuleBuildTracking = dict() + +# Dictionary of booleans that dictate whether a module or +# library can be skiped +# Top Dict: Key: Arch Type Value: Dictionary +# Second Dict: Key: Module\Library Name Value: True\False +gBuildHashSkipTracking = dict() + +# Common dictionary to share module cache intermediate result and state +gCacheIR = None +# Common lock for the module cache intermediate data +cache_lock = None +# Common lock for the file access in multiple process AutoGens +file_lock = None +# Common dictionary to share platform libraries' constant Pcd +libConstPcd = None +# Common dictionary to share platform libraries' reference info +Refes = None diff --git a/tools/python/Common/LongFilePathOs.py b/tools/python/Common/LongFilePathOs.py new file mode 100755 index 0000000..190f36d --- /dev/null +++ b/tools/python/Common/LongFilePathOs.py @@ -0,0 +1,79 @@ +## @file +# Override built in module os to provide support for long file path +# +# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from __future__ import absolute_import +import os +from . import LongFilePathOsPath +from Common.LongFilePathSupport import LongFilePath +import time + +path = LongFilePathOsPath + +def access(path, mode): + return os.access(LongFilePath(path), mode) + +def remove(path): + Timeout = 0.0 + while Timeout < 5.0: + try: + return os.remove(LongFilePath(path)) + except: + time.sleep(0.1) + Timeout = Timeout + 0.1 + return os.remove(LongFilePath(path)) + +def removedirs(name): + return os.removedirs(LongFilePath(name)) + +def rmdir(path): + return os.rmdir(LongFilePath(path)) + +def mkdir(path): + return os.mkdir(LongFilePath(path)) + +def makedirs(name, mode=0o777): + return os.makedirs(LongFilePath(name), mode) + +def rename(old, new): + return os.rename(LongFilePath(old), LongFilePath(new)) + +def chdir(path): + return os.chdir(LongFilePath(path)) + +def chmod(path, mode): + return os.chmod(LongFilePath(path), mode) + +def stat(path): + return os.stat(LongFilePath(path)) + +def utime(path, times): + return os.utime(LongFilePath(path), times) + +def listdir(path): + List = [] + uList = os.listdir(u"%s" % LongFilePath(path)) + for Item in uList: + List.append(Item) + return List + +if hasattr(os, 'replace'): + def replace(src, dst): + return os.replace(LongFilePath(src), LongFilePath(dst)) + +environ = os.environ +getcwd = os.getcwd +chdir = os.chdir +walk = os.walk +W_OK = os.W_OK +F_OK = os.F_OK +sep = os.sep +linesep = os.linesep +getenv = os.getenv +pathsep = os.pathsep +name = os.name +SEEK_SET = os.SEEK_SET +SEEK_END = os.SEEK_END diff --git a/tools/python/Common/LongFilePathOsPath.py b/tools/python/Common/LongFilePathOsPath.py new file mode 100755 index 0000000..60a0536 --- /dev/null +++ b/tools/python/Common/LongFilePathOsPath.py @@ -0,0 +1,47 @@ +## @file +# Override built in module os.path to provide support for long file path +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import os +from Common.LongFilePathSupport import LongFilePath + +def isfile(path): + return os.path.isfile(LongFilePath(path)) + +def isdir(path): + return os.path.isdir(LongFilePath(path)) + +def exists(path): + return os.path.exists(LongFilePath(path)) + +def getsize(filename): + return os.path.getsize(LongFilePath(filename)) + +def getmtime(filename): + return os.path.getmtime(LongFilePath(filename)) + +def getatime(filename): + return os.path.getatime(LongFilePath(filename)) + +def getctime(filename): + return os.path.getctime(LongFilePath(filename)) + +join = os.path.join +splitext = os.path.splitext +splitdrive = os.path.splitdrive +split = os.path.split +abspath = os.path.abspath +basename = os.path.basename +commonprefix = os.path.commonprefix +sep = os.path.sep +normpath = os.path.normpath +normcase = os.path.normcase +dirname = os.path.dirname +islink = os.path.islink +isabs = os.path.isabs +realpath = os.path.realpath +relpath = os.path.relpath +pardir = os.path.pardir diff --git a/tools/python/Common/LongFilePathSupport.py b/tools/python/Common/LongFilePathSupport.py new file mode 100755 index 0000000..38c4396 --- /dev/null +++ b/tools/python/Common/LongFilePathSupport.py @@ -0,0 +1,45 @@ +## @file +# Override built in function file.open to provide support for long file path +# +# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import os +import platform +import shutil +import codecs + +## +# OpenLongPath +# Convert a file path to a long file path +# +def LongFilePath(FileName): + FileName = os.path.normpath(FileName) + if platform.system() == 'Windows': + if FileName.startswith('\\\\?\\'): + return FileName + if FileName.startswith('\\\\'): + return '\\\\?\\UNC\\' + FileName[2:] + if os.path.isabs(FileName): + return '\\\\?\\' + FileName + return FileName + +## +# OpenLongFilePath +# wrap open to support opening a long file path +# +def OpenLongFilePath(FileName, Mode='r', Buffer= -1): + return open(LongFilePath(FileName), Mode, Buffer) + +def CodecOpenLongFilePath(Filename, Mode='rb', Encoding=None, Errors='strict', Buffering=1): + return codecs.open(LongFilePath(Filename), Mode, Encoding, Errors, Buffering) + +## +# CopyLongFilePath +# wrap copyfile to support copy a long file path +# +def CopyLongFilePath(src, dst): + with open(LongFilePath(src), 'rb') as fsrc: + with open(LongFilePath(dst), 'wb') as fdst: + shutil.copyfileobj(fsrc, fdst) diff --git a/tools/python/Common/Misc.py b/tools/python/Common/Misc.py new file mode 100755 index 0000000..a488536 --- /dev/null +++ b/tools/python/Common/Misc.py @@ -0,0 +1,1926 @@ +## @file +# Common routines used by all tools +# +# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import + +import sys +import string +import threading +import time +import re +import pickle +import array +import shutil +import filecmp +from random import sample +from struct import pack +import uuid +import subprocess +import tempfile +from collections import OrderedDict + +import Common.LongFilePathOs as os +from Common import EdkLogger as EdkLogger +from Common import GlobalData as GlobalData +from Common.DataType import * +from Common.BuildToolError import * +from CommonDataClass.DataClass import * +from Common.Parsing import GetSplitValueList +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.LongFilePathSupport import CopyLongFilePath as CopyLong +from Common.LongFilePathSupport import LongFilePath as LongFilePath +from Common.MultipleWorkspace import MultipleWorkspace as mws +from CommonDataClass.Exceptions import BadExpression +from Common.caching import cached_property + +ArrayIndex = re.compile("\[\s*[0-9a-fA-FxX]*\s*\]") +## Regular expression used to find out place holders in string template +gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE) + +## regular expressions for map file processing +startPatternGeneral = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class") +addressPatternGeneral = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base") +valuePatternGcc = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$') +pcdPatternGcc = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)') +secReGeneral = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE) + +StructPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*$') + +## Dictionary used to store dependencies of files +gDependencyDatabase = {} # arch : {file path : [dependent files list]} + +# +# If a module is built more than once with different PCDs or library classes +# a temporary INF file with same content is created, the temporary file is removed +# when build exits. +# +_TempInfs = [] + +def GetVariableOffset(mapfilepath, efifilepath, varnames): + """ Parse map file to get variable offset in current EFI file + @param mapfilepath Map file absolution path + @param efifilepath: EFI binary file full path + @param varnames iteratable container whose elements are variable names to be searched + + @return List whos elements are tuple with variable name and raw offset + """ + lines = [] + try: + f = open(mapfilepath, 'r') + lines = f.readlines() + f.close() + except: + return None + + if len(lines) == 0: return None + firstline = lines[0].strip() + if (firstline.startswith("Archive member included ") and + firstline.endswith(" file (symbol)")): + return _parseForGCC(lines, efifilepath, varnames) + if firstline.startswith("# Path:"): + return _parseForXcode(lines, efifilepath, varnames) + return _parseGeneral(lines, efifilepath, varnames) + +def _parseForXcode(lines, efifilepath, varnames): + status = 0 + ret = [] + for line in lines: + line = line.strip() + if status == 0 and line == "# Symbols:": + status = 1 + continue + if status == 1 and len(line) != 0: + for varname in varnames: + if varname in line: + # cannot pregenerate this RegEx since it uses varname from varnames. + m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line) + if m is not None: + ret.append((varname, m.group(1))) + return ret + +def _parseForGCC(lines, efifilepath, varnames): + """ Parse map file generated by GCC linker """ + status = 0 + sections = [] + varoffset = [] + for index, line in enumerate(lines): + line = line.strip() + # status machine transection + if status == 0 and line == "Memory Configuration": + status = 1 + continue + elif status == 1 and line == 'Linker script and memory map': + status = 2 + continue + elif status ==2 and line == 'START GROUP': + status = 3 + continue + + # status handler + if status == 3: + m = valuePatternGcc.match(line) + if m is not None: + sections.append(m.groups(0)) + for varname in varnames: + Str = '' + m = re.match("^.data.(%s)" % varname, line) + if m is not None: + m = re.match(".data.(%s)$" % varname, line) + if m is not None: + Str = lines[index + 1] + else: + Str = line[len(".data.%s" % varname):] + if Str: + m = pcdPatternGcc.match(Str.strip()) + if m is not None: + varoffset.append((varname, int(m.groups(0)[0], 16), int(sections[-1][1], 16), sections[-1][0])) + + if not varoffset: + return [] + # get section information from efi file + efisecs = PeImageClass(efifilepath).SectionHeaderList + if efisecs is None or len(efisecs) == 0: + return [] + #redirection + redirection = 0 + for efisec in efisecs: + for section in sections: + if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text': + redirection = int(section[1], 16) - efisec[1] + + ret = [] + for var in varoffset: + for efisec in efisecs: + if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]: + ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection))) + return ret + +def _parseGeneral(lines, efifilepath, varnames): + status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table + secs = [] # key = section name + varoffset = [] + symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$-]+) +([\da-fA-F]+)', re.UNICODE) + + for line in lines: + line = line.strip() + if startPatternGeneral.match(line): + status = 1 + continue + if addressPatternGeneral.match(line): + status = 2 + continue + if line.startswith("entry point at"): + status = 3 + continue + if status == 1 and len(line) != 0: + m = secReGeneral.match(line) + assert m is not None, "Fail to parse the section in map file , line is %s" % line + sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0) + secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class]) + if status == 2 and len(line) != 0: + for varname in varnames: + m = symRe.match(line) + assert m is not None, "Fail to parse the symbol in map file, line is %s" % line + sec_no, sym_offset, sym_name, vir_addr = m.groups(0) + sec_no = int(sec_no, 16) + sym_offset = int(sym_offset, 16) + vir_addr = int(vir_addr, 16) + # cannot pregenerate this RegEx since it uses varname from varnames. + m2 = re.match('^[_]*(%s)' % varname, sym_name) + if m2 is not None: + # fond a binary pcd entry in map file + for sec in secs: + if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]): + varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no]) + + if not varoffset: return [] + + # get section information from efi file + efisecs = PeImageClass(efifilepath).SectionHeaderList + if efisecs is None or len(efisecs) == 0: + return [] + + ret = [] + for var in varoffset: + index = 0 + for efisec in efisecs: + index = index + 1 + if var[1].strip() == efisec[0].strip(): + ret.append((var[0], hex(efisec[2] + var[2]))) + elif var[4] == index: + ret.append((var[0], hex(efisec[2] + var[2]))) + + return ret + +## Routine to process duplicated INF +# +# This function is called by following two cases: +# Case 1 in DSC: +# [components.arch] +# Pkg/module/module.inf +# Pkg/module/module.inf { +# +# FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 +# } +# Case 2 in FDF: +# INF Pkg/module/module.inf +# INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf +# +# This function copies Pkg/module/module.inf to +# Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf +# +# @param Path Original PathClass object +# @param BaseName New file base name +# +# @retval return the new PathClass object +# +def ProcessDuplicatedInf(Path, BaseName, Workspace): + Filename = os.path.split(Path.File)[1] + if '.' in Filename: + Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):] + else: + Filename = BaseName + Path.BaseName + + DbDir = os.path.split(GlobalData.gDatabasePath)[0] + + # + # A temporary INF is copied to database path which must have write permission + # The temporary will be removed at the end of build + # In case of name conflict, the file name is + # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf) + # + TempFullPath = os.path.join(DbDir, + Filename) + RtPath = PathClass(Path.File, Workspace) + # + # Modify the full path to temporary path, keep other unchanged + # + # To build same module more than once, the module path with FILE_GUID overridden has + # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path + # in DSC which is used as relative path by C files and other files in INF. + # A trick was used: all module paths are PathClass instances, after the initialization + # of PathClass, the PathClass.Path is overridden by the temporary INF path. + # + # The reason for creating a temporary INF is: + # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary, + # the key is the full path of INF, the value is an object to save overridden library instances, PCDs. + # A different key for the same module is needed to create different output directory, + # retrieve overridden PCDs, library instances. + # + # The BaseName is the FILE_GUID which is also the output directory name. + # + # + RtPath.Path = TempFullPath + RtPath.BaseName = BaseName + RtPath.OriginalPath = Path + # + # If file exists, compare contents + # + if os.path.exists(TempFullPath): + with open(str(Path), 'rb') as f1, open(TempFullPath, 'rb') as f2: + if f1.read() == f2.read(): + return RtPath + _TempInfs.append(TempFullPath) + shutil.copy2(str(Path), TempFullPath) + return RtPath + +## Remove temporary created INFs whose paths were saved in _TempInfs +# +def ClearDuplicatedInf(): + while _TempInfs: + File = _TempInfs.pop() + if os.path.exists(File): + os.remove(File) + +## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style +# +# @param Guid The GUID string +# +# @retval string The GUID string in C structure style +# +def GuidStringToGuidStructureString(Guid): + GuidList = Guid.split('-') + Result = '{' + for Index in range(0, 3, 1): + Result = Result + '0x' + GuidList[Index] + ', ' + Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] + for Index in range(0, 12, 2): + Result = Result + ', 0x' + GuidList[4][Index:Index + 2] + Result += '}}' + return Result + +## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# +# @param GuidValue The GUID value in byte array +# +# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format +# +def GuidStructureByteArrayToGuidString(GuidValue): + guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "") + guidValueList = guidValueString.split(",") + if len(guidValueList) != 16: + return '' + #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue) + try: + return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( + int(guidValueList[3], 16), + int(guidValueList[2], 16), + int(guidValueList[1], 16), + int(guidValueList[0], 16), + int(guidValueList[5], 16), + int(guidValueList[4], 16), + int(guidValueList[7], 16), + int(guidValueList[6], 16), + int(guidValueList[8], 16), + int(guidValueList[9], 16), + int(guidValueList[10], 16), + int(guidValueList[11], 16), + int(guidValueList[12], 16), + int(guidValueList[13], 16), + int(guidValueList[14], 16), + int(guidValueList[15], 16) + ) + except: + return '' + +## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# +# @param GuidValue The GUID value in C structure format +# +# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format +# +def GuidStructureStringToGuidString(GuidValue): + if not GlobalData.gGuidCFormatPattern.match(GuidValue): + return '' + guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "") + guidValueList = guidValueString.split(",") + if len(guidValueList) != 11: + return '' + #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue) + try: + return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( + int(guidValueList[0], 16), + int(guidValueList[1], 16), + int(guidValueList[2], 16), + int(guidValueList[3], 16), + int(guidValueList[4], 16), + int(guidValueList[5], 16), + int(guidValueList[6], 16), + int(guidValueList[7], 16), + int(guidValueList[8], 16), + int(guidValueList[9], 16), + int(guidValueList[10], 16) + ) + except: + return '' + +## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx +# +# @param GuidValue The GUID value in C structure format +# +# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format +# +def GuidStructureStringToGuidValueName(GuidValue): + guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "") + guidValueList = guidValueString.split(",") + if len(guidValueList) != 11: + EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue) + return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % ( + int(guidValueList[0], 16), + int(guidValueList[1], 16), + int(guidValueList[2], 16), + int(guidValueList[3], 16), + int(guidValueList[4], 16), + int(guidValueList[5], 16), + int(guidValueList[6], 16), + int(guidValueList[7], 16), + int(guidValueList[8], 16), + int(guidValueList[9], 16), + int(guidValueList[10], 16) + ) + +## Create directories +# +# @param Directory The directory name +# +def CreateDirectory(Directory): + if Directory is None or Directory.strip() == "": + return True + try: + if not os.access(Directory, os.F_OK): + os.makedirs(Directory) + except: + return False + return True + +## Remove directories, including files and sub-directories in it +# +# @param Directory The directory name +# +def RemoveDirectory(Directory, Recursively=False): + if Directory is None or Directory.strip() == "" or not os.path.exists(Directory): + return + if Recursively: + CurrentDirectory = os.getcwd() + os.chdir(Directory) + for File in os.listdir("."): + if os.path.isdir(File): + RemoveDirectory(File, Recursively) + else: + os.remove(File) + os.chdir(CurrentDirectory) + os.rmdir(Directory) + +## Store content in file +# +# This method is used to save file only when its content is changed. This is +# quite useful for "make" system to decide what will be re-built and what won't. +# +# @param File The path of file +# @param Content The new content of the file +# @param IsBinaryFile The flag indicating if the file is binary file or not +# +# @retval True If the file content is changed and the file is renewed +# @retval False If the file content is the same +# +def SaveFileOnChange(File, Content, IsBinaryFile=True, FileLock=None): + + # Convert to long file path format + File = LongFilePath(File) + + if os.path.exists(File): + if IsBinaryFile: + try: + with open(File, "rb") as f: + if Content == f.read(): + return False + except: + EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File) + else: + try: + with open(File, "r") as f: + if Content == f.read(): + return False + except: + EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File) + + DirName = os.path.dirname(File) + if not CreateDirectory(DirName): + EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName) + else: + if DirName == '': + DirName = os.getcwd() + if not os.access(DirName, os.W_OK): + EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName) + + OpenMode = "w" + if IsBinaryFile: + OpenMode = "wb" + + # use default file_lock if no input new lock + if not FileLock: + FileLock = GlobalData.file_lock + if FileLock: + FileLock.acquire() + + + if GlobalData.gIsWindows and not os.path.exists(File): + try: + with open(File, OpenMode) as tf: + tf.write(Content) + except IOError as X: + if GlobalData.gBinCacheSource: + EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X)) + else: + EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X) + finally: + if FileLock: + FileLock.release() + else: + try: + with open(File, OpenMode) as Fd: + Fd.write(Content) + except IOError as X: + if GlobalData.gBinCacheSource: + EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X)) + else: + EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X) + finally: + if FileLock: + FileLock.release() + + return True + +## Copy source file only if it is different from the destination file +# +# This method is used to copy file only if the source file and destination +# file content are different. This is quite useful to avoid duplicated +# file writing. +# +# @param SrcFile The path of source file +# @param Dst The path of destination file or folder +# +# @retval True The two files content are different and the file is copied +# @retval False No copy really happen +# +def CopyFileOnChange(SrcFile, Dst, FileLock=None): + + # Convert to long file path format + SrcFile = LongFilePath(SrcFile) + Dst = LongFilePath(Dst) + + if os.path.isdir(SrcFile): + EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='CopyFileOnChange SrcFile is a dir, not a file: %s' % SrcFile) + return False + + if os.path.isdir(Dst): + DstFile = os.path.join(Dst, os.path.basename(SrcFile)) + else: + DstFile = Dst + + if os.path.exists(DstFile) and filecmp.cmp(SrcFile, DstFile, shallow=False): + return False + + DirName = os.path.dirname(DstFile) + if not CreateDirectory(DirName): + EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName) + else: + if DirName == '': + DirName = os.getcwd() + if not os.access(DirName, os.W_OK): + EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName) + + # use default file_lock if no input new lock + if not FileLock: + FileLock = GlobalData.file_lock + if FileLock: + FileLock.acquire() + + try: + CopyLong(SrcFile, DstFile) + except IOError as X: + if GlobalData.gBinCacheSource: + EdkLogger.quiet("[cache error]:fails to copy file with error: %s" % (X)) + else: + EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='IOError %s' % X) + finally: + if FileLock: + FileLock.release() + + return True + +## Retrieve and cache the real path name in file system +# +# @param Root The root directory of path relative to +# +# @retval str The path string if the path exists +# @retval None If path doesn't exist +# +class DirCache: + _CACHE_ = set() + _UPPER_CACHE_ = {} + + def __init__(self, Root): + self._Root = Root + for F in os.listdir(Root): + self._CACHE_.add(F) + self._UPPER_CACHE_[F.upper()] = F + + # =[] operator + def __getitem__(self, Path): + Path = Path[len(os.path.commonprefix([Path, self._Root])):] + if not Path: + return self._Root + if Path and Path[0] == os.path.sep: + Path = Path[1:] + if Path in self._CACHE_: + return os.path.join(self._Root, Path) + UpperPath = Path.upper() + if UpperPath in self._UPPER_CACHE_: + return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath]) + + IndexList = [] + LastSepIndex = -1 + SepIndex = Path.find(os.path.sep) + while SepIndex > -1: + Parent = UpperPath[:SepIndex] + if Parent not in self._UPPER_CACHE_: + break + LastSepIndex = SepIndex + SepIndex = Path.find(os.path.sep, LastSepIndex + 1) + + if LastSepIndex == -1: + return None + + Cwd = os.getcwd() + os.chdir(self._Root) + SepIndex = LastSepIndex + while SepIndex > -1: + Parent = Path[:SepIndex] + ParentKey = UpperPath[:SepIndex] + if ParentKey not in self._UPPER_CACHE_: + os.chdir(Cwd) + return None + + if Parent in self._CACHE_: + ParentDir = Parent + else: + ParentDir = self._UPPER_CACHE_[ParentKey] + for F in os.listdir(ParentDir): + Dir = os.path.join(ParentDir, F) + self._CACHE_.add(Dir) + self._UPPER_CACHE_[Dir.upper()] = Dir + + SepIndex = Path.find(os.path.sep, SepIndex + 1) + + os.chdir(Cwd) + if Path in self._CACHE_: + return os.path.join(self._Root, Path) + elif UpperPath in self._UPPER_CACHE_: + return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath]) + return None + +def RealPath(File, Dir='', OverrideDir=''): + NewFile = os.path.normpath(os.path.join(Dir, File)) + NewFile = GlobalData.gAllFiles[NewFile] + if not NewFile and OverrideDir: + NewFile = os.path.normpath(os.path.join(OverrideDir, File)) + NewFile = GlobalData.gAllFiles[NewFile] + return NewFile + +## Get GUID value from given packages +# +# @param CName The CName of the GUID +# @param PackageList List of packages looking-up in +# @param Inffile The driver file +# +# @retval GuidValue if the CName is found in any given package +# @retval None if the CName is not found in all given packages +# +def GuidValue(CName, PackageList, Inffile = None): + for P in PackageList: + GuidKeys = list(P.Guids.keys()) + if Inffile and P._PrivateGuids: + if not Inffile.startswith(P.MetaFile.Dir): + GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids] + if CName in GuidKeys: + return P.Guids[CName] + return None + +## A string template class +# +# This class implements a template for string replacement. A string template +# looks like following +# +# ${BEGIN} other_string ${placeholder_name} other_string ${END} +# +# The string between ${BEGIN} and ${END} will be repeated as many times as the +# length of "placeholder_name", which is a list passed through a dict. The +# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can +# be not used and, in this case, the "placeholder_name" must not a list and it +# will just be replaced once. +# +class TemplateString(object): + _REPEAT_START_FLAG = "BEGIN" + _REPEAT_END_FLAG = "END" + + class Section(object): + _LIST_TYPES = [type([]), type(set()), type((0,))] + + def __init__(self, TemplateSection, PlaceHolderList): + self._Template = TemplateSection + self._PlaceHolderList = [] + + # Split the section into sub-sections according to the position of placeholders + if PlaceHolderList: + self._SubSectionList = [] + SubSectionStart = 0 + # + # The placeholders passed in must be in the format of + # + # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint + # + for PlaceHolder, Start, End in PlaceHolderList: + self._SubSectionList.append(TemplateSection[SubSectionStart:Start]) + self._SubSectionList.append(TemplateSection[Start:End]) + self._PlaceHolderList.append(PlaceHolder) + SubSectionStart = End + if SubSectionStart < len(TemplateSection): + self._SubSectionList.append(TemplateSection[SubSectionStart:]) + else: + self._SubSectionList = [TemplateSection] + + def __str__(self): + return self._Template + " : " + str(self._PlaceHolderList) + + def Instantiate(self, PlaceHolderValues): + RepeatTime = -1 + RepeatPlaceHolders = {} + NonRepeatPlaceHolders = {} + + for PlaceHolder in self._PlaceHolderList: + if PlaceHolder not in PlaceHolderValues: + continue + Value = PlaceHolderValues[PlaceHolder] + if type(Value) in self._LIST_TYPES: + if RepeatTime < 0: + RepeatTime = len(Value) + elif RepeatTime != len(Value): + EdkLogger.error( + "TemplateString", + PARAMETER_INVALID, + "${%s} has different repeat time from others!" % PlaceHolder, + ExtraData=str(self._Template) + ) + RepeatPlaceHolders["${%s}" % PlaceHolder] = Value + else: + NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value + + if NonRepeatPlaceHolders: + StringList = [] + for S in self._SubSectionList: + if S not in NonRepeatPlaceHolders: + StringList.append(S) + else: + StringList.append(str(NonRepeatPlaceHolders[S])) + else: + StringList = self._SubSectionList + + if RepeatPlaceHolders: + TempStringList = [] + for Index in range(RepeatTime): + for S in StringList: + if S not in RepeatPlaceHolders: + TempStringList.append(S) + else: + TempStringList.append(str(RepeatPlaceHolders[S][Index])) + StringList = TempStringList + + return "".join(StringList) + + ## Constructor + def __init__(self, Template=None): + self.String = [] + self.IsBinary = False + self._Template = Template + self._TemplateSectionList = self._Parse(Template) + + ## str() operator + # + # @retval string The string replaced + # + def __str__(self): + return "".join(self.String) + + ## Split the template string into fragments per the ${BEGIN} and ${END} flags + # + # @retval list A list of TemplateString.Section objects + # + def _Parse(self, Template): + SectionStart = 0 + SearchFrom = 0 + MatchEnd = 0 + PlaceHolderList = [] + TemplateSectionList = [] + while Template: + MatchObj = gPlaceholderPattern.search(Template, SearchFrom) + if not MatchObj: + if MatchEnd <= len(Template): + TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList) + TemplateSectionList.append(TemplateSection) + break + + MatchString = MatchObj.group(1) + MatchStart = MatchObj.start() + MatchEnd = MatchObj.end() + + if MatchString == self._REPEAT_START_FLAG: + if MatchStart > SectionStart: + TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList) + TemplateSectionList.append(TemplateSection) + SectionStart = MatchEnd + PlaceHolderList = [] + elif MatchString == self._REPEAT_END_FLAG: + TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList) + TemplateSectionList.append(TemplateSection) + SectionStart = MatchEnd + PlaceHolderList = [] + else: + PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart)) + SearchFrom = MatchEnd + return TemplateSectionList + + ## Replace the string template with dictionary of placeholders and append it to previous one + # + # @param AppendString The string template to append + # @param Dictionary The placeholder dictionaries + # + def Append(self, AppendString, Dictionary=None): + if Dictionary: + SectionList = self._Parse(AppendString) + self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList)) + else: + if isinstance(AppendString,list): + self.String.extend(AppendString) + else: + self.String.append(AppendString) + + ## Replace the string template with dictionary of placeholders + # + # @param Dictionary The placeholder dictionaries + # + # @retval str The string replaced with placeholder values + # + def Replace(self, Dictionary=None): + return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList) + +## Progress indicator class +# +# This class makes use of thread to print progress on console. +# +class Progressor: + # for avoiding deadloop + _StopFlag = None + _ProgressThread = None + _CheckInterval = 0.25 + + ## Constructor + # + # @param OpenMessage The string printed before progress characters + # @param CloseMessage The string printed after progress characters + # @param ProgressChar The character used to indicate the progress + # @param Interval The interval in seconds between two progress characters + # + def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0): + self.PromptMessage = OpenMessage + self.CodaMessage = CloseMessage + self.ProgressChar = ProgressChar + self.Interval = Interval + if Progressor._StopFlag is None: + Progressor._StopFlag = threading.Event() + + ## Start to print progress character + # + # @param OpenMessage The string printed before progress characters + # + def Start(self, OpenMessage=None): + if OpenMessage is not None: + self.PromptMessage = OpenMessage + Progressor._StopFlag.clear() + if Progressor._ProgressThread is None: + Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry) + Progressor._ProgressThread.setDaemon(False) + Progressor._ProgressThread.start() + + ## Stop printing progress character + # + # @param CloseMessage The string printed after progress characters + # + def Stop(self, CloseMessage=None): + OriginalCodaMessage = self.CodaMessage + if CloseMessage is not None: + self.CodaMessage = CloseMessage + self.Abort() + self.CodaMessage = OriginalCodaMessage + + ## Thread entry method + def _ProgressThreadEntry(self): + sys.stdout.write(self.PromptMessage + " ") + sys.stdout.flush() + TimeUp = 0.0 + while not Progressor._StopFlag.isSet(): + if TimeUp <= 0.0: + sys.stdout.write(self.ProgressChar) + sys.stdout.flush() + TimeUp = self.Interval + time.sleep(self._CheckInterval) + TimeUp -= self._CheckInterval + sys.stdout.write(" " + self.CodaMessage + "\n") + sys.stdout.flush() + + ## Abort the progress display + @staticmethod + def Abort(): + if Progressor._StopFlag is not None: + Progressor._StopFlag.set() + if Progressor._ProgressThread is not None: + Progressor._ProgressThread.join() + Progressor._ProgressThread = None + + +## Dictionary using prioritized list as key +# +class tdict: + _ListType = type([]) + _TupleType = type(()) + _Wildcard = 'COMMON' + _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', TAB_STAR, 'PLATFORM'] + + def __init__(self, _Single_=False, _Level_=2): + self._Level_ = _Level_ + self.data = {} + self._Single_ = _Single_ + + # =[] operator + def __getitem__(self, key): + KeyType = type(key) + RestKeys = None + if KeyType == self._ListType or KeyType == self._TupleType: + FirstKey = key[0] + if len(key) > 1: + RestKeys = key[1:] + elif self._Level_ > 1: + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] + else: + FirstKey = key + if self._Level_ > 1: + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] + + if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList: + FirstKey = self._Wildcard + + if self._Single_: + return self._GetSingleValue(FirstKey, RestKeys) + else: + return self._GetAllValues(FirstKey, RestKeys) + + def _GetSingleValue(self, FirstKey, RestKeys): + Value = None + #print "%s-%s" % (FirstKey, self._Level_) , + if self._Level_ > 1: + if FirstKey == self._Wildcard: + if FirstKey in self.data: + Value = self.data[FirstKey][RestKeys] + if Value is None: + for Key in self.data: + Value = self.data[Key][RestKeys] + if Value is not None: break + else: + if FirstKey in self.data: + Value = self.data[FirstKey][RestKeys] + if Value is None and self._Wildcard in self.data: + #print "Value=None" + Value = self.data[self._Wildcard][RestKeys] + else: + if FirstKey == self._Wildcard: + if FirstKey in self.data: + Value = self.data[FirstKey] + if Value is None: + for Key in self.data: + Value = self.data[Key] + if Value is not None: break + else: + if FirstKey in self.data: + Value = self.data[FirstKey] + elif self._Wildcard in self.data: + Value = self.data[self._Wildcard] + return Value + + def _GetAllValues(self, FirstKey, RestKeys): + Value = [] + if self._Level_ > 1: + if FirstKey == self._Wildcard: + for Key in self.data: + Value += self.data[Key][RestKeys] + else: + if FirstKey in self.data: + Value += self.data[FirstKey][RestKeys] + if self._Wildcard in self.data: + Value += self.data[self._Wildcard][RestKeys] + else: + if FirstKey == self._Wildcard: + for Key in self.data: + Value.append(self.data[Key]) + else: + if FirstKey in self.data: + Value.append(self.data[FirstKey]) + if self._Wildcard in self.data: + Value.append(self.data[self._Wildcard]) + return Value + + ## []= operator + def __setitem__(self, key, value): + KeyType = type(key) + RestKeys = None + if KeyType == self._ListType or KeyType == self._TupleType: + FirstKey = key[0] + if len(key) > 1: + RestKeys = key[1:] + else: + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] + else: + FirstKey = key + if self._Level_ > 1: + RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] + + if FirstKey in self._ValidWildcardList: + FirstKey = self._Wildcard + + if FirstKey not in self.data and self._Level_ > 0: + self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1) + + if self._Level_ > 1: + self.data[FirstKey][RestKeys] = value + else: + self.data[FirstKey] = value + + def SetGreedyMode(self): + self._Single_ = False + if self._Level_ > 1: + for Key in self.data: + self.data[Key].SetGreedyMode() + + def SetSingleMode(self): + self._Single_ = True + if self._Level_ > 1: + for Key in self.data: + self.data[Key].SetSingleMode() + + def GetKeys(self, KeyIndex=0): + assert KeyIndex >= 0 + if KeyIndex == 0: + return set(self.data.keys()) + else: + keys = set() + for Key in self.data: + keys |= self.data[Key].GetKeys(KeyIndex - 1) + return keys + +def AnalyzePcdExpression(Setting): + RanStr = ''.join(sample(string.ascii_letters + string.digits, 8)) + Setting = Setting.replace('\\\\', RanStr).strip() + # There might be escaped quote in a string: \", \\\" , \', \\\' + Data = Setting + # There might be '|' in string and in ( ... | ... ), replace it with '-' + NewStr = '' + InSingleQuoteStr = False + InDoubleQuoteStr = False + Pair = 0 + for Index, ch in enumerate(Data): + if ch == '"' and not InSingleQuoteStr: + if Data[Index - 1] != '\\': + InDoubleQuoteStr = not InDoubleQuoteStr + elif ch == "'" and not InDoubleQuoteStr: + if Data[Index - 1] != '\\': + InSingleQuoteStr = not InSingleQuoteStr + elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr): + Pair += 1 + elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr): + Pair -= 1 + + if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT: + NewStr += '-' + else: + NewStr += ch + FieldList = [] + StartPos = 0 + while True: + Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos) + if Pos < 0: + FieldList.append(Setting[StartPos:].strip()) + break + FieldList.append(Setting[StartPos:Pos].strip()) + StartPos = Pos + 1 + for i, ch in enumerate(FieldList): + if RanStr in ch: + FieldList[i] = ch.replace(RanStr,'\\\\') + return FieldList + +def ParseFieldValue (Value): + def ParseDevPathValue (Value): + if '\\' in Value: + Value.replace('\\', '/').replace(' ', '') + + Cmd = 'DevicePath ' + '"' + Value + '"' + try: + p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + out, err = p.communicate() + except Exception as X: + raise BadExpression("DevicePath: %s" % (str(X)) ) + finally: + subprocess._cleanup() + p.stdout.close() + p.stderr.close() + if err: + raise BadExpression("DevicePath: %s" % str(err)) + out = out.decode() + Size = len(out.split()) + out = ','.join(out.split()) + return '{' + out + '}', Size + + if "{CODE(" in Value: + return Value, len(Value.split(",")) + if isinstance(Value, type(0)): + return Value, (Value.bit_length() + 7) // 8 + if not isinstance(Value, type('')): + raise BadExpression('Type %s is %s' %(Value, type(Value))) + Value = Value.strip() + if Value.startswith(TAB_UINT8) and Value.endswith(')'): + Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) + if Size > 1: + raise BadExpression('Value (%s) Size larger than %d' %(Value, Size)) + return Value, 1 + if Value.startswith(TAB_UINT16) and Value.endswith(')'): + Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) + if Size > 2: + raise BadExpression('Value (%s) Size larger than %d' %(Value, Size)) + return Value, 2 + if Value.startswith(TAB_UINT32) and Value.endswith(')'): + Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) + if Size > 4: + raise BadExpression('Value (%s) Size larger than %d' %(Value, Size)) + return Value, 4 + if Value.startswith(TAB_UINT64) and Value.endswith(')'): + Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1]) + if Size > 8: + raise BadExpression('Value (%s) Size larger than %d' % (Value, Size)) + return Value, 8 + if Value.startswith(TAB_GUID) and Value.endswith(')'): + Value = Value.split('(', 1)[1][:-1].strip() + if Value[0] == '{' and Value[-1] == '}': + TmpValue = GuidStructureStringToGuidString(Value) + if not TmpValue: + raise BadExpression("Invalid GUID value string %s" % Value) + Value = TmpValue + if Value[0] == '"' and Value[-1] == '"': + Value = Value[1:-1] + try: + Value = str(uuid.UUID(Value).bytes_le) + if Value.startswith("b'"): + Value = Value[2:-1] + Value = "'" + Value + "'" + except ValueError as Message: + raise BadExpression(Message) + Value, Size = ParseFieldValue(Value) + return Value, 16 + if Value.startswith('L"') and Value.endswith('"'): + # Unicode String + # translate escape character + Value = Value[1:] + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) + List.reverse() + Value = 0 + for Char in List: + Value = (Value << 16) | ord(Char) + return Value, (len(List) + 1) * 2 + if Value.startswith('"') and Value.endswith('"'): + # ASCII String + # translate escape character + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) + List.reverse() + Value = 0 + for Char in List: + Value = (Value << 8) | ord(Char) + return Value, len(List) + 1 + if Value.startswith("L'") and Value.endswith("'"): + # Unicode Character Constant + # translate escape character + Value = Value[1:] + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) + if len(List) == 0: + raise BadExpression('Length %s is %s' % (Value, len(List))) + List.reverse() + Value = 0 + for Char in List: + Value = (Value << 16) | ord(Char) + return Value, len(List) * 2 + if Value.startswith("'") and Value.endswith("'"): + # Character constant + # translate escape character + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) + if len(List) == 0: + raise BadExpression('Length %s is %s' % (Value, len(List))) + List.reverse() + Value = 0 + for Char in List: + Value = (Value << 8) | ord(Char) + return Value, len(List) + if Value.startswith('{') and Value.endswith('}'): + # Byte array + Value = Value[1:-1] + List = [Item.strip() for Item in Value.split(',')] + List.reverse() + Value = 0 + RetSize = 0 + for Item in List: + ItemValue, Size = ParseFieldValue(Item) + RetSize += Size + for I in range(Size): + Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff) + return Value, RetSize + if Value.startswith('DEVICE_PATH(') and Value.endswith(')'): + Value = Value.replace("DEVICE_PATH(", '').rstrip(')') + Value = Value.strip().strip('"') + return ParseDevPathValue(Value) + if Value.lower().startswith('0x'): + try: + Value = int(Value, 16) + except: + raise BadExpression("invalid hex value: %s" % Value) + if Value == 0: + return 0, 1 + return Value, (Value.bit_length() + 7) // 8 + if Value[0].isdigit(): + Value = int(Value, 10) + if Value == 0: + return 0, 1 + return Value, (Value.bit_length() + 7) // 8 + if Value.lower() == 'true': + return 1, 1 + if Value.lower() == 'false': + return 0, 1 + return Value, 1 + +## AnalyzeDscPcd +# +# Analyze DSC PCD value, since there is no data type info in DSC +# This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database +# 1. Feature flag: TokenSpace.PcdCName|PcdValue +# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]] +# 3. Dynamic default: +# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]] +# TokenSpace.PcdCName|PcdValue +# 4. Dynamic VPD: +# TokenSpace.PcdCName|VpdOffset[|VpdValue] +# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]] +# 5. Dynamic HII: +# TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue] +# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which +# there might have "|" operator, also in string value. +# +# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped +# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII +# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL +# @retval: +# ValueList: A List contain fields described above +# IsValid: True if conforming EBNF, otherwise False +# Index: The index where PcdValue is in ValueList +# +def AnalyzeDscPcd(Setting, PcdType, DataType=''): + FieldList = AnalyzePcdExpression(Setting) + + IsValid = True + if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT): + Value = FieldList[0] + Size = '' + if len(FieldList) > 1 and FieldList[1]: + DataType = FieldList[1] + if FieldList[1] != TAB_VOID and StructPattern.match(FieldList[1]) is None: + IsValid = False + if len(FieldList) > 2: + Size = FieldList[2] + if IsValid: + if DataType == "": + IsValid = (len(FieldList) <= 1) + else: + IsValid = (len(FieldList) <= 3) + + if Size: + try: + int(Size, 16) if Size.upper().startswith("0X") else int(Size) + except: + IsValid = False + Size = -1 + return [str(Value), DataType, str(Size)], IsValid, 0 + elif PcdType == MODEL_PCD_FEATURE_FLAG: + Value = FieldList[0] + Size = '' + IsValid = (len(FieldList) <= 1) + return [Value, DataType, str(Size)], IsValid, 0 + elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD): + VpdOffset = FieldList[0] + Value = Size = '' + if not DataType == TAB_VOID: + if len(FieldList) > 1: + Value = FieldList[1] + else: + if len(FieldList) > 1: + Size = FieldList[1] + if len(FieldList) > 2: + Value = FieldList[2] + if DataType == "": + IsValid = (len(FieldList) <= 1) + else: + IsValid = (len(FieldList) <= 3) + if Size: + try: + int(Size, 16) if Size.upper().startswith("0X") else int(Size) + except: + IsValid = False + Size = -1 + return [VpdOffset, str(Size), Value], IsValid, 2 + elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII): + IsValid = (3 <= len(FieldList) <= 5) + HiiString = FieldList[0] + Guid = Offset = Value = Attribute = '' + if len(FieldList) > 1: + Guid = FieldList[1] + if len(FieldList) > 2: + Offset = FieldList[2] + if len(FieldList) > 3: + Value = FieldList[3] + if len(FieldList) > 4: + Attribute = FieldList[4] + return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3 + return [], False, 0 + +## AnalyzePcdData +# +# Analyze the pcd Value, Datum type and TokenNumber. +# Used to avoid split issue while the value string contain "|" character +# +# @param[in] Setting: A String contain value/datum type/token number information; +# +# @retval ValueList: A List contain value, datum type and toke number. +# +def AnalyzePcdData(Setting): + ValueList = ['', '', ''] + + ValueRe = re.compile(r'^\s*L?\".*\|.*\"') + PtrValue = ValueRe.findall(Setting) + + ValueUpdateFlag = False + + if len(PtrValue) >= 1: + Setting = re.sub(ValueRe, '', Setting) + ValueUpdateFlag = True + + TokenList = Setting.split(TAB_VALUE_SPLIT) + ValueList[0:len(TokenList)] = TokenList + + if ValueUpdateFlag: + ValueList[0] = PtrValue[0] + + return ValueList + +## check format of PCD value against its the datum type +# +# For PCD value setting +# +def CheckPcdDatum(Type, Value): + if Type == TAB_VOID: + ValueRe = re.compile(r'\s*L?\".*\"\s*$') + if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"')) + or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'")) + ): + return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\ + ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type) + elif ValueRe.match(Value): + # Check the chars in UnicodeString or CString is printable + if Value.startswith("L"): + Value = Value[2:-1] + else: + Value = Value[1:-1] + Printset = set(string.printable) + Printset.remove(TAB_PRINTCHAR_VT) + Printset.add(TAB_PRINTCHAR_BS) + Printset.add(TAB_PRINTCHAR_NUL) + if not set(Value).issubset(Printset): + PrintList = sorted(Printset) + return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList) + elif Type == 'BOOLEAN': + if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']: + return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\ + ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type) + elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]: + if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'): + Value = Value.lstrip('0') + try: + if Value and int(Value, 0) < 0: + return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value, Type) + Value = int(Value, 0) + if Value > MAX_VAL_TYPE[Type]: + return False, "Too large PCD value[%s] for datum type [%s]" % (Value, Type) + except: + return False, "Invalid value [%s] of type [%s];"\ + " must be a hexadecimal, decimal or octal in C language format." % (Value, Type) + else: + return True, "StructurePcd" + + return True, "" + +def CommonPath(PathList): + P1 = min(PathList).split(os.path.sep) + P2 = max(PathList).split(os.path.sep) + for Index in range(min(len(P1), len(P2))): + if P1[Index] != P2[Index]: + return os.path.sep.join(P1[:Index]) + return os.path.sep.join(P1) + +class PathClass(object): + def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, + Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''): + self.Arch = Arch + self.File = str(File) + if os.path.isabs(self.File): + self.Root = '' + self.AlterRoot = '' + else: + self.Root = str(Root) + self.AlterRoot = str(AlterRoot) + + # Remove any '.' and '..' in path + if self.Root: + self.Root = mws.getWs(self.Root, self.File) + self.Path = os.path.normpath(os.path.join(self.Root, self.File)) + self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) + # eliminate the side-effect of 'C:' + if self.Root[-1] == ':': + self.Root += os.path.sep + # file path should not start with path separator + if self.Root[-1] == os.path.sep: + self.File = self.Path[len(self.Root):] + else: + self.File = self.Path[len(self.Root) + 1:] + else: + self.Path = os.path.normpath(self.File) + + self.SubDir, self.Name = os.path.split(self.File) + self.BaseName, self.Ext = os.path.splitext(self.Name) + + if self.Root: + if self.SubDir: + self.Dir = os.path.join(self.Root, self.SubDir) + else: + self.Dir = self.Root + else: + self.Dir = self.SubDir + + if IsBinary: + self.Type = Type + else: + self.Type = self.Ext.lower() + + self.IsBinary = IsBinary + self.Target = Target + self.TagName = TagName + self.ToolCode = ToolCode + self.ToolChainFamily = ToolChainFamily + self.OriginalPath = self + + ## Convert the object of this class to a string + # + # Convert member Path of the class to a string + # + # @retval string Formatted String + # + def __str__(self): + return self.Path + + ## Override __eq__ function + # + # Check whether PathClass are the same + # + # @retval False The two PathClass are different + # @retval True The two PathClass are the same + # + def __eq__(self, Other): + return self.Path == str(Other) + + ## Override __cmp__ function + # + # Customize the comparison operation of two PathClass + # + # @retval 0 The two PathClass are different + # @retval -1 The first PathClass is less than the second PathClass + # @retval 1 The first PathClass is Bigger than the second PathClass + def __cmp__(self, Other): + OtherKey = str(Other) + + SelfKey = self.Path + if SelfKey == OtherKey: + return 0 + elif SelfKey > OtherKey: + return 1 + else: + return -1 + + ## Override __hash__ function + # + # Use Path as key in hash table + # + # @retval string Key for hash table + # + def __hash__(self): + return hash(self.Path) + + @cached_property + def Key(self): + return self.Path.upper() + + @property + def TimeStamp(self): + return os.stat(self.Path)[8] + + def Validate(self, Type='', CaseSensitive=True): + def RealPath2(File, Dir='', OverrideDir=''): + NewFile = None + if OverrideDir: + NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))] + if NewFile: + if OverrideDir[-1] == os.path.sep: + return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] + else: + return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)] + if GlobalData.gAllFiles: + NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))] + if not NewFile: + NewFile = os.path.normpath(os.path.join(Dir, File)) + if not os.path.exists(NewFile): + return None, None + if NewFile: + if Dir: + if Dir[-1] == os.path.sep: + return NewFile[len(Dir):], NewFile[0:len(Dir)] + else: + return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] + else: + return NewFile, '' + + return None, None + + if GlobalData.gCaseInsensitive: + CaseSensitive = False + if Type and Type.lower() != self.Type: + return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type) + + RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) + if not RealRoot and not RealFile: + RealFile = self.File + if self.AlterRoot: + RealFile = os.path.join(self.AlterRoot, self.File) + elif self.Root: + RealFile = os.path.join(self.Root, self.File) + if len (mws.getPkgPath()) == 0: + return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + else: + return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath())) + + ErrorCode = 0 + ErrorInfo = '' + if RealRoot != self.Root or RealFile != self.File: + if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)): + ErrorCode = FILE_CASE_MISMATCH + ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]" + + self.SubDir, self.Name = os.path.split(RealFile) + self.BaseName, self.Ext = os.path.splitext(self.Name) + if self.SubDir: + self.Dir = os.path.join(RealRoot, self.SubDir) + else: + self.Dir = RealRoot + self.File = RealFile + self.Root = RealRoot + self.Path = os.path.join(RealRoot, RealFile) + return ErrorCode, ErrorInfo + +## Parse PE image to get the required PE information. +# +class PeImageClass(): + ## Constructor + # + # @param File FilePath of PeImage + # + def __init__(self, PeFile): + self.FileName = PeFile + self.IsValid = False + self.Size = 0 + self.EntryPoint = 0 + self.SectionAlignment = 0 + self.SectionHeaderList = [] + self.ErrorInfo = '' + try: + PeObject = open(PeFile, 'rb') + except: + self.ErrorInfo = self.FileName + ' can not be found\n' + return + # Read DOS header + ByteArray = array.array('B') + ByteArray.fromfile(PeObject, 0x3E) + ByteList = ByteArray.tolist() + # DOS signature should be 'MZ' + if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ': + self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ' + return + + # Read 4 byte PE Signature + PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E]) + PeObject.seek(PeOffset) + ByteArray = array.array('B') + ByteArray.fromfile(PeObject, 4) + # PE signature should be 'PE\0\0' + if ByteArray.tostring() != b'PE\0\0': + self.ErrorInfo = self.FileName + ' has no valid PE signature PE00' + return + + # Read PE file header + ByteArray = array.array('B') + ByteArray.fromfile(PeObject, 0x14) + ByteList = ByteArray.tolist() + SecNumber = self._ByteListToInt(ByteList[0x2:0x4]) + if SecNumber == 0: + self.ErrorInfo = self.FileName + ' has no section header' + return + + # Read PE optional header + OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12]) + ByteArray = array.array('B') + ByteArray.fromfile(PeObject, OptionalHeaderSize) + ByteList = ByteArray.tolist() + self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14]) + self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24]) + self.Size = self._ByteListToInt(ByteList[0x38:0x3C]) + + # Read each Section Header + for Index in range(SecNumber): + ByteArray = array.array('B') + ByteArray.fromfile(PeObject, 0x28) + ByteList = ByteArray.tolist() + SecName = self._ByteListToStr(ByteList[0:8]) + SecVirtualSize = self._ByteListToInt(ByteList[8:12]) + SecRawAddress = self._ByteListToInt(ByteList[20:24]) + SecVirtualAddress = self._ByteListToInt(ByteList[12:16]) + self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize)) + self.IsValid = True + PeObject.close() + + def _ByteListToStr(self, ByteList): + String = '' + for index in range(len(ByteList)): + if ByteList[index] == 0: + break + String += chr(ByteList[index]) + return String + + def _ByteListToInt(self, ByteList): + Value = 0 + for index in range(len(ByteList) - 1, -1, -1): + Value = (Value << 8) | int(ByteList[index]) + return Value + +class DefaultStore(): + def __init__(self, DefaultStores ): + + self.DefaultStores = DefaultStores + def DefaultStoreID(self, DefaultStoreName): + for key, value in self.DefaultStores.items(): + if value == DefaultStoreName: + return key + return None + def GetDefaultDefault(self): + if not self.DefaultStores or "0" in self.DefaultStores: + return "0", TAB_DEFAULT_STORES_DEFAULT + else: + minvalue = min(int(value_str) for value_str in self.DefaultStores) + return (str(minvalue), self.DefaultStores[str(minvalue)]) + def GetMin(self, DefaultSIdList): + if not DefaultSIdList: + return TAB_DEFAULT_STORES_DEFAULT + storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList} + if not storeidset: + return "" + minid = min(storeidset ) + for sid, name in self.DefaultStores.values(): + if sid == minid: + return name + +class SkuClass(): + DEFAULT = 0 + SINGLE = 1 + MULTIPLE =2 + + def __init__(self,SkuIdentifier='', SkuIds=None): + if SkuIds is None: + SkuIds = {} + + for SkuName in SkuIds: + SkuId = SkuIds[SkuName][0] + skuid_num = int(SkuId, 16) if SkuId.upper().startswith("0X") else int(SkuId) + if skuid_num > 0xFFFFFFFFFFFFFFFF: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64" + % (SkuName, SkuId)) + + self.AvailableSkuIds = OrderedDict() + self.SkuIdSet = [] + self.SkuIdNumberSet = [] + self.SkuData = SkuIds + self._SkuInherit = {} + self._SkuIdentifier = SkuIdentifier + if SkuIdentifier == '' or SkuIdentifier is None: + self.SkuIdSet = ['DEFAULT'] + self.SkuIdNumberSet = ['0U'] + elif SkuIdentifier == 'ALL': + self.SkuIdSet = list(SkuIds.keys()) + self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()] + else: + r = SkuIdentifier.split('|') + self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))] + k = None + try: + self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet] + except Exception: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]" + % (k, " | ".join(SkuIds.keys()))) + for each in self.SkuIdSet: + if each in SkuIds: + self.AvailableSkuIds[each] = SkuIds[each][0] + else: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]" + % (each, " | ".join(SkuIds.keys()))) + if self.SkuUsageType != SkuClass.SINGLE: + self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0}) + if self.SkuIdSet: + GlobalData.gSkuids = (self.SkuIdSet) + if 'COMMON' in GlobalData.gSkuids: + GlobalData.gSkuids.remove('COMMON') + if self.SkuUsageType == self.SINGLE: + if len(GlobalData.gSkuids) != 1: + if 'DEFAULT' in GlobalData.gSkuids: + GlobalData.gSkuids.remove('DEFAULT') + if GlobalData.gSkuids: + GlobalData.gSkuids.sort() + + def GetNextSkuId(self, skuname): + if not self._SkuInherit: + self._SkuInherit = {} + for item in self.SkuData.values(): + self._SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT" + return self._SkuInherit.get(skuname, "DEFAULT") + + def GetSkuChain(self, sku): + if sku == "DEFAULT": + return ["DEFAULT"] + skulist = [sku] + nextsku = sku + while True: + nextsku = self.GetNextSkuId(nextsku) + skulist.append(nextsku) + if nextsku == "DEFAULT": + break + skulist.reverse() + return skulist + def SkuOverrideOrder(self): + skuorderset = [] + for skuname in self.SkuIdSet: + skuorderset.append(self.GetSkuChain(skuname)) + + skuorder = [] + for index in range(max(len(item) for item in skuorderset)): + for subset in skuorderset: + if index > len(subset)-1: + continue + if subset[index] in skuorder: + continue + skuorder.append(subset[index]) + + return skuorder + + @property + def SkuUsageType(self): + if self._SkuIdentifier.upper() == "ALL": + return SkuClass.MULTIPLE + + if len(self.SkuIdSet) == 1: + if self.SkuIdSet[0] == 'DEFAULT': + return SkuClass.DEFAULT + return SkuClass.SINGLE + if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet: + return SkuClass.SINGLE + return SkuClass.MULTIPLE + + def DumpSkuIdArrary(self): + if self.SkuUsageType == SkuClass.SINGLE: + return "{0x0}" + ArrayStrList = [] + for skuname in self.AvailableSkuIds: + if skuname == "COMMON": + continue + while skuname != "DEFAULT": + ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname]))) + skuname = self.GetNextSkuId(skuname) + ArrayStrList.append("0x0") + return "{{{myList}}}".format(myList=",".join(ArrayStrList)) + + @property + def AvailableSkuIdSet(self): + return self.AvailableSkuIds + + @property + def SystemSkuId(self): + if self.SkuUsageType == SkuClass.SINGLE: + if len(self.SkuIdSet) == 1: + return self.SkuIdSet[0] + else: + return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1] + else: + return 'DEFAULT' + +## Get the integer value from string like "14U" or integer like 2 +# +# @param Input The object that may be either a integer value or a string +# +# @retval Value The integer value that the input represents +# +def GetIntegerValue(Input): + if not isinstance(Input, str): + return Input + String = Input + if String.endswith("U"): + String = String[:-1] + if String.endswith("ULL"): + String = String[:-3] + if String.endswith("LL"): + String = String[:-2] + + if String.startswith("0x") or String.startswith("0X"): + return int(String, 16) + elif String == '': + return 0 + else: + return int(String) + +# +# Pack a GUID (registry format) list into a buffer and return it +# +def PackGUID(Guid): + return pack(PACK_PATTERN_GUID, + int(Guid[0], 16), + int(Guid[1], 16), + int(Guid[2], 16), + int(Guid[3][-4:-2], 16), + int(Guid[3][-2:], 16), + int(Guid[4][-12:-10], 16), + int(Guid[4][-10:-8], 16), + int(Guid[4][-8:-6], 16), + int(Guid[4][-6:-4], 16), + int(Guid[4][-4:-2], 16), + int(Guid[4][-2:], 16) + ) + +# +# Pack a GUID (byte) list into a buffer and return it +# +def PackByteFormatGUID(Guid): + return pack(PACK_PATTERN_GUID, + Guid[0], + Guid[1], + Guid[2], + Guid[3], + Guid[4], + Guid[5], + Guid[6], + Guid[7], + Guid[8], + Guid[9], + Guid[10], + ) + +## DeepCopy dict/OrderedDict recusively +# +# @param ori_dict a nested dict or ordereddict +# +# @retval new dict or orderdict +# +def CopyDict(ori_dict): + dict_type = ori_dict.__class__ + if dict_type not in (dict,OrderedDict): + return ori_dict + new_dict = dict_type() + for key in ori_dict: + if isinstance(ori_dict[key],(dict,OrderedDict)): + new_dict[key] = CopyDict(ori_dict[key]) + else: + new_dict[key] = ori_dict[key] + return new_dict + +# +# Remove the c/c++ comments: // and /* */ +# +def RemoveCComments(ctext): + return re.sub('//.*?\n|/\*.*?\*/', '\n', ctext, flags=re.S) diff --git a/tools/python/Common/MultipleWorkspace.py b/tools/python/Common/MultipleWorkspace.py new file mode 100755 index 0000000..ad5d485 --- /dev/null +++ b/tools/python/Common/MultipleWorkspace.py @@ -0,0 +1,150 @@ +## @file +# manage multiple workspace file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import Common.LongFilePathOs as os +from Common.DataType import TAB_WORKSPACE + +## MultipleWorkspace +# +# This class manage multiple workspace behavior +# +# @param class: +# +# @var WORKSPACE: defined the current WORKSPACE +# @var PACKAGES_PATH: defined the other WORKSPACE, if current WORKSPACE is invalid, search valid WORKSPACE from PACKAGES_PATH +# +class MultipleWorkspace(object): + WORKSPACE = '' + PACKAGES_PATH = None + + ## convertPackagePath() + # + # Convert path to match workspace. + # + # @param cls The class pointer + # @param Ws The current WORKSPACE + # @param Path Path to be converted to match workspace. + # + @classmethod + def convertPackagePath(cls, Ws, Path): + if str(os.path.normcase (Path)).startswith(Ws): + return os.path.join(Ws, os.path.relpath(Path, Ws)) + return Path + + ## setWs() + # + # set WORKSPACE and PACKAGES_PATH environment + # + # @param cls The class pointer + # @param Ws initialize WORKSPACE variable + # @param PackagesPath initialize PackagesPath variable + # + @classmethod + def setWs(cls, Ws, PackagesPath=None): + cls.WORKSPACE = Ws + if PackagesPath: + cls.PACKAGES_PATH = [cls.convertPackagePath (Ws, os.path.normpath(Path.strip())) for Path in PackagesPath.split(os.pathsep)] + else: + cls.PACKAGES_PATH = [] + + ## join() + # + # rewrite os.path.join function + # + # @param cls The class pointer + # @param Ws the current WORKSPACE + # @param *p path of the inf/dec/dsc/fdf/conf file + # @retval Path the absolute path of specified file + # + @classmethod + def join(cls, Ws, *p): + Path = os.path.join(Ws, *p) + if not os.path.exists(Path): + for Pkg in cls.PACKAGES_PATH: + Path = os.path.join(Pkg, *p) + if os.path.exists(Path): + return Path + Path = os.path.join(Ws, *p) + return Path + + ## relpath() + # + # rewrite os.path.relpath function + # + # @param cls The class pointer + # @param Path path of the inf/dec/dsc/fdf/conf file + # @param Ws the current WORKSPACE + # @retval Path the relative path of specified file + # + @classmethod + def relpath(cls, Path, Ws): + for Pkg in cls.PACKAGES_PATH: + if Path.lower().startswith(Pkg.lower()): + Path = os.path.relpath(Path, Pkg) + return Path + if Path.lower().startswith(Ws.lower()): + Path = os.path.relpath(Path, Ws) + return Path + + ## getWs() + # + # get valid workspace for the path + # + # @param cls The class pointer + # @param Ws the current WORKSPACE + # @param Path path of the inf/dec/dsc/fdf/conf file + # @retval Ws the valid workspace relative to the specified file path + # + @classmethod + def getWs(cls, Ws, Path): + absPath = os.path.join(Ws, Path) + if not os.path.exists(absPath): + for Pkg in cls.PACKAGES_PATH: + absPath = os.path.join(Pkg, Path) + if os.path.exists(absPath): + return Pkg + return Ws + + ## handleWsMacro() + # + # handle the $(WORKSPACE) tag, if current workspace is invalid path relative the tool, replace it. + # + # @param cls The class pointer + # @retval PathStr Path string include the $(WORKSPACE) + # + @classmethod + def handleWsMacro(cls, PathStr): + if TAB_WORKSPACE in PathStr: + PathList = PathStr.split() + if PathList: + for i, str in enumerate(PathList): + MacroStartPos = str.find(TAB_WORKSPACE) + if MacroStartPos != -1: + Substr = str[MacroStartPos:] + Path = Substr.replace(TAB_WORKSPACE, cls.WORKSPACE).strip() + if not os.path.exists(Path): + for Pkg in cls.PACKAGES_PATH: + Path = Substr.replace(TAB_WORKSPACE, Pkg).strip() + if os.path.exists(Path): + break + PathList[i] = str[0:MacroStartPos] + Path + PathStr = ' '.join(PathList) + return PathStr + + ## getPkgPath() + # + # get all package paths. + # + # @param cls The class pointer + # + @classmethod + def getPkgPath(cls): + return cls.PACKAGES_PATH + diff --git a/tools/python/Common/Parsing.py b/tools/python/Common/Parsing.py new file mode 100755 index 0000000..740283a --- /dev/null +++ b/tools/python/Common/Parsing.py @@ -0,0 +1,906 @@ +## @file +# This file is used to define common parsing related functions used in parsing INF/DEC/DSC process +# +# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from .StringUtils import * +from CommonDataClass.DataClass import * +from .DataType import * + +## ParseDefineMacro +# +# Search whole table to find all defined Macro and replaced them with the real values +# +def ParseDefineMacro2(Table, RecordSets, GlobalMacro): + Macros = {} + # + # Find all DEFINE macros in section [Header] and its section + # + SqlCommand = """select Value1, Value2, BelongsToItem, StartLine, Arch from %s + where Model = %s + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE) + RecordSet = Table.Exec(SqlCommand) + for Record in RecordSet: + Macros[Record[0]] = Record[1] + + # + # Overridden by Global Macros + # + Macros.update(GlobalMacro) + + # + # Replace the Macros + # + for Value in (v for v in RecordSets.values() if v): + for Item in Value: + Item[0] = ReplaceMacro(Item[0], Macros) + +## ParseDefineMacro +# +# Search whole table to find all defined Macro and replaced them with the real values +# +def ParseDefineMacro(Table, GlobalMacro): + Macros = {} + # + # Find all DEFINE macros + # + SqlCommand = """select Value1, Value2, BelongsToItem, StartLine, Arch from %s + where Model = %s + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE) + RecordSet = Table.Exec(SqlCommand) + for Record in RecordSet: +#*************************************************************************************************************************************************** +# The follow SqlCommand (expr replace) is not supported in Sqlite 3.3.4 which is used in Python 2.5 * +# Reserved Only * +# SqlCommand = """update %s set Value1 = replace(Value1, '%s', '%s') * +# where ID in (select ID from %s * +# where Model = %s * +# and Value1 like '%%%s%%' * +# and StartLine > %s * +# and Enabled > -1 * +# and Arch = '%s')""" % \ * +# (self.TblDsc.Table, Record[0], Record[1], self.TblDsc.Table, Record[2], Record[1], Record[3], Record[4]) * +#*************************************************************************************************************************************************** + Macros[Record[0]] = Record[1] + + # + # Overridden by Global Macros + # + Macros.update(GlobalMacro) + + # + # Found all defined macro and replaced + # + SqlCommand = """select ID, Value1 from %s + where Model != %s + and Value1 like '%%$(%%' and Value1 like '%%)%%' + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE) + FoundRecords = Table.Exec(SqlCommand) + for FoundRecord in FoundRecords: + NewValue = ReplaceMacro(FoundRecord[1], Macros) + SqlCommand = """update %s set Value1 = '%s' + where ID = %s""" % (Table.Table, ConvertToSqlString2(NewValue), FoundRecord[0]) + Table.Exec(SqlCommand) + +##QueryDefinesItem +# +# Search item of section [Defines] by name, return its values +# +# @param Table: The Table to be executed +# @param Name: The Name of item of section [Defines] +# @param Arch: The Arch of item of section [Defines] +# +# @retval RecordSet: A list of all matched records +# +def QueryDefinesItem(Table, Name, Arch, BelongsToFile): + SqlCommand = """select Value2 from %s + where Model = %s + and Value1 = '%s' + and Arch = '%s' + and BelongsToFile = %s + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(Arch), BelongsToFile) + RecordSet = Table.Exec(SqlCommand) + if len(RecordSet) < 1: + SqlCommand = """select Value2 from %s + where Model = %s + and Value1 = '%s' + and Arch = '%s' + and BelongsToFile = %s + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(TAB_ARCH_COMMON.upper()), BelongsToFile) + RecordSet = Table.Exec(SqlCommand) + if len(RecordSet) == 1: + if Name == TAB_INF_DEFINES_LIBRARY_CLASS: + return [RecordSet[0][0]] + else: + return GetSplitValueList(RecordSet[0][0]) + elif len(RecordSet) < 1: + return [''] + elif len(RecordSet) > 1: + RetVal = [] + for Record in RecordSet: + if Name == TAB_INF_DEFINES_LIBRARY_CLASS: + RetVal.append(Record[0]) + else: + Items = GetSplitValueList(Record[0]) + for Item in Items: + RetVal.append(Item) + return RetVal + +##QueryDefinesItem +# +# Search item of section [Defines] by name, return its values +# +# @param Table: The Table to be executed +# @param Name: The Name of item of section [Defines] +# @param Arch: The Arch of item of section [Defines] +# +# @retval RecordSet: A list of all matched records +# +def QueryDefinesItem2(Table, Arch, BelongsToFile): + SqlCommand = """select Value1, Value2, StartLine from %s + where Model = %s + and Arch = '%s' + and BelongsToFile = %s + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Arch), BelongsToFile) + RecordSet = Table.Exec(SqlCommand) + if len(RecordSet) < 1: + SqlCommand = """select Value1, Value2, StartLine from %s + where Model = %s + and Arch = '%s' + and BelongsToFile = %s + and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(TAB_ARCH_COMMON), BelongsToFile) + RecordSet = Table.Exec(SqlCommand) + + return RecordSet + +##QueryDscItem +# +# Search all dsc item for a specific section +# +# @param Table: The Table to be executed +# @param Model: The type of section +# +# @retval RecordSet: A list of all matched records +# +def QueryDscItem(Table, Model, BelongsToItem, BelongsToFile): + SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s + where Model = %s + and BelongsToItem = %s + and BelongsToFile = %s + and Enabled > -1""" % (Table.Table, Model, BelongsToItem, BelongsToFile) + return Table.Exec(SqlCommand) + +##QueryDecItem +# +# Search all dec item for a specific section +# +# @param Table: The Table to be executed +# @param Model: The type of section +# +# @retval RecordSet: A list of all matched records +# +def QueryDecItem(Table, Model, BelongsToItem): + SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s + where Model = %s + and BelongsToItem = %s + and Enabled > -1""" % (Table.Table, Model, BelongsToItem) + return Table.Exec(SqlCommand) + +##QueryInfItem +# +# Search all dec item for a specific section +# +# @param Table: The Table to be executed +# @param Model: The type of section +# +# @retval RecordSet: A list of all matched records +# +def QueryInfItem(Table, Model, BelongsToItem): + SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s + where Model = %s + and BelongsToItem = %s + and Enabled > -1""" % (Table.Table, Model, BelongsToItem) + return Table.Exec(SqlCommand) + +## GetBuildOption +# +# Parse a string with format "[:]=Flag" +# Return (Family, ToolFlag, Flag) +# +# @param String: String with BuildOption statement +# @param File: The file which defines build option, used in error report +# +# @retval truple() A truple structure as (Family, ToolChain, Flag) +# +def GetBuildOption(String, File, LineNo = -1): + (Family, ToolChain, Flag) = ('', '', '') + if String.find(TAB_EQUAL_SPLIT) < 0: + RaiseParserError(String, 'BuildOptions', File, '[:]=Flag', LineNo) + else: + List = GetSplitValueList(String, TAB_EQUAL_SPLIT, MaxSplit = 1) + if List[0].find(':') > -1: + Family = List[0][ : List[0].find(':')].strip() + ToolChain = List[0][List[0].find(':') + 1 : ].strip() + else: + ToolChain = List[0].strip() + Flag = List[1].strip() + return (Family, ToolChain, Flag) + +## Get Library Class +# +# Get Library of Dsc as | +# +# @param Item: String as | +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item +# +def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo = -1): + List = GetSplitValueList(Item[0]) + SupMod = SUP_MODULE_LIST_STRING + if len(List) != 2: + RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, '|') + else: + CheckFileType(List[1], '.Inf', ContainerFile, 'library class instance', Item[0], LineNo) + CheckFileExist(WorkspaceDir, List[1], ContainerFile, 'LibraryClasses', Item[0], LineNo) + if Item[1] != '': + SupMod = Item[1] + + return (List[0], List[1], SupMod) + +## Get Library Class +# +# Get Library of Dsc as [|][|.] +# +# @param Item: String as | +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item +# +def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo = -1): + ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2)) + SupMod = SUP_MODULE_LIST_STRING + + if len(ItemList) > 5: + RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, '[|][|.]') + else: + CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', Item[0], LineNo) + CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, 'LibraryClasses', Item[0], LineNo) + if ItemList[2] != '': + CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', ContainerFile, LineNo) + if Item[1] != '': + SupMod = Item[1] + + return (ItemList[0], ItemList[1], ItemList[2], SupMod) + +## CheckPcdTokenInfo +# +# Check if PcdTokenInfo is following . +# +# @param TokenInfoString: String to be checked +# @param Section: Used for error report +# @param File: Used for error report +# +# @retval True PcdTokenInfo is in correct format +# +def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo = -1): + Format = '.' + if TokenInfoString != '' and TokenInfoString is not None: + TokenInfoList = GetSplitValueList(TokenInfoString, TAB_SPLIT) + if len(TokenInfoList) == 2: + return True + + RaiseParserError(TokenInfoString, Section, File, Format, LineNo) + +## Get Pcd +# +# Get Pcd of Dsc as .|[||] +# +# @param Item: String as .|[||] +# @param ContainerFile: The file which describes the pcd, used for error report +# +# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type) +# +def GetPcd(Item, Type, ContainerFile, LineNo = -1): + TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', '' + List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2) + + if len(List) < 4 or len(List) > 6: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '.|[||]', LineNo) + else: + Value = List[1] + MaximumDatumSize = List[2] + Token = List[3] + + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT) + + return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type) + +## Get FeatureFlagPcd +# +# Get FeatureFlagPcd of Dsc as .|TRUE/FALSE +# +# @param Item: String as .|TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error report +# +# @retval (TokenInfo[1], TokenInfo[0], List[1], Type) +# +def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo = -1): + TokenGuid, TokenName, Value = '', '', '' + List = GetSplitValueList(Item) + if len(List) != 2: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '.|TRUE/FALSE', LineNo) + else: + Value = List[1] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, Value, Type) + +## Get DynamicDefaultPcd +# +# Get DynamicDefaultPcd of Dsc as .|[|[|]] +# +# @param Item: String as .|TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error report +# +# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type) +# +def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo = -1): + TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', '' + List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2) + if len(List) < 4 or len(List) > 8: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '.|[|[|]]', LineNo) + else: + Value = List[1] + DatumTyp = List[2] + MaxDatumSize = List[3] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT) + + return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type) + +## Get DynamicHiiPcd +# +# Get DynamicHiiPcd of Dsc as .|||[|[|]] +# +# @param Item: String as .|TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error report +# +# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], List[4], List[5], Type) +# +def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo = -1): + TokenGuid, TokenName, L1, L2, L3, L4, L5 = '', '', '', '', '', '', '' + List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2) + if len(List) < 6 or len(List) > 8: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '.|||[|[|]]', LineNo) + else: + L1, L2, L3, L4, L5 = List[1], List[2], List[3], List[4], List[5] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, L1, L2, L3, L4, L5, Type) + +## Get DynamicVpdPcd +# +# Get DynamicVpdPcd of Dsc as .|[|] +# +# @param Item: String as .|TRUE/FALSE +# @param ContainerFile: The file which describes the pcd, used for error report +# +# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], Type) +# +def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo = -1): + TokenGuid, TokenName, L1, L2 = '', '', '', '' + List = GetSplitValueList(Item + TAB_VALUE_SPLIT) + if len(List) < 3 or len(List) > 4: + RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '.|[|]', LineNo) + else: + L1, L2 = List[1], List[2] + if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): + (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) + + return (TokenName, TokenGuid, L1, L2, Type) + +## GetComponent +# +# Parse block of the components defined in dsc file +# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...] +# +# @param Lines: The content to be parsed +# @param KeyValues: To store data after parsing +# +# @retval True Get component successfully +# +def GetComponent(Lines, KeyValues): + (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False) + ListItem = None + LibraryClassItem = [] + BuildOption = [] + Pcd = [] + + for Line in Lines: + Line = Line[0] + + # + # Ignore !include statement + # + if Line.upper().find(TAB_INCLUDE.upper() + ' ') > -1 or Line.upper().find(TAB_DEFINE + ' ') > -1: + continue + + if findBlock == False: + ListItem = Line + # + # find '{' at line tail + # + if Line.endswith('{'): + findBlock = True + ListItem = CleanString(Line.rsplit('{', 1)[0], DataType.TAB_COMMENT_SPLIT) + + # + # Parse a block content + # + if findBlock: + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True) + continue + if Line.endswith('}'): + # + # find '}' at line tail + # + KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd]) + (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False) + LibraryClassItem, BuildOption, Pcd = [], [], [] + continue + + if findBlock: + if findLibraryClass: + LibraryClassItem.append(Line) + elif findBuildOption: + BuildOption.append(Line) + elif findPcdsFeatureFlag: + Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line)) + elif findPcdsPatchableInModule: + Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line)) + elif findPcdsFixedAtBuild: + Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line)) + elif findPcdsDynamic: + Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line)) + elif findPcdsDynamicEx: + Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line)) + else: + KeyValues.append([ListItem, [], [], []]) + + return True + +## GetExec +# +# Parse a string with format "InfFilename [EXEC = ExecFilename]" +# Return (InfFilename, ExecFilename) +# +# @param String: String with EXEC statement +# +# @retval truple() A pair as (InfFilename, ExecFilename) +# +def GetExec(String): + InfFilename = '' + ExecFilename = '' + if String.find('EXEC') > -1: + InfFilename = String[ : String.find('EXEC')].strip() + ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip() + else: + InfFilename = String.strip() + + return (InfFilename, ExecFilename) + +## GetComponents +# +# Parse block of the components defined in dsc file +# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...] +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval True Get component successfully +# +def GetComponents(Lines, Key, KeyValues, CommentCharacter): + if Lines.find(DataType.TAB_SECTION_END) > -1: + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False) + ListItem = None + LibraryClassItem = [] + BuildOption = [] + Pcd = [] + + LineList = Lines.split('\n') + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line is None or Line == '': + continue + + if findBlock == False: + ListItem = Line + # + # find '{' at line tail + # + if Line.endswith('{'): + findBlock = True + ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter) + + # + # Parse a block content + # + if findBlock: + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False) + continue + if Line.find('') != -1: + (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True) + continue + if Line.endswith('}'): + # + # find '}' at line tail + # + KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd]) + (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False) + LibraryClassItem, BuildOption, Pcd = [], [], [] + continue + + if findBlock: + if findLibraryClass: + LibraryClassItem.append(Line) + elif findBuildOption: + BuildOption.append(Line) + elif findPcdsFeatureFlag: + Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line)) + elif findPcdsPatchableInModule: + Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line)) + elif findPcdsFixedAtBuild: + Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line)) + elif findPcdsDynamic: + Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line)) + elif findPcdsDynamicEx: + Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line)) + else: + KeyValues.append([ListItem, [], [], []]) + + return True + +## Get Source +# +# Get Source of Inf as [|[|[|[|]]]] +# +# @param Item: String as [|[|[|[|]]]] +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (List[0], List[1], List[2], List[3], List[4]) +# +def GetSource(Item, ContainerFile, FileRelativePath, LineNo = -1): + ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4 + List = GetSplitValueList(ItemNew) + if len(List) < 5 or len(List) > 9: + RaiseParserError(Item, 'Sources', ContainerFile, '[|[|[|[|]]]]', LineNo) + List[0] = NormPath(List[0]) + CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', Item, LineNo) + if List[4] != '': + CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo) + + return (List[0], List[1], List[2], List[3], List[4]) + +## Get Binary +# +# Get Binary of Inf as [|[|[|[|]]]] +# +# @param Item: String as [|[|[|[|]]]] +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (List[0], List[1], List[2], List[3]) +# @retval List +# +def GetBinary(Item, ContainerFile, FileRelativePath, LineNo = -1): + ItemNew = Item + DataType.TAB_VALUE_SPLIT + List = GetSplitValueList(ItemNew) + if len(List) != 4 and len(List) != 5: + RaiseParserError(Item, 'Binaries', ContainerFile, "||[|.]", LineNo) + else: + if List[3] != '': + CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo) + + if len(List) == 4: + return (List[0], List[1], List[2], List[3]) + elif len(List) == 3: + return (List[0], List[1], List[2], '') + elif len(List) == 2: + return (List[0], List[1], '', '') + elif len(List) == 1: + return (List[0], '', '', '') + +## Get Guids/Protocols/Ppis +# +# Get Guids/Protocols/Ppis of Inf as [|] +# +# @param Item: String as [|] +# @param Type: Type of parsing string +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (List[0], List[1]) +# +def GetGuidsProtocolsPpisOfInf(Item, Type, ContainerFile, LineNo = -1): + ItemNew = Item + TAB_VALUE_SPLIT + List = GetSplitValueList(ItemNew) + if List[1] != '': + CheckPcdTokenInfo(List[1], Type, ContainerFile, LineNo) + + return (List[0], List[1]) + +## Get Guids/Protocols/Ppis +# +# Get Guids/Protocols/Ppis of Dec as = +# +# @param Item: String as = +# @param Type: Type of parsing string +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (List[0], List[1]) +# +def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo = -1): + List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT) + if len(List) != 2: + RaiseParserError(Item, Type, ContainerFile, '=', LineNo) + + return (List[0], List[1]) + +## GetPackage +# +# Get Package of Inf as [|] +# +# @param Item: String as [|] +# @param Type: Type of parsing string +# @param ContainerFile: The file which describes the library class, used for error report +# +# @retval (List[0], List[1]) +# +def GetPackage(Item, ContainerFile, FileRelativePath, LineNo = -1): + ItemNew = Item + TAB_VALUE_SPLIT + List = GetSplitValueList(ItemNew) + CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo) + CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', List[0], LineNo) + + if List[1] != '': + CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo) + + return (List[0], List[1]) + +## Get Pcd Values of Inf +# +# Get Pcd of Inf as .[|] +# +# @param Item: The string describes pcd +# @param Type: The type of Pcd +# @param File: The file which describes the pcd, used for error report +# +# @retval (TokenSpcCName, TokenCName, Value, ItemType) Formatted Pcd Item +# +def GetPcdOfInf(Item, Type, File, LineNo): + Format = '.[|]' + TokenGuid, TokenName, Value, InfType = '', '', '', '' + + if Type == TAB_PCDS_FIXED_AT_BUILD: + InfType = TAB_INF_FIXED_PCD + elif Type == TAB_PCDS_PATCHABLE_IN_MODULE: + InfType = TAB_INF_PATCH_PCD + elif Type == TAB_PCDS_FEATURE_FLAG: + InfType = TAB_INF_FEATURE_PCD + elif Type == TAB_PCDS_DYNAMIC_EX: + InfType = TAB_INF_PCD_EX + elif Type == TAB_PCDS_DYNAMIC: + InfType = TAB_INF_PCD + List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT) + if len(List) < 2 or len(List) > 3: + RaiseParserError(Item, InfType, File, Format, LineNo) + else: + Value = List[1] + TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT) + if len(TokenInfo) != 2: + RaiseParserError(Item, InfType, File, Format, LineNo) + else: + TokenGuid = TokenInfo[0] + TokenName = TokenInfo[1] + + return (TokenGuid, TokenName, Value, Type) + + +## Get Pcd Values of Dec +# +# Get Pcd of Dec as .||| +# @retval (TokenSpcCName, TokenCName, Value, DatumType, Token, ItemType) Formatted Pcd Item +# +def GetPcdOfDec(Item, Type, File, LineNo = -1): + Format = '.|||' + TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', '' + List = GetSplitValueList(Item) + if len(List) != 4: + RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo) + else: + Value = List[1] + DatumType = List[2] + Token = List[3] + TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT) + if len(TokenInfo) != 2: + RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo) + else: + TokenGuid = TokenInfo[0] + TokenName = TokenInfo[1] + + return (TokenGuid, TokenName, Value, DatumType, Token, Type) + +## Parse DEFINE statement +# +# Get DEFINE macros +# +# 1. Insert a record into TblDec +# Value1: Macro Name +# Value2: Macro Value +# +def ParseDefine(LineValue, StartLine, Table, FileID, Filename, SectionName, SectionModel, Arch): + EdkLogger.debug(EdkLogger.DEBUG_2, "DEFINE statement '%s' found in section %s" % (LineValue, SectionName)) + Define = GetSplitValueList(CleanString(LineValue[LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') + len(DataType.TAB_DEFINE + ' ') : ]), TAB_EQUAL_SPLIT, 1) + Table.Insert(MODEL_META_DATA_DEFINE, Define[0], Define[1], '', '', '', Arch, SectionModel, FileID, StartLine, -1, StartLine, -1, 0) + +## InsertSectionItems +# +# Insert item data of a section to a dict +# +def InsertSectionItems(Model, CurrentSection, SectionItemList, ArchList, ThirdList, RecordSet): + # Insert each item data of a section + for Index in range(0, len(ArchList)): + Arch = ArchList[Index] + Third = ThirdList[Index] + if Arch == '': + Arch = TAB_ARCH_COMMON + + Records = RecordSet[Model] + for SectionItem in SectionItemList: + BelongsToItem, EndLine, EndColumn = -1, -1, -1 + LineValue, StartLine, EndLine, Comment = SectionItem[0], SectionItem[1], SectionItem[1], SectionItem[2] + + EdkLogger.debug(4, "Parsing %s ..." %LineValue) + # And then parse DEFINE statement + if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1: + continue + + # At last parse other sections + ID = -1 + Records.append([LineValue, Arch, StartLine, ID, Third, Comment]) + + if RecordSet != {}: + RecordSet[Model] = Records + +## Insert records to database +# +# Insert item data of a section to database +# @param Table: The Table to be inserted +# @param FileID: The ID of belonging file +# @param Filename: The name of belonging file +# @param CurrentSection: The name of current section +# @param SectionItemList: A list of items of the section +# @param ArchList: A list of arches +# @param ThirdList: A list of third parameters, ModuleType for LibraryClass and SkuId for Dynamic Pcds +# @param IfDefList: A list of all conditional statements +# @param RecordSet: A dict of all parsed records +# +def InsertSectionItemsIntoDatabase(Table, FileID, Filename, Model, CurrentSection, SectionItemList, ArchList, ThirdList, IfDefList, RecordSet): + # + # Insert each item data of a section + # + for Index in range(0, len(ArchList)): + Arch = ArchList[Index] + Third = ThirdList[Index] + if Arch == '': + Arch = TAB_ARCH_COMMON + + Records = RecordSet[Model] + for SectionItem in SectionItemList: + BelongsToItem, EndLine, EndColumn = -1, -1, -1 + LineValue, StartLine, EndLine = SectionItem[0], SectionItem[1], SectionItem[1] + + EdkLogger.debug(4, "Parsing %s ..." %LineValue) + # + # And then parse DEFINE statement + # + if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1: + ParseDefine(LineValue, StartLine, Table, FileID, Filename, CurrentSection, Model, Arch) + continue + + # + # At last parse other sections + # + ID = Table.Insert(Model, LineValue, Third, Third, '', '', Arch, -1, FileID, StartLine, -1, StartLine, -1, 0) + Records.append([LineValue, Arch, StartLine, ID, Third]) + + if RecordSet != {}: + RecordSet[Model] = Records + +## GenMetaDatSectionItem +def GenMetaDatSectionItem(Key, Value, List): + if Key not in List: + List[Key] = [Value] + else: + List[Key].append(Value) + +## IsValidWord +# +# Check whether the word is valid. +# ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with +# optional +# dash "-" and/or underscore "_" characters. No whitespace +# characters are permitted. +# +# @param Word: The word string need to be checked. +# +def IsValidWord(Word): + if not Word: + return False + # + # The first char should be alpha, _ or Digit. + # + if not Word[0].isalnum() and \ + not Word[0] == '_' and \ + not Word[0].isdigit(): + return False + + LastChar = '' + for Char in Word[1:]: + if (not Char.isalpha()) and \ + (not Char.isdigit()) and \ + Char != '-' and \ + Char != '_' and \ + Char != '.': + return False + if Char == '.' and LastChar == '.': + return False + LastChar = Char + + return True diff --git a/tools/python/Common/StringUtils.py b/tools/python/Common/StringUtils.py new file mode 100755 index 0000000..73dafa7 --- /dev/null +++ b/tools/python/Common/StringUtils.py @@ -0,0 +1,873 @@ +## @file +# This file is used to define common string related functions used in parsing process +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +import re +from . import DataType +import Common.LongFilePathOs as os +import string +from . import EdkLogger as EdkLogger + +from . import GlobalData +from .BuildToolError import * +from CommonDataClass.Exceptions import * +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws + +gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE) +gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') + +## GetSplitValueList +# +# Get a value list from a string with multiple values split with SplitTag +# The default SplitTag is DataType.TAB_VALUE_SPLIT +# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] +# +# @param String: The input string to be splitted +# @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT +# @param MaxSplit: The max number of split values, default is -1 +# +# @retval list() A list for splitted string +# +def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): + ValueList = [] + Last = 0 + Escaped = False + InSingleQuoteString = False + InDoubleQuoteString = False + InParenthesis = 0 + for Index in range(0, len(String)): + Char = String[Index] + + if not Escaped: + # Found a splitter not in a string, split it + if (not InSingleQuoteString or not InDoubleQuoteString) and InParenthesis == 0 and Char == SplitTag: + ValueList.append(String[Last:Index].strip()) + Last = Index + 1 + if MaxSplit > 0 and len(ValueList) >= MaxSplit: + break + + if Char == '\\' and (InSingleQuoteString or InDoubleQuoteString): + Escaped = True + elif Char == '"' and not InSingleQuoteString: + if not InDoubleQuoteString: + InDoubleQuoteString = True + else: + InDoubleQuoteString = False + elif Char == "'" and not InDoubleQuoteString: + if not InSingleQuoteString: + InSingleQuoteString = True + else: + InSingleQuoteString = False + elif Char == '(': + InParenthesis = InParenthesis + 1 + elif Char == ')': + InParenthesis = InParenthesis - 1 + else: + Escaped = False + + if Last < len(String): + ValueList.append(String[Last:].strip()) + elif Last == len(String): + ValueList.append('') + + return ValueList + +## GetSplitList +# +# Get a value list from a string with multiple values split with SplitString +# The default SplitTag is DataType.TAB_VALUE_SPLIT +# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] +# +# @param String: The input string to be splitted +# @param SplitStr: The split key, default is DataType.TAB_VALUE_SPLIT +# @param MaxSplit: The max number of split values, default is -1 +# +# @retval list() A list for splitted string +# +def GetSplitList(String, SplitStr=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): + return list(map(lambda l: l.strip(), String.split(SplitStr, MaxSplit))) + +## MergeArches +# +# Find a key's all arches in dict, add the new arch to the list +# If not exist any arch, set the arch directly +# +# @param Dict: The input value for Dict +# @param Key: The input value for Key +# @param Arch: The Arch to be added or merged +# +def MergeArches(Dict, Key, Arch): + if Key in Dict: + Dict[Key].append(Arch) + else: + Dict[Key] = Arch.split() + +## GenDefines +# +# Parse a string with format "DEFINE = " +# Generate a map Defines[VarName] = PATH +# Return False if invalid format +# +# @param String: String with DEFINE statement +# @param Arch: Supported Arch +# @param Defines: DEFINE statement to be parsed +# +# @retval 0 DEFINE statement found, and valid +# @retval 1 DEFINE statement found, but not valid +# @retval -1 DEFINE statement not found +# +def GenDefines(String, Arch, Defines): + if String.find(DataType.TAB_DEFINE + ' ') > -1: + List = String.replace(DataType.TAB_DEFINE + ' ', '').split(DataType.TAB_EQUAL_SPLIT) + if len(List) == 2: + Defines[(CleanString(List[0]), Arch)] = CleanString(List[1]) + return 0 + else: + return -1 + + return 1 + +## GenInclude +# +# Parse a string with format "!include " +# Return the file path +# Return False if invalid format or NOT FOUND +# +# @param String: String with INCLUDE statement +# @param IncludeFiles: INCLUDE statement to be parsed +# @param Arch: Supported Arch +# +# @retval True +# @retval False +# +def GenInclude(String, IncludeFiles, Arch): + if String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1: + IncludeFile = CleanString(String[String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') + len(DataType.TAB_INCLUDE + ' ') : ]) + MergeArches(IncludeFiles, IncludeFile, Arch) + return True + else: + return False + +## GetLibraryClassesWithModuleType +# +# Get Library Class definition when no module type defined +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval True Get library classes successfully +# +def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter): + newKey = SplitModuleType(Key) + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + LineList = Lines.splitlines() + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line != '' and Line[0] != CommentCharacter: + KeyValues.append([CleanString(Line, CommentCharacter), newKey[1]]) + + return True + +## GetDynamics +# +# Get Dynamic Pcds +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval True Get Dynamic Pcds successfully +# +def GetDynamics(Lines, Key, KeyValues, CommentCharacter): + # + # Get SkuId Name List + # + SkuIdNameList = SplitModuleType(Key) + + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + LineList = Lines.splitlines() + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line != '' and Line[0] != CommentCharacter: + KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]]) + + return True + +## SplitModuleType +# +# Split ModuleType out of section defien to get key +# [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [ 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ] +# +# @param Key: String to be parsed +# +# @retval ReturnValue A list for module types +# +def SplitModuleType(Key): + KeyList = Key.split(DataType.TAB_SPLIT) + # + # Fill in for arch + # + KeyList.append('') + # + # Fill in for moduletype + # + KeyList.append('') + ReturnValue = [] + KeyValue = KeyList[0] + if KeyList[1] != '': + KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1] + ReturnValue.append(KeyValue) + ReturnValue.append(GetSplitValueList(KeyList[2])) + + return ReturnValue + +## Replace macro in strings list +# +# This method replace macros used in a given string list. The macros are +# given in a dictionary. +# +# @param StringList StringList to be processed +# @param MacroDefinitions The macro definitions in the form of dictionary +# @param SelfReplacement To decide whether replace un-defined macro to '' +# +# @retval NewList A new string list whose macros are replaced +# +def ReplaceMacros(StringList, MacroDefinitions=None, SelfReplacement=False): + NewList = [] + if MacroDefinitions is None: + MacroDefinitions = {} + for String in StringList: + if isinstance(String, type('')): + NewList.append(ReplaceMacro(String, MacroDefinitions, SelfReplacement)) + else: + NewList.append(String) + + return NewList + +## Replace macro in string +# +# This method replace macros used in given string. The macros are given in a +# dictionary. +# +# @param String String to be processed +# @param MacroDefinitions The macro definitions in the form of dictionary +# @param SelfReplacement To decide whether replace un-defined macro to '' +# +# @retval string The string whose macros are replaced +# +def ReplaceMacro(String, MacroDefinitions=None, SelfReplacement=False, RaiseError=False): + LastString = String + if MacroDefinitions is None: + MacroDefinitions = {} + while String and MacroDefinitions: + MacroUsed = GlobalData.gMacroRefPattern.findall(String) + # no macro found in String, stop replacing + if len(MacroUsed) == 0: + break + + for Macro in MacroUsed: + if Macro not in MacroDefinitions: + if RaiseError: + raise SymbolNotFound("%s not defined" % Macro) + if SelfReplacement: + String = String.replace("$(%s)" % Macro, '') + continue + if "$(%s)" % Macro not in MacroDefinitions[Macro]: + String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro]) + # in case there's macro not defined + if String == LastString: + break + LastString = String + + return String + +## NormPath +# +# Create a normal path +# And replace DEFINE in the path +# +# @param Path: The input value for Path to be converted +# @param Defines: A set for DEFINE statement +# +# @retval Path Formatted path +# +def NormPath(Path, Defines=None): + IsRelativePath = False + if Path: + if Path[0] == '.': + IsRelativePath = True + # + # Replace with Define + # + if Defines: + Path = ReplaceMacro(Path, Defines) + # + # To local path format + # + Path = os.path.normpath(Path) + if Path.startswith(GlobalData.gWorkspace) and not Path.startswith(GlobalData.gBuildDirectory) and not os.path.exists(Path): + Path = Path[len (GlobalData.gWorkspace):] + if Path[0] == os.path.sep: + Path = Path[1:] + Path = mws.join(GlobalData.gWorkspace, Path) + + if IsRelativePath and Path[0] != '.': + Path = os.path.join('.', Path) + + return Path + +## CleanString +# +# Remove comments in a string +# Remove spaces +# +# @param Line: The string to be cleaned +# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT +# +# @retval Path Formatted path +# +def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False): + # + # remove whitespace + # + Line = Line.strip(); + # + # Replace Edk's comment character + # + if AllowCppStyleComment: + Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) + # + # remove comments, but we should escape comment character in string + # + InDoubleQuoteString = False + InSingleQuoteString = False + CommentInString = False + for Index in range(0, len(Line)): + if Line[Index] == '"' and not InSingleQuoteString: + InDoubleQuoteString = not InDoubleQuoteString + elif Line[Index] == "'" and not InDoubleQuoteString: + InSingleQuoteString = not InSingleQuoteString + elif Line[Index] == CommentCharacter and (InSingleQuoteString or InDoubleQuoteString): + CommentInString = True + elif Line[Index] == CommentCharacter and not (InSingleQuoteString or InDoubleQuoteString): + Line = Line[0: Index] + break + + if CommentInString and BuildOption: + Line = Line.replace('"', '') + ChIndex = Line.find('#') + while ChIndex >= 0: + if GlobalData.gIsWindows: + if ChIndex == 0 or Line[ChIndex - 1] != '^': + Line = Line[0:ChIndex] + '^' + Line[ChIndex:] + ChIndex = Line.find('#', ChIndex + 2) + else: + ChIndex = Line.find('#', ChIndex + 1) + else: + if ChIndex == 0 or Line[ChIndex - 1] != '\\': + Line = Line[0:ChIndex] + '\\' + Line[ChIndex:] + ChIndex = Line.find('#', ChIndex + 2) + else: + ChIndex = Line.find('#', ChIndex + 1) + # + # remove whitespace again + # + Line = Line.strip(); + + return Line + +## CleanString2 +# +# Split statement with comments in a string +# Remove spaces +# +# @param Line: The string to be cleaned +# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT +# +# @retval Path Formatted path +# +def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): + # + # remove whitespace + # + Line = Line.strip(); + # + # Replace Edk's comment character + # + if AllowCppStyleComment: + Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) + # + # separate comments and statements, but we should escape comment character in string + # + InDoubleQuoteString = False + InSingleQuoteString = False + CommentInString = False + Comment = '' + for Index in range(0, len(Line)): + if Line[Index] == '"' and not InSingleQuoteString: + InDoubleQuoteString = not InDoubleQuoteString + elif Line[Index] == "'" and not InDoubleQuoteString: + InSingleQuoteString = not InSingleQuoteString + elif Line[Index] == CommentCharacter and (InDoubleQuoteString or InSingleQuoteString): + CommentInString = True + elif Line[Index] == CommentCharacter and not (InDoubleQuoteString or InSingleQuoteString): + Comment = Line[Index:].strip() + Line = Line[0:Index].strip() + break + + return Line, Comment + +## GetMultipleValuesOfKeyFromLines +# +# Parse multiple strings to clean comment and spaces +# The result is saved to KeyValues +# +# @param Lines: The content to be parsed +# @param Key: Reserved +# @param KeyValues: To store data after parsing +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval True Successfully executed +# +def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter): + Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] + LineList = Lines.split('\n') + for Line in LineList: + Line = CleanString(Line, CommentCharacter) + if Line != '' and Line[0] != CommentCharacter: + KeyValues.append(Line) + + return True + +## GetDefineValue +# +# Parse a DEFINE statement to get defined value +# DEFINE Key Value +# +# @param String: The content to be parsed +# @param Key: The key of DEFINE statement +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval string The defined value +# +def GetDefineValue(String, Key, CommentCharacter): + String = CleanString(String) + return String[String.find(Key + ' ') + len(Key + ' ') : ] + +## GetHexVerValue +# +# Get a Hex Version Value +# +# @param VerString: The version string to be parsed +# +# +# @retval: If VerString is incorrectly formatted, return "None" which will break the build. +# If VerString is correctly formatted, return a Hex value of the Version Number (0xmmmmnnnn) +# where mmmm is the major number and nnnn is the adjusted minor number. +# +def GetHexVerValue(VerString): + VerString = CleanString(VerString) + + if gHumanReadableVerPatt.match(VerString): + ValueList = VerString.split('.') + Major = ValueList[0] + Minor = ValueList[1] + if len(Minor) == 1: + Minor += '0' + DeciValue = (int(Major) << 16) + int(Minor); + return "0x%08x" % DeciValue + elif gHexVerPatt.match(VerString): + return VerString + else: + return None + + +## GetSingleValueOfKeyFromLines +# +# Parse multiple strings as below to get value of each definition line +# Key1 = Value1 +# Key2 = Value2 +# The result is saved to Dictionary +# +# @param Lines: The content to be parsed +# @param Dictionary: To store data after parsing +# @param CommentCharacter: Comment char, be used to ignore comment content +# @param KeySplitCharacter: Key split char, between key name and key value. Key1 = Value1, '=' is the key split char +# @param ValueSplitFlag: Value split flag, be used to decide if has multiple values +# @param ValueSplitCharacter: Value split char, be used to split multiple values. Key1 = Value1|Value2, '|' is the value split char +# +# @retval True Successfully executed +# +def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter): + Lines = Lines.split('\n') + Keys = [] + Value = '' + DefineValues = [''] + SpecValues = [''] + + for Line in Lines: + # + # Handle DEFINE and SPEC + # + if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1: + if '' in DefineValues: + DefineValues.remove('') + DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter)) + continue + if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1: + if '' in SpecValues: + SpecValues.remove('') + SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter)) + continue + + # + # Handle Others + # + LineList = Line.split(KeySplitCharacter, 1) + if len(LineList) >= 2: + Key = LineList[0].split() + if len(Key) == 1 and Key[0][0] != CommentCharacter: + # + # Remove comments and white spaces + # + LineList[1] = CleanString(LineList[1], CommentCharacter) + if ValueSplitFlag: + Value = list(map(string.strip, LineList[1].split(ValueSplitCharacter))) + else: + Value = CleanString(LineList[1], CommentCharacter).splitlines() + + if Key[0] in Dictionary: + if Key[0] not in Keys: + Dictionary[Key[0]] = Value + Keys.append(Key[0]) + else: + Dictionary[Key[0]].extend(Value) + else: + Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0] + + if DefineValues == []: + DefineValues = [''] + if SpecValues == []: + SpecValues = [''] + Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues + Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues + + return True + +## The content to be parsed +# +# Do pre-check for a file before it is parsed +# Check $() +# Check [] +# +# @param FileName: Used for error report +# @param FileContent: File content to be parsed +# @param SupSectionTag: Used for error report +# +def PreCheck(FileName, FileContent, SupSectionTag): + LineNo = 0 + IsFailed = False + NewFileContent = '' + for Line in FileContent.splitlines(): + LineNo = LineNo + 1 + # + # Clean current line + # + Line = CleanString(Line) + + # + # Remove commented line + # + if Line.find(DataType.TAB_COMMA_SPLIT) == 0: + Line = '' + # + # Check $() + # + if Line.find('$') > -1: + if Line.find('$(') < 0 or Line.find(')') < 0: + EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) + + # + # Check [] + # + if Line.find('[') > -1 or Line.find(']') > -1: + # + # Only get one '[' or one ']' + # + if not (Line.find('[') > -1 and Line.find(']') > -1): + EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) + + # + # Regenerate FileContent + # + NewFileContent = NewFileContent + Line + '\r\n' + + if IsFailed: + EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) + + return NewFileContent + +## CheckFileType +# +# Check if the Filename is including ExtName +# Return True if it exists +# Raise a error message if it not exists +# +# @param CheckFilename: Name of the file to be checked +# @param ExtName: Ext name of the file to be checked +# @param ContainerFilename: The container file which describes the file to be checked, used for error report +# @param SectionName: Used for error report +# @param Line: The line in container file which defines the file to be checked +# +# @retval True The file type is correct +# +def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1): + if CheckFilename != '' and CheckFilename is not None: + (Root, Ext) = os.path.splitext(CheckFilename) + if Ext.upper() != ExtName.upper(): + ContainerFile = open(ContainerFilename, 'r').read() + if LineNo == -1: + LineNo = GetLineNo(ContainerFile, Line) + ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName) + EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, + File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError) + + return True + +## CheckFileExist +# +# Check if the file exists +# Return True if it exists +# Raise a error message if it not exists +# +# @param CheckFilename: Name of the file to be checked +# @param WorkspaceDir: Current workspace dir +# @param ContainerFilename: The container file which describes the file to be checked, used for error report +# @param SectionName: Used for error report +# @param Line: The line in container file which defines the file to be checked +# +# @retval The file full path if the file exists +# +def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1): + CheckFile = '' + if CheckFilename != '' and CheckFilename is not None: + CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename) + if not os.path.isfile(CheckFile): + ContainerFile = open(ContainerFilename, 'r').read() + if LineNo == -1: + LineNo = GetLineNo(ContainerFile, Line) + ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName) + EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, + File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError) + + return CheckFile + +## GetLineNo +# +# Find the index of a line in a file +# +# @param FileContent: Search scope +# @param Line: Search key +# +# @retval int Index of the line +# @retval -1 The line is not found +# +def GetLineNo(FileContent, Line, IsIgnoreComment=True): + LineList = FileContent.splitlines() + for Index in range(len(LineList)): + if LineList[Index].find(Line) > -1: + # + # Ignore statement in comment + # + if IsIgnoreComment: + if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT: + continue + return Index + 1 + + return -1 + +## RaiseParserError +# +# Raise a parser error +# +# @param Line: String which has error +# @param Section: Used for error report +# @param File: File which has the string +# @param Format: Correct format +# +def RaiseParserError(Line, Section, File, Format='', LineNo= -1): + if LineNo == -1: + LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line) + ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section) + if Format != '': + Format = "Correct format is " + Format + EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError) + +## WorkspaceFile +# +# Return a full path with workspace dir +# +# @param WorkspaceDir: Workspace dir +# @param Filename: Relative file name +# +# @retval string A full path +# +def WorkspaceFile(WorkspaceDir, Filename): + return mws.join(NormPath(WorkspaceDir), NormPath(Filename)) + +## Split string +# +# Remove '"' which startswith and endswith string +# +# @param String: The string need to be split +# +# @retval String: The string after removed '""' +# +def SplitString(String): + if String.startswith('\"'): + String = String[1:] + if String.endswith('\"'): + String = String[:-1] + + return String + +## Convert To Sql String +# +# 1. Replace "'" with "''" in each item of StringList +# +# @param StringList: A list for strings to be converted +# +def ConvertToSqlString(StringList): + return list(map(lambda s: s.replace("'", "''"), StringList)) + +## Convert To Sql String +# +# 1. Replace "'" with "''" in the String +# +# @param String: A String to be converted +# +def ConvertToSqlString2(String): + return String.replace("'", "''") + +# +# Remove comment block +# +def RemoveBlockComment(Lines): + IsFindBlockComment = False + IsFindBlockCode = False + ReservedLine = '' + NewLines = [] + + for Line in Lines: + Line = Line.strip() + # + # Remove comment block + # + if Line.find(DataType.TAB_COMMENT_EDK_START) > -1: + ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0] + IsFindBlockComment = True + if Line.find(DataType.TAB_COMMENT_EDK_END) > -1: + Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1] + ReservedLine = '' + IsFindBlockComment = False + if IsFindBlockComment: + NewLines.append('') + continue + + NewLines.append(Line) + return NewLines + +# +# Get String of a List +# +def GetStringOfList(List, Split=' '): + if not isinstance(List, type([])): + return List + Str = '' + for Item in List: + Str = Str + Item + Split + + return Str.strip() + +# +# Get HelpTextList from HelpTextClassList +# +def GetHelpTextList(HelpTextClassList): + List = [] + if HelpTextClassList: + for HelpText in HelpTextClassList: + if HelpText.String.endswith('\n'): + HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')] + List.extend(HelpText.String.split('\n')) + + return List + +def StringToArray(String): + if String.startswith('L"'): + if String == "L\"\"": + return "{0x00,0x00}" + else: + return "{%s,0x00,0x00}" % ",".join("0x%02x,0x00" % ord(C) for C in String[2:-1]) + elif String.startswith('"'): + if String == "\"\"": + return "{0x00,0x00}" + else: + StringLen = len(String[1:-1]) + if StringLen % 2: + return "{%s,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1]) + else: + return "{%s,0x00,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1]) + elif String.startswith('{'): + return "{%s}" % ",".join(C.strip() for C in String[1:-1].split(',')) + else: + if len(String.split()) % 2: + return '{%s,0}' % ','.join(String.split()) + else: + return '{%s,0,0}' % ','.join(String.split()) + +def StringArrayLength(String): + if String.startswith('L"'): + return (len(String) - 3 + 1) * 2 + elif String.startswith('"'): + return (len(String) - 2 + 1) + else: + return len(String.split()) + 1 + +def RemoveDupOption(OptionString, Which="/I", Against=None): + OptionList = OptionString.split() + ValueList = [] + if Against: + ValueList += Against + for Index in range(len(OptionList)): + Opt = OptionList[Index] + if not Opt.startswith(Which): + continue + if len(Opt) > len(Which): + Val = Opt[len(Which):] + else: + Val = "" + if Val in ValueList: + OptionList[Index] = "" + else: + ValueList.append(Val) + return " ".join(OptionList) + +## +# +# This acts like the main() function for the script, unless it is 'import'ed into another +# script. +# +if __name__ == '__main__': + pass + diff --git a/tools/python/Common/__init__.py b/tools/python/Common/__init__.py new file mode 100755 index 0000000..7aaef6a --- /dev/null +++ b/tools/python/Common/__init__.py @@ -0,0 +1,9 @@ +## @file +# Python 'Common' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/tools/python/Common/caching.py b/tools/python/Common/caching.py new file mode 100755 index 0000000..fda30f7 --- /dev/null +++ b/tools/python/Common/caching.py @@ -0,0 +1,41 @@ +## @file +# help with caching in BaseTools +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## Import Modules +# + +# for class function +class cached_class_function(object): + def __init__(self, function): + self._function = function + def __get__(self, obj, cls): + def CallMeHere(*args,**kwargs): + Value = self._function(obj, *args,**kwargs) + obj.__dict__[self._function.__name__] = lambda *args,**kwargs:Value + return Value + return CallMeHere + +# for class property +class cached_property(object): + def __init__(self, function): + self._function = function + def __get__(self, obj, cls): + Value = obj.__dict__[self._function.__name__] = self._function(obj) + return Value + +# for non-class function +class cached_basic_function(object): + def __init__(self, function): + self._function = function + # wrapper to call _do since .__dict__ doesn't support changing __call__ + def __call__(self,*args,**kwargs): + return self._do(*args,**kwargs) + def _do(self,*args,**kwargs): + Value = self._function(*args,**kwargs) + self.__dict__['_do'] = lambda self,*args,**kwargs:Value + return Value diff --git a/tools/python/CommonDataClass/DataClass.py b/tools/python/CommonDataClass/DataClass.py new file mode 100755 index 0000000..6f35bd4 --- /dev/null +++ b/tools/python/CommonDataClass/DataClass.py @@ -0,0 +1,369 @@ +## @file +# This file is used to define class for data structure used in ECC +# +# Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent + +## +# Import Modules +# +import Common.EdkLogger as EdkLogger + +## +# Static values for data models +# +MODEL_UNKNOWN = 0 + +MODEL_FILE_C = 1001 +MODEL_FILE_H = 1002 +MODEL_FILE_ASM = 1003 +MODEL_FILE_INF = 1011 +MODEL_FILE_DEC = 1012 +MODEL_FILE_DSC = 1013 +MODEL_FILE_FDF = 1014 +MODEL_FILE_INC = 1015 +MODEL_FILE_CIF = 1016 +MODEL_FILE_UNI = 1017 +MODEL_FILE_OTHERS = 1099 + +MODEL_IDENTIFIER_FILE_HEADER = 2001 +MODEL_IDENTIFIER_FUNCTION_HEADER = 2002 +MODEL_IDENTIFIER_COMMENT = 2003 +MODEL_IDENTIFIER_PARAMETER = 2004 +MODEL_IDENTIFIER_STRUCTURE = 2005 +MODEL_IDENTIFIER_VARIABLE = 2006 +MODEL_IDENTIFIER_INCLUDE = 2007 +MODEL_IDENTIFIER_PREDICATE_EXPRESSION = 2008 +MODEL_IDENTIFIER_ENUMERATE = 2009 +MODEL_IDENTIFIER_PCD = 2010 +MODEL_IDENTIFIER_UNION = 2011 +MODEL_IDENTIFIER_MACRO_IFDEF = 2012 +MODEL_IDENTIFIER_MACRO_IFNDEF = 2013 +MODEL_IDENTIFIER_MACRO_DEFINE = 2014 +MODEL_IDENTIFIER_MACRO_ENDIF = 2015 +MODEL_IDENTIFIER_MACRO_PROGMA = 2016 +MODEL_IDENTIFIER_FUNCTION_CALLING = 2018 +MODEL_IDENTIFIER_TYPEDEF = 2017 +MODEL_IDENTIFIER_FUNCTION_DECLARATION = 2019 +MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION = 2020 + +MODEL_EFI_PROTOCOL = 3001 +MODEL_EFI_PPI = 3002 +MODEL_EFI_GUID = 3003 +MODEL_EFI_LIBRARY_CLASS = 3004 +MODEL_EFI_LIBRARY_INSTANCE = 3005 +MODEL_EFI_PCD = 3006 +MODEL_EFI_SOURCE_FILE = 3007 +MODEL_EFI_BINARY_FILE = 3008 +MODEL_EFI_SKU_ID = 3009 +MODEL_EFI_INCLUDE = 3010 +MODEL_EFI_DEPEX = 3011 +MODEL_EFI_DEFAULT_STORES = 3012 + +MODEL_PCD = 4000 +MODEL_PCD_FIXED_AT_BUILD = 4001 +MODEL_PCD_PATCHABLE_IN_MODULE = 4002 +MODEL_PCD_FEATURE_FLAG = 4003 +MODEL_PCD_DYNAMIC_EX = 4004 +MODEL_PCD_DYNAMIC_EX_DEFAULT = 4005 +MODEL_PCD_DYNAMIC_EX_VPD = 4006 +MODEL_PCD_DYNAMIC_EX_HII = 4007 +MODEL_PCD_DYNAMIC = 4008 +MODEL_PCD_DYNAMIC_DEFAULT = 4009 +MODEL_PCD_DYNAMIC_VPD = 4010 +MODEL_PCD_DYNAMIC_HII = 4011 +MODEL_PCD_TYPE_LIST = [MODEL_PCD_FIXED_AT_BUILD, + MODEL_PCD_PATCHABLE_IN_MODULE, + MODEL_PCD_FEATURE_FLAG, + MODEL_PCD_DYNAMIC_DEFAULT, + MODEL_PCD_DYNAMIC_HII, + MODEL_PCD_DYNAMIC_VPD, + MODEL_PCD_DYNAMIC_EX_DEFAULT, + MODEL_PCD_DYNAMIC_EX_HII, + MODEL_PCD_DYNAMIC_EX_VPD + ] + +MODEL_META_DATA_HEADER_COMMENT = 5000 +MODEL_META_DATA_HEADER = 5001 +MODEL_META_DATA_INCLUDE = 5002 +MODEL_META_DATA_DEFINE = 5003 +MODEL_META_DATA_CONDITIONAL_STATEMENT_IF = 5004 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE = 5005 +MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF = 5006 +MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF = 5007 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR = 5400 +MODEL_META_DATA_BUILD_OPTION = 5008 +MODEL_META_DATA_COMPONENT = 5009 +MODEL_META_DATA_USER_EXTENSION = 5010 +MODEL_META_DATA_PACKAGE = 5011 +MODEL_META_DATA_NMAKE = 5012 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF = 5013 +MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF = 5014 +MODEL_META_DATA_COMMENT = 5016 +MODEL_META_DATA_GLOBAL_DEFINE = 5017 +MODEL_META_DATA_SECTION_HEADER = 5100 +MODEL_META_DATA_SUBSECTION_HEADER = 5200 +MODEL_META_DATA_TAIL_COMMENT = 5300 + +MODEL_EXTERNAL_DEPENDENCY = 10000 + +MODEL_LIST = [('MODEL_UNKNOWN', MODEL_UNKNOWN), + ('MODEL_FILE_C', MODEL_FILE_C), + ('MODEL_FILE_H', MODEL_FILE_H), + ('MODEL_FILE_ASM', MODEL_FILE_ASM), + ('MODEL_FILE_INF', MODEL_FILE_INF), + ('MODEL_FILE_DEC', MODEL_FILE_DEC), + ('MODEL_FILE_DSC', MODEL_FILE_DSC), + ('MODEL_FILE_FDF', MODEL_FILE_FDF), + ('MODEL_FILE_INC', MODEL_FILE_INC), + ('MODEL_FILE_CIF', MODEL_FILE_CIF), + ('MODEL_FILE_OTHERS', MODEL_FILE_OTHERS), + ('MODEL_IDENTIFIER_FILE_HEADER', MODEL_IDENTIFIER_FILE_HEADER), + ('MODEL_IDENTIFIER_FUNCTION_HEADER', MODEL_IDENTIFIER_FUNCTION_HEADER), + ('MODEL_IDENTIFIER_COMMENT', MODEL_IDENTIFIER_COMMENT), + ('MODEL_IDENTIFIER_PARAMETER', MODEL_IDENTIFIER_PARAMETER), + ('MODEL_IDENTIFIER_STRUCTURE', MODEL_IDENTIFIER_STRUCTURE), + ('MODEL_IDENTIFIER_VARIABLE', MODEL_IDENTIFIER_VARIABLE), + ('MODEL_IDENTIFIER_INCLUDE', MODEL_IDENTIFIER_INCLUDE), + ('MODEL_IDENTIFIER_PREDICATE_EXPRESSION', MODEL_IDENTIFIER_PREDICATE_EXPRESSION), + ('MODEL_IDENTIFIER_ENUMERATE', MODEL_IDENTIFIER_ENUMERATE), + ('MODEL_IDENTIFIER_PCD', MODEL_IDENTIFIER_PCD), + ('MODEL_IDENTIFIER_UNION', MODEL_IDENTIFIER_UNION), + ('MODEL_IDENTIFIER_MACRO_IFDEF', MODEL_IDENTIFIER_MACRO_IFDEF), + ('MODEL_IDENTIFIER_MACRO_IFNDEF', MODEL_IDENTIFIER_MACRO_IFNDEF), + ('MODEL_IDENTIFIER_MACRO_DEFINE', MODEL_IDENTIFIER_MACRO_DEFINE), + ('MODEL_IDENTIFIER_MACRO_ENDIF', MODEL_IDENTIFIER_MACRO_ENDIF), + ('MODEL_IDENTIFIER_MACRO_PROGMA', MODEL_IDENTIFIER_MACRO_PROGMA), + ('MODEL_IDENTIFIER_FUNCTION_CALLING', MODEL_IDENTIFIER_FUNCTION_CALLING), + ('MODEL_IDENTIFIER_TYPEDEF', MODEL_IDENTIFIER_TYPEDEF), + ('MODEL_IDENTIFIER_FUNCTION_DECLARATION', MODEL_IDENTIFIER_FUNCTION_DECLARATION), + ('MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION', MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION), + ('MODEL_EFI_PROTOCOL', MODEL_EFI_PROTOCOL), + ('MODEL_EFI_PPI', MODEL_EFI_PPI), + ('MODEL_EFI_GUID', MODEL_EFI_GUID), + ('MODEL_EFI_LIBRARY_CLASS', MODEL_EFI_LIBRARY_CLASS), + ('MODEL_EFI_LIBRARY_INSTANCE', MODEL_EFI_LIBRARY_INSTANCE), + ('MODEL_EFI_PCD', MODEL_EFI_PCD), + ('MODEL_EFI_SKU_ID', MODEL_EFI_SKU_ID), + ('MODEL_EFI_INCLUDE', MODEL_EFI_INCLUDE), + ('MODEL_EFI_DEPEX', MODEL_EFI_DEPEX), + ('MODEL_IDENTIFIER_UNION', MODEL_IDENTIFIER_UNION), + ('MODEL_EFI_SOURCE_FILE', MODEL_EFI_SOURCE_FILE), + ('MODEL_EFI_BINARY_FILE', MODEL_EFI_BINARY_FILE), + ('MODEL_PCD', MODEL_PCD), + ('MODEL_PCD_FIXED_AT_BUILD', MODEL_PCD_FIXED_AT_BUILD), + ('MODEL_PCD_PATCHABLE_IN_MODULE', MODEL_PCD_PATCHABLE_IN_MODULE), + ('MODEL_PCD_FEATURE_FLAG', MODEL_PCD_FEATURE_FLAG), + ('MODEL_PCD_DYNAMIC_EX', MODEL_PCD_DYNAMIC_EX), + ('MODEL_PCD_DYNAMIC_EX_DEFAULT', MODEL_PCD_DYNAMIC_EX_DEFAULT), + ('MODEL_PCD_DYNAMIC_EX_VPD', MODEL_PCD_DYNAMIC_EX_VPD), + ('MODEL_PCD_DYNAMIC_EX_HII', MODEL_PCD_DYNAMIC_EX_HII), + ('MODEL_PCD_DYNAMIC', MODEL_PCD_DYNAMIC), + ('MODEL_PCD_DYNAMIC_DEFAULT', MODEL_PCD_DYNAMIC_DEFAULT), + ('MODEL_PCD_DYNAMIC_VPD', MODEL_PCD_DYNAMIC_VPD), + ('MODEL_PCD_DYNAMIC_HII', MODEL_PCD_DYNAMIC_HII), + ("MODEL_META_DATA_HEADER", MODEL_META_DATA_HEADER), + ("MODEL_META_DATA_INCLUDE", MODEL_META_DATA_INCLUDE), + ("MODEL_META_DATA_DEFINE", MODEL_META_DATA_DEFINE), + ("MODEL_META_DATA_CONDITIONAL_STATEMENT_IF", MODEL_META_DATA_CONDITIONAL_STATEMENT_IF), + ("MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE", MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE), + ("MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF", MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF), + ("MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF", MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF), + ("MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR", MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR), + ("MODEL_META_DATA_BUILD_OPTION", MODEL_META_DATA_BUILD_OPTION), + ("MODEL_META_DATA_COMPONENT", MODEL_META_DATA_COMPONENT), + ('MODEL_META_DATA_USER_EXTENSION', MODEL_META_DATA_USER_EXTENSION), + ('MODEL_META_DATA_PACKAGE', MODEL_META_DATA_PACKAGE), + ('MODEL_META_DATA_NMAKE', MODEL_META_DATA_NMAKE), + ('MODEL_META_DATA_COMMENT', MODEL_META_DATA_COMMENT) + ] + +## FunctionClass +# +# This class defines a structure of a function +# +# @param ID: ID of a Function +# @param Header: Header of a Function +# @param Modifier: Modifier of a Function +# @param Name: Name of a Function +# @param ReturnStatement: ReturnStatement of a Function +# @param StartLine: StartLine of a Function +# @param StartColumn: StartColumn of a Function +# @param EndLine: EndLine of a Function +# @param EndColumn: EndColumn of a Function +# @param BodyStartLine: BodyStartLine of a Function Body +# @param BodyStartColumn: BodyStartColumn of a Function Body +# @param BelongsToFile: The Function belongs to which file +# @param IdentifierList: IdentifierList of a File +# @param PcdList: PcdList of a File +# +# @var ID: ID of a Function +# @var Header: Header of a Function +# @var Modifier: Modifier of a Function +# @var Name: Name of a Function +# @var ReturnStatement: ReturnStatement of a Function +# @var StartLine: StartLine of a Function +# @var StartColumn: StartColumn of a Function +# @var EndLine: EndLine of a Function +# @var EndColumn: EndColumn of a Function +# @var BodyStartLine: StartLine of a Function Body +# @var BodyStartColumn: StartColumn of a Function Body +# @var BelongsToFile: The Function belongs to which file +# @var IdentifierList: IdentifierList of a File +# @var PcdList: PcdList of a File +# +class FunctionClass(object): + def __init__(self, ID = -1, Header = '', Modifier = '', Name = '', ReturnStatement = '', \ + StartLine = -1, StartColumn = -1, EndLine = -1, EndColumn = -1, \ + BodyStartLine = -1, BodyStartColumn = -1, BelongsToFile = -1, \ + IdentifierList = [], PcdList = [], \ + FunNameStartLine = -1, FunNameStartColumn = -1): + self.ID = ID + self.Header = Header + self.Modifier = Modifier + self.Name = Name + self.ReturnStatement = ReturnStatement + self.StartLine = StartLine + self.StartColumn = StartColumn + self.EndLine = EndLine + self.EndColumn = EndColumn + self.BodyStartLine = BodyStartLine + self.BodyStartColumn = BodyStartColumn + self.BelongsToFile = BelongsToFile + self.FunNameStartLine = FunNameStartLine + self.FunNameStartColumn = FunNameStartColumn + + self.IdentifierList = IdentifierList + self.PcdList = PcdList + +## IdentifierClass +# +# This class defines a structure of a variable +# +# @param ID: ID of a Identifier +# @param Modifier: Modifier of a Identifier +# @param Type: Type of a Identifier +# @param Name: Name of a Identifier +# @param Value: Value of a Identifier +# @param Model: Model of a Identifier +# @param BelongsToFile: The Identifier belongs to which file +# @param BelongsToFunction: The Identifier belongs to which function +# @param StartLine: StartLine of a Identifier +# @param StartColumn: StartColumn of a Identifier +# @param EndLine: EndLine of a Identifier +# @param EndColumn: EndColumn of a Identifier +# +# @var ID: ID of a Identifier +# @var Modifier: Modifier of a Identifier +# @var Type: Type of a Identifier +# @var Name: Name of a Identifier +# @var Value: Value of a Identifier +# @var Model: Model of a Identifier +# @var BelongsToFile: The Identifier belongs to which file +# @var BelongsToFunction: The Identifier belongs to which function +# @var StartLine: StartLine of a Identifier +# @var StartColumn: StartColumn of a Identifier +# @var EndLine: EndLine of a Identifier +# @var EndColumn: EndColumn of a Identifier +# +class IdentifierClass(object): + def __init__(self, ID = -1, Modifier = '', Type = '', Name = '', Value = '', Model = MODEL_UNKNOWN, \ + BelongsToFile = -1, BelongsToFunction = -1, StartLine = -1, StartColumn = -1, EndLine = -1, EndColumn = -1): + self.ID = ID + self.Modifier = Modifier + self.Type = Type + self.Name = Name + self.Value = Value + self.Model = Model + self.BelongsToFile = BelongsToFile + self.BelongsToFunction = BelongsToFunction + self.StartLine = StartLine + self.StartColumn = StartColumn + self.EndLine = EndLine + self.EndColumn = EndColumn + +## PcdClass +# +# This class defines a structure of a Pcd +# +# @param ID: ID of a Pcd +# @param CName: CName of a Pcd +# @param TokenSpaceGuidCName: TokenSpaceGuidCName of a Pcd +# @param Token: Token of a Pcd +# @param DatumType: DatumType of a Pcd +# @param Model: Model of a Pcd +# @param BelongsToFile: The Pcd belongs to which file +# @param BelongsToFunction: The Pcd belongs to which function +# @param StartLine: StartLine of a Pcd +# @param StartColumn: StartColumn of a Pcd +# @param EndLine: EndLine of a Pcd +# @param EndColumn: EndColumn of a Pcd +# +# @var ID: ID of a Pcd +# @var CName: CName of a Pcd +# @var TokenSpaceGuidCName: TokenSpaceGuidCName of a Pcd +# @var Token: Token of a Pcd +# @var DatumType: DatumType of a Pcd +# @var Model: Model of a Pcd +# @var BelongsToFile: The Pcd belongs to which file +# @var BelongsToFunction: The Pcd belongs to which function +# @var StartLine: StartLine of a Pcd +# @var StartColumn: StartColumn of a Pcd +# @var EndLine: EndLine of a Pcd +# @var EndColumn: EndColumn of a Pcd +# +class PcdDataClass(object): + def __init__(self, ID = -1, CName = '', TokenSpaceGuidCName = '', Token = '', DatumType = '', Model = MODEL_UNKNOWN, \ + BelongsToFile = -1, BelongsToFunction = -1, StartLine = -1, StartColumn = -1, EndLine = -1, EndColumn = -1): + self.ID = ID + self.CName = CName + self.TokenSpaceGuidCName = TokenSpaceGuidCName + self.Token = Token + self.DatumType = DatumType + self.BelongsToFile = BelongsToFile + self.BelongsToFunction = BelongsToFunction + self.StartLine = StartLine + self.StartColumn = StartColumn + self.EndLine = EndLine + self.EndColumn = EndColumn + +## FileClass +# +# This class defines a structure of a file +# +# @param ID: ID of a File +# @param Name: Name of a File +# @param ExtName: ExtName of a File +# @param Path: Path of a File +# @param FullPath: FullPath of a File +# @param Model: Model of a File +# @param TimeStamp: TimeStamp of a File +# @param FunctionList: FunctionList of a File +# @param IdentifierList: IdentifierList of a File +# @param PcdList: PcdList of a File +# +# @var ID: ID of a File +# @var Name: Name of a File +# @var ExtName: ExtName of a File +# @var Path: Path of a File +# @var FullPath: FullPath of a File +# @var Model: Model of a File +# @var TimeStamp: TimeStamp of a File +# @var FunctionList: FunctionList of a File +# @var IdentifierList: IdentifierList of a File +# @var PcdList: PcdList of a File +# +class FileClass(object): + def __init__(self, ID = -1, Name = '', ExtName = '', Path = '', FullPath = '', Model = MODEL_UNKNOWN, TimeStamp = '', \ + FunctionList = [], IdentifierList = [], PcdList = []): + self.ID = ID + self.Name = Name + self.ExtName = ExtName + self.Path = Path + self.FullPath = FullPath + self.Model = Model + self.TimeStamp = TimeStamp + + self.FunctionList = FunctionList + self.IdentifierList = IdentifierList + self.PcdList = PcdList diff --git a/tools/python/CommonDataClass/Exceptions.py b/tools/python/CommonDataClass/Exceptions.py new file mode 100755 index 0000000..4489b75 --- /dev/null +++ b/tools/python/CommonDataClass/Exceptions.py @@ -0,0 +1,23 @@ +## @file +# This file is used to define common Exceptions class used in python tools +# +# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent + +## Exceptions used in Expression +class EvaluationException(Exception): + pass + +class BadExpression(EvaluationException): + pass + +class WrnExpression(Exception): + pass + +## Exceptions used in macro replacements +class MacroException(Exception): + pass + +class SymbolNotFound(MacroException): + pass + diff --git a/tools/python/CommonDataClass/__init__.py b/tools/python/CommonDataClass/__init__.py new file mode 100755 index 0000000..81af4c0 --- /dev/null +++ b/tools/python/CommonDataClass/__init__.py @@ -0,0 +1,9 @@ +## @file +# Python 'CommonDataClass' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/tools/python/Trim/Trim.py b/tools/python/Trim/Trim.py new file mode 100755 index 0000000..24c3faf --- /dev/null +++ b/tools/python/Trim/Trim.py @@ -0,0 +1,551 @@ +## @file +# Trim files preprocessed by compiler +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +import Common.LongFilePathOs as os +import sys +import re +from io import BytesIO +import codecs +from optparse import OptionParser +from optparse import make_option +from Common.BuildToolError import * +from Common.Misc import * +from Common.DataType import * +from Common.BuildVersion import gBUILD_VERSION +import Common.EdkLogger as EdkLogger +from Common.LongFilePathSupport import OpenLongFilePath as open + +# Version and Copyright +__version_number__ = ("0.10" + " " + gBUILD_VERSION) +__version__ = "%prog Version " + __version_number__ +__copyright__ = "Copyright (c) 2007-2018, Intel Corporation. All rights reserved." + +## Regular expression for matching Line Control directive like "#line xxx" +gLineControlDirective = re.compile('^\s*#(?:line)?\s+([0-9]+)\s+"*([^"]*)"') +## Regular expression for matching "typedef struct" +gTypedefPattern = re.compile("^\s*typedef\s+struct(\s+\w+)?\s*[{]*$", re.MULTILINE) +## Regular expression for matching "#pragma pack" +gPragmaPattern = re.compile("^\s*#pragma\s+pack", re.MULTILINE) +## Regular expression for matching "typedef" +gTypedef_SinglePattern = re.compile("^\s*typedef", re.MULTILINE) +## Regular expression for matching "typedef struct, typedef union, struct, union" +gTypedef_MulPattern = re.compile("^\s*(typedef)?\s+(struct|union)(\s+\w+)?\s*[{]*$", re.MULTILINE) + +# +# The following number pattern match will only match if following criteria is met: +# There is leading non-(alphanumeric or _) character, and no following alphanumeric or _ +# as the pattern is greedily match, so it is ok for the gDecNumberPattern or gHexNumberPattern to grab the maximum match +# +## Regular expression for matching HEX number +gHexNumberPattern = re.compile("(?<=[^a-zA-Z0-9_])(0[xX])([0-9a-fA-F]+)(U(?=$|[^a-zA-Z0-9_]))?") +## Regular expression for matching decimal number with 'U' postfix +gDecNumberPattern = re.compile("(?<=[^a-zA-Z0-9_])([0-9]+)U(?=$|[^a-zA-Z0-9_])") +## Regular expression for matching constant with 'ULL' 'LL' postfix +gLongNumberPattern = re.compile("(?<=[^a-zA-Z0-9_])(0[xX][0-9a-fA-F]+|[0-9]+)U?LL(?=$|[^a-zA-Z0-9_])") + +## Regular expression for matching "Include ()" in asl file +gAslIncludePattern = re.compile("^(\s*)[iI]nclude\s*\(\"?([^\"\(\)]+)\"\)", re.MULTILINE) +## Regular expression for matching C style #include "XXX.asl" in asl file +gAslCIncludePattern = re.compile(r'^(\s*)#include\s*[<"]\s*([-\\/\w.]+)\s*([>"])', re.MULTILINE) +## Patterns used to convert EDK conventions to EDK2 ECP conventions + +## file cache to avoid circular include in ASL file +gIncludedAslFile = [] + +## Trim preprocessed source code +# +# Remove extra content made by preprocessor. The preprocessor must enable the +# line number generation option when preprocessing. +# +# @param Source File to be trimmed +# @param Target File to store the trimmed content +# @param Convert If True, convert standard HEX format to MASM format +# +def TrimPreprocessedFile(Source, Target, ConvertHex, TrimLong): + CreateDirectory(os.path.dirname(Target)) + try: + with open(Source, "r") as File: + Lines = File.readlines() + except IOError: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Source) + except: + EdkLogger.error("Trim", AUTOGEN_ERROR, "TrimPreprocessedFile: Error while processing file", File=Source) + + PreprocessedFile = "" + InjectedFile = "" + LineIndexOfOriginalFile = None + NewLines = [] + LineControlDirectiveFound = False + for Index in range(len(Lines)): + Line = Lines[Index] + # + # Find out the name of files injected by preprocessor from the lines + # with Line Control directive + # + MatchList = gLineControlDirective.findall(Line) + if MatchList != []: + MatchList = MatchList[0] + if len(MatchList) == 2: + LineNumber = int(MatchList[0], 0) + InjectedFile = MatchList[1] + InjectedFile = os.path.normpath(InjectedFile) + InjectedFile = os.path.normcase(InjectedFile) + # The first injected file must be the preprocessed file itself + if PreprocessedFile == "": + PreprocessedFile = InjectedFile + LineControlDirectiveFound = True + continue + elif PreprocessedFile == "" or InjectedFile != PreprocessedFile: + continue + + if LineIndexOfOriginalFile is None: + # + # Any non-empty lines must be from original preprocessed file. + # And this must be the first one. + # + LineIndexOfOriginalFile = Index + EdkLogger.verbose("Found original file content starting from line %d" + % (LineIndexOfOriginalFile + 1)) + + if TrimLong: + Line = gLongNumberPattern.sub(r"\1", Line) + # convert HEX number format if indicated + if ConvertHex: + Line = gHexNumberPattern.sub(r"0\2h", Line) + else: + Line = gHexNumberPattern.sub(r"\1\2", Line) + + # convert Decimal number format + Line = gDecNumberPattern.sub(r"\1", Line) + + if LineNumber is not None: + EdkLogger.verbose("Got line directive: line=%d" % LineNumber) + # in case preprocessor removed some lines, like blank or comment lines + if LineNumber <= len(NewLines): + # possible? + NewLines[LineNumber - 1] = Line + else: + if LineNumber > (len(NewLines) + 1): + for LineIndex in range(len(NewLines), LineNumber-1): + NewLines.append(TAB_LINE_BREAK) + NewLines.append(Line) + LineNumber = None + EdkLogger.verbose("Now we have lines: %d" % len(NewLines)) + else: + NewLines.append(Line) + + # in case there's no line directive or linemarker found + if (not LineControlDirectiveFound) and NewLines == []: + MulPatternFlag = False + SinglePatternFlag = False + Brace = 0 + for Index in range(len(Lines)): + Line = Lines[Index] + if MulPatternFlag == False and gTypedef_MulPattern.search(Line) is None: + if SinglePatternFlag == False and gTypedef_SinglePattern.search(Line) is None: + # remove "#pragram pack" directive + if gPragmaPattern.search(Line) is None: + NewLines.append(Line) + continue + elif SinglePatternFlag == False: + SinglePatternFlag = True + if Line.find(";") >= 0: + SinglePatternFlag = False + elif MulPatternFlag == False: + # found "typedef struct, typedef union, union, struct", keep its position and set a flag + MulPatternFlag = True + + # match { and } to find the end of typedef definition + if Line.find("{") >= 0: + Brace += 1 + elif Line.find("}") >= 0: + Brace -= 1 + + # "typedef struct, typedef union, union, struct" must end with a ";" + if Brace == 0 and Line.find(";") >= 0: + MulPatternFlag = False + + # save to file + try: + with open(Target, 'w') as File: + File.writelines(NewLines) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Target) + +## Trim preprocessed VFR file +# +# Remove extra content made by preprocessor. The preprocessor doesn't need to +# enable line number generation option when preprocessing. +# +# @param Source File to be trimmed +# @param Target File to store the trimmed content +# +def TrimPreprocessedVfr(Source, Target): + CreateDirectory(os.path.dirname(Target)) + + try: + with open(Source, "r") as File: + Lines = File.readlines() + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Source) + # read whole file + + FoundTypedef = False + Brace = 0 + TypedefStart = 0 + TypedefEnd = 0 + for Index in range(len(Lines)): + Line = Lines[Index] + # don't trim the lines from "formset" definition to the end of file + if Line.strip() == 'formset': + break + + if FoundTypedef == False and (Line.find('#line') == 0 or Line.find('# ') == 0): + # empty the line number directive if it's not aomong "typedef struct" + Lines[Index] = "\n" + continue + + if FoundTypedef == False and gTypedefPattern.search(Line) is None: + # keep "#pragram pack" directive + if gPragmaPattern.search(Line) is None: + Lines[Index] = "\n" + continue + elif FoundTypedef == False: + # found "typedef struct", keept its position and set a flag + FoundTypedef = True + TypedefStart = Index + + # match { and } to find the end of typedef definition + if Line.find("{") >= 0: + Brace += 1 + elif Line.find("}") >= 0: + Brace -= 1 + + # "typedef struct" must end with a ";" + if Brace == 0 and Line.find(";") >= 0: + FoundTypedef = False + TypedefEnd = Index + # keep all "typedef struct" except to GUID, EFI_PLABEL and PAL_CALL_RETURN + if Line.strip("} ;\r\n") in [TAB_GUID, "EFI_PLABEL", "PAL_CALL_RETURN"]: + for i in range(TypedefStart, TypedefEnd+1): + Lines[i] = "\n" + + # save all lines trimmed + try: + with open(Target, 'w') as File: + File.writelines(Lines) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Target) + +## Read the content ASL file, including ASL included, recursively +# +# @param Source File to be read +# @param Indent Spaces before the Include() statement +# @param IncludePathList The list of external include file +# @param LocalSearchPath If LocalSearchPath is specified, this path will be searched +# first for the included file; otherwise, only the path specified +# in the IncludePathList will be searched. +# +def DoInclude(Source, Indent='', IncludePathList=[], LocalSearchPath=None): + NewFileContent = [] + + try: + # + # Search LocalSearchPath first if it is specified. + # + if LocalSearchPath: + SearchPathList = [LocalSearchPath] + IncludePathList + else: + SearchPathList = IncludePathList + + for IncludePath in SearchPathList: + IncludeFile = os.path.join(IncludePath, Source) + if os.path.isfile(IncludeFile): + try: + with open(IncludeFile, "r") as File: + F = File.readlines() + except: + with codecs.open(IncludeFile, "r", encoding='utf-8') as File: + F = File.readlines() + break + else: + EdkLogger.error("Trim", "Failed to find include file %s" % Source) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Source) + + + # avoid A "include" B and B "include" A + IncludeFile = os.path.abspath(os.path.normpath(IncludeFile)) + if IncludeFile in gIncludedAslFile: + EdkLogger.warn("Trim", "Circular include", + ExtraData= "%s -> %s" % (" -> ".join(gIncludedAslFile), IncludeFile)) + return [] + gIncludedAslFile.append(IncludeFile) + + for Line in F: + LocalSearchPath = None + Result = gAslIncludePattern.findall(Line) + if len(Result) == 0: + Result = gAslCIncludePattern.findall(Line) + if len(Result) == 0 or os.path.splitext(Result[0][1])[1].lower() not in [".asl", ".asi"]: + NewFileContent.append("%s%s" % (Indent, Line)) + continue + # + # We should first search the local directory if current file are using pattern #include "XXX" + # + if Result[0][2] == '"': + LocalSearchPath = os.path.dirname(IncludeFile) + CurrentIndent = Indent + Result[0][0] + IncludedFile = Result[0][1] + NewFileContent.extend(DoInclude(IncludedFile, CurrentIndent, IncludePathList, LocalSearchPath)) + NewFileContent.append("\n") + + gIncludedAslFile.pop() + + return NewFileContent + + +## Trim ASL file +# +# Replace ASL include statement with the content the included file +# +# @param Source File to be trimmed +# @param Target File to store the trimmed content +# @param IncludePathFile The file to log the external include path +# +def TrimAslFile(Source, Target, IncludePathFile): + CreateDirectory(os.path.dirname(Target)) + + SourceDir = os.path.dirname(Source) + if SourceDir == '': + SourceDir = '.' + + # + # Add source directory as the first search directory + # + IncludePathList = [SourceDir] + + # + # If additional include path file is specified, append them all + # to the search directory list. + # + if IncludePathFile: + try: + LineNum = 0 + with open(IncludePathFile, 'r') as File: + FileLines = File.readlines() + for Line in FileLines: + LineNum += 1 + if Line.startswith("/I") or Line.startswith ("-I"): + IncludePathList.append(Line[2:].strip()) + else: + EdkLogger.warn("Trim", "Invalid include line in include list file.", IncludePathFile, LineNum) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=IncludePathFile) + + Lines = DoInclude(Source, '', IncludePathList) + + # + # Undef MIN and MAX to avoid collision in ASL source code + # + Lines.insert(0, "#undef MIN\n#undef MAX\n") + + # save all lines trimmed + try: + with open(Target, 'w') as File: + File.writelines(Lines) + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, ExtraData=Target) + +def GenerateVfrBinSec(ModuleName, DebugDir, OutputFile): + VfrNameList = [] + if os.path.isdir(DebugDir): + for CurrentDir, Dirs, Files in os.walk(DebugDir): + for FileName in Files: + Name, Ext = os.path.splitext(FileName) + if Ext == '.c' and Name != 'AutoGen': + VfrNameList.append (Name + 'Bin') + + VfrNameList.append (ModuleName + 'Strings') + + EfiFileName = os.path.join(DebugDir, ModuleName + '.efi') + MapFileName = os.path.join(DebugDir, ModuleName + '.map') + VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, VfrNameList) + + if not VfrUniOffsetList: + return + + try: + fInputfile = open(OutputFile, "wb+") + except: + EdkLogger.error("Trim", FILE_OPEN_FAILURE, "File open failed for %s" %OutputFile, None) + + # Use a instance of BytesIO to cache data + fStringIO = BytesIO() + + for Item in VfrUniOffsetList: + if (Item[0].find("Strings") != -1): + # + # UNI offset in image. + # GUID + Offset + # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } } + # + UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f' + fStringIO.write(UniGuid) + UniValue = pack ('Q', int (Item[1], 16)) + fStringIO.write (UniValue) + else: + # + # VFR binary offset in image. + # GUID + Offset + # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }; + # + VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2' + fStringIO.write(VfrGuid) + type (Item[1]) + VfrValue = pack ('Q', int (Item[1], 16)) + fStringIO.write (VfrValue) + + # + # write data into file. + # + try : + fInputfile.write (fStringIO.getvalue()) + except: + EdkLogger.error("Trim", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." %OutputFile, None) + + fStringIO.close () + fInputfile.close () + + +## Parse command line options +# +# Using standard Python module optparse to parse command line option of this tool. +# +# @retval Options A optparse.Values object containing the parsed options +# @retval InputFile Path of file to be trimmed +# +def Options(): + OptionList = [ + make_option("-s", "--source-code", dest="FileType", const="SourceCode", action="store_const", + help="The input file is preprocessed source code, including C or assembly code"), + make_option("-r", "--vfr-file", dest="FileType", const="Vfr", action="store_const", + help="The input file is preprocessed VFR file"), + make_option("--Vfr-Uni-Offset", dest="FileType", const="VfrOffsetBin", action="store_const", + help="The input file is EFI image"), + make_option("-a", "--asl-file", dest="FileType", const="Asl", action="store_const", + help="The input file is ASL file"), + make_option("-c", "--convert-hex", dest="ConvertHex", action="store_true", + help="Convert standard hex format (0xabcd) to MASM format (abcdh)"), + + make_option("-l", "--trim-long", dest="TrimLong", action="store_true", + help="Remove postfix of long number"), + make_option("-i", "--include-path-file", dest="IncludePathFile", + help="The input file is include path list to search for ASL include file"), + make_option("-o", "--output", dest="OutputFile", + help="File to store the trimmed content"), + make_option("--ModuleName", dest="ModuleName", help="The module's BASE_NAME"), + make_option("--DebugDir", dest="DebugDir", + help="Debug Output directory to store the output files"), + make_option("-v", "--verbose", dest="LogLevel", action="store_const", const=EdkLogger.VERBOSE, + help="Run verbosely"), + make_option("-d", "--debug", dest="LogLevel", type="int", + help="Run with debug information"), + make_option("-q", "--quiet", dest="LogLevel", action="store_const", const=EdkLogger.QUIET, + help="Run quietly"), + make_option("-?", action="help", help="show this help message and exit"), + ] + + # use clearer usage to override default usage message + UsageString = "%prog [-s|-r|-a|--Vfr-Uni-Offset] [-c] [-v|-d |-q] [-i ] [-o ] [--ModuleName ] [--DebugDir ] []" + + Parser = OptionParser(description=__copyright__, version=__version__, option_list=OptionList, usage=UsageString) + Parser.set_defaults(FileType="Vfr") + Parser.set_defaults(ConvertHex=False) + Parser.set_defaults(LogLevel=EdkLogger.INFO) + + Options, Args = Parser.parse_args() + + # error check + if Options.FileType == 'VfrOffsetBin': + if len(Args) == 0: + return Options, '' + elif len(Args) > 1: + EdkLogger.error("Trim", OPTION_NOT_SUPPORTED, ExtraData=Parser.get_usage()) + if len(Args) == 0: + EdkLogger.error("Trim", OPTION_MISSING, ExtraData=Parser.get_usage()) + if len(Args) > 1: + EdkLogger.error("Trim", OPTION_NOT_SUPPORTED, ExtraData=Parser.get_usage()) + + InputFile = Args[0] + return Options, InputFile + +## Entrance method +# +# This method mainly dispatch specific methods per the command line options. +# If no error found, return zero value so the caller of this tool can know +# if it's executed successfully or not. +# +# @retval 0 Tool was successful +# @retval 1 Tool failed +# +def Main(): + try: + EdkLogger.Initialize() + CommandOptions, InputFile = Options() + if CommandOptions.LogLevel < EdkLogger.DEBUG_9: + EdkLogger.SetLevel(CommandOptions.LogLevel + 1) + else: + EdkLogger.SetLevel(CommandOptions.LogLevel) + except FatalError as X: + return 1 + + try: + if CommandOptions.FileType == "Vfr": + if CommandOptions.OutputFile is None: + CommandOptions.OutputFile = os.path.splitext(InputFile)[0] + '.iii' + TrimPreprocessedVfr(InputFile, CommandOptions.OutputFile) + elif CommandOptions.FileType == "Asl": + if CommandOptions.OutputFile is None: + CommandOptions.OutputFile = os.path.splitext(InputFile)[0] + '.iii' + TrimAslFile(InputFile, CommandOptions.OutputFile, CommandOptions.IncludePathFile) + elif CommandOptions.FileType == "VfrOffsetBin": + GenerateVfrBinSec(CommandOptions.ModuleName, CommandOptions.DebugDir, CommandOptions.OutputFile) + else : + if CommandOptions.OutputFile is None: + CommandOptions.OutputFile = os.path.splitext(InputFile)[0] + '.iii' + TrimPreprocessedFile(InputFile, CommandOptions.OutputFile, CommandOptions.ConvertHex, CommandOptions.TrimLong) + except FatalError as X: + import platform + import traceback + if CommandOptions is not None and CommandOptions.LogLevel <= EdkLogger.DEBUG_9: + EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) + return 1 + except: + import traceback + import platform + EdkLogger.error( + "\nTrim", + CODE_ERROR, + "Unknown fatal error when trimming [%s]" % InputFile, + ExtraData="\n(Please send email to %s for help, attaching following call stack trace!)\n" % MSG_EDKII_MAIL_ADDR, + RaiseError=False + ) + EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc()) + return 1 + + return 0 + +if __name__ == '__main__': + r = Main() + ## 0-127 is a safe return range, and 1 is a standard default error + if r < 0 or r > 127: r = 1 + sys.exit(r) + diff --git a/tools/src/GenFw/Common/build-win.sh b/tools/src/GenFw/Common/build-win.sh new file mode 100755 index 0000000..61ec61e --- /dev/null +++ b/tools/src/GenFw/Common/build-win.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +mkdir obj 2>/dev/null +CFLAGS="-c -I ../Include/ -I src -I ../MdePkg/Include/X64/ -I ../MdePkg/Include -fshort-wchar -fno-strict-aliasing -fwrapv -fno-delete-null-pointer-checks -Wall -nostdlib -O2" + +for srcfile in src/*.c; do + srcfilebase=$(basename "$srcfile") + printf "\033[1;34mCompiling\033[1;97m\t==> $srcfilebase...\033[0m" + x86_64-w64-mingw32-gcc $CFLAGS $srcfile -o obj/${srcfilebase%.c}.o || exit 1 + printf "\033[1;32mdone\033[0m\n" +done + +x86_64-w64-mingw32-ar crs libCommon.a obj/*.o diff --git a/tools/src/GenFw/Common/build.sh b/tools/src/GenFw/Common/build.sh new file mode 100755 index 0000000..1f9d5bf --- /dev/null +++ b/tools/src/GenFw/Common/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +mkdir obj 2>/dev/null +CFLAGS="-c -I ../Include/ -I src -I ../MdePkg/Include/X64/ -I ../MdePkg/Include -fshort-wchar -fno-strict-aliasing -fwrapv -fno-delete-null-pointer-checks -Wall -nostdlib -O2" + +for srcfile in src/*.c; do + srcfilebase=$(basename "$srcfile") + printf "\033[1;34mCompiling\033[1;97m\t==> $srcfilebase...\033[0m" + gcc $CFLAGS $srcfile -o obj/${srcfilebase%.c}.o || exit 1 + printf "\033[1;32mdone\033[0m\n" +done + +ar crs libCommon.a obj/*.o diff --git a/tools/src/GenFw/Common/clean.sh b/tools/src/GenFw/Common/clean.sh new file mode 100755 index 0000000..ef28714 --- /dev/null +++ b/tools/src/GenFw/Common/clean.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +rm obj/*.o 2>/dev/null +rm libCommon.a 2>/dev/null diff --git a/tools/src/GenFw/Common/src/BasePeCoff.c b/tools/src/GenFw/Common/src/BasePeCoff.c new file mode 100644 index 0000000..3de8178 --- /dev/null +++ b/tools/src/GenFw/Common/src/BasePeCoff.c @@ -0,0 +1,1417 @@ +/** @file + + Functions to get info and load PE/COFF image. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include "PeCoffLib.h" + +typedef union { + VOID *Header; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64; +} EFI_IMAGE_OPTIONAL_HEADER_POINTER; + +STATIC +RETURN_STATUS +PeCoffLoaderGetPeHeader ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr, + OUT EFI_TE_IMAGE_HEADER **TeHdr + ); + +STATIC +RETURN_STATUS +PeCoffLoaderCheckImageType ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr, + IN EFI_TE_IMAGE_HEADER *TeHdr + ); + +STATIC +VOID * +PeCoffLoaderImageAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Address + ); + +RETURN_STATUS +PeCoffLoaderRelocateIa32Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + + +RETURN_STATUS +PeCoffLoaderRelocateArmImage ( + IN UINT16 **Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +RETURN_STATUS +PeCoffLoaderRelocateRiscVImage ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +RETURN_STATUS +PeCoffLoaderRelocateLoongArch64Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +/** + Retrieves the PE or TE Header from a PE/COFF or TE image + + @param ImageContext The context of the image being loaded + @param PeHdr The buffer in which to return the PE header + @param TeHdr The buffer in which to return the TE header + + @return RETURN_SUCCESS if the PE or TE Header is read, + Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function. +**/ +STATIC +RETURN_STATUS +PeCoffLoaderGetPeHeader ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr, + OUT EFI_TE_IMAGE_HEADER **TeHdr + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_DOS_HEADER DosHdr; + UINTN Size; + + ImageContext->IsTeImage = FALSE; + // + // Read the DOS image headers + // + Size = sizeof (EFI_IMAGE_DOS_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &Size, + &DosHdr + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + ImageContext->PeCoffHeaderOffset = 0; + if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header + // + ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew; + } + // + // Get the PE/COFF Header pointer + // + *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset); + if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + // + // Check the PE/COFF Header Signature. If not, then try to get a TE header + // + *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr; + if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { + return RETURN_UNSUPPORTED; + } + ImageContext->IsTeImage = TRUE; + } + + return RETURN_SUCCESS; +} + +/** + Checks the PE or TE header of a PE/COFF or TE image to determine if it supported + + @param ImageContext The context of the image being loaded + @param PeHdr The buffer in which to return the PE header + @param TeHdr The buffer in which to return the TE header + + @retval RETURN_SUCCESS if the PE/COFF or TE image is supported + @retval RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported. + +**/ +STATIC +RETURN_STATUS +PeCoffLoaderCheckImageType ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr, + IN EFI_TE_IMAGE_HEADER *TeHdr + ) +{ + // + // See if the machine type is supported. + // We support a native machine type (IA-32/Itanium-based) + // + if (ImageContext->IsTeImage == FALSE) { + ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine; + } else { + ImageContext->Machine = TeHdr->Machine; + } + + if (ImageContext->Machine != IMAGE_FILE_MACHINE_I386 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_X64 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_ARMTHUMB_MIXED && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_EBC && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_ARM64 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_RISCV64 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_LOONGARCH64) { + // + // unsupported PeImage machine type + // + return RETURN_UNSUPPORTED; + } + + // + // See if the image type is supported. We support EFI Applications, + // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers. + // + if (ImageContext->IsTeImage == FALSE) { + ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem; + } else { + ImageContext->ImageType = (UINT16) (TeHdr->Subsystem); + } + + if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \ + ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \ + ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \ + ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) { + // + // unsupported PeImage subsystem type + // + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +/** + Retrieves information on a PE/COFF image + + @param This Calling context + @param ImageContext The context of the image being loaded + + @retval RETURN_SUCCESS The information on the PE/COFF image was collected. + @retval RETURN_INVALID_PARAMETER ImageContext is NULL. + @retval RETURN_UNSUPPORTED The PE/COFF image is not supported. + @retval Otherwise The error status from reading the PE/COFF image using the + ImageContext->ImageRead() function + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderGetImageInfo ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry; + UINTN Size; + UINTN Index; + UINTN DebugDirectoryEntryRva; + UINTN DebugDirectoryEntryFileOffset; + UINTN SectionHeaderOffset; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry; + EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader; + + PeHdr = NULL; + TeHdr = NULL; + DebugDirectoryEntry = NULL; + DebugDirectoryEntryRva = 0; + + if (NULL == ImageContext) { + return RETURN_INVALID_PARAMETER; + } + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr); + if (RETURN_ERROR (Status)) { + return Status; + } + + // + // Verify machine type + // + Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr); + if (RETURN_ERROR (Status)) { + return Status; + } + OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader); + + // + // Retrieve the base address of the image + // + if (!(ImageContext->IsTeImage)) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase; + } else { + ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase; + } + } else { + ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + } + // + // Initialize the alternate destination address to 0 indicating that it + // should not be used. + // + ImageContext->DestinationAddress = 0; + + // + // Initialize the codeview pointer. + // + ImageContext->CodeView = NULL; + ImageContext->PdbPointer = NULL; + + // + // Three cases with regards to relocations: + // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable + // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable + // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but + // has no base relocs to apply + // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid. + // + // Look at the file header to determine if relocations have been stripped, and + // save this info in the image context for later use. + // + if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) { + ImageContext->RelocationsStripped = TRUE; + } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0) && (TeHdr->DataDirectory[0].VirtualAddress == 0)) { + ImageContext->RelocationsStripped = TRUE; + } else { + ImageContext->RelocationsStripped = FALSE; + } + + if (!(ImageContext->IsTeImage)) { + + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage; + ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment; + ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders; + + // + // Modify ImageSize to contain .PDB file name if required and initialize + // PdbRVA field... + // + if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + } + } else { + ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage; + ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment; + ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders; + + // + // Modify ImageSize to contain .PDB file name if required and initialize + // PdbRVA field... + // + if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + } + } + + if (DebugDirectoryEntryRva != 0) { + // + // Determine the file offset of the debug directory... This means we walk + // the sections to find which section contains the RVA of the debug + // directory + // + DebugDirectoryEntryFileOffset = 0; + + SectionHeaderOffset = (UINTN)( + ImageContext->PeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress && + DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = + DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData; + break; + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + if (DebugDirectoryEntryFileOffset != 0) { + for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) { + // + // Read next debug directory entry + // + Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugDirectoryEntryFileOffset + Index, + &Size, + &DebugEntry + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index); + if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) { + ImageContext->ImageSize += DebugEntry.SizeOfData; + } + + return RETURN_SUCCESS; + } + } + } + } + } else { + ImageContext->ImageSize = 0; + ImageContext->SectionAlignment = 4096; + ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize; + + DebugDirectoryEntry = &TeHdr->DataDirectory[1]; + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER)); + + DebugDirectoryEntryFileOffset = 0; + + for (Index = 0; Index < TeHdr->NumberOfSections;) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress && + DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - + SectionHeader.VirtualAddress + + SectionHeader.PointerToRawData + + sizeof (EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize; + + // + // File offset of the debug directory was found, if this is not the last + // section, then skip to the last section for calculating the image size. + // + if (Index < (UINTN) TeHdr->NumberOfSections - 1) { + SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER); + Index = TeHdr->NumberOfSections - 1; + continue; + } + } + + // + // In Te image header there is not a field to describe the ImageSize. + // Actually, the ImageSize equals the RVA plus the VirtualSize of + // the last section mapped into memory (Must be rounded up to + // a multiple of Section Alignment). Per the PE/COFF specification, the + // section headers in the Section Table must appear in order of the RVA + // values for the corresponding sections. So the ImageSize can be determined + // by the RVA and the VirtualSize of the last section header in the + // Section Table. + // + if ((++Index) == (UINTN) TeHdr->NumberOfSections) { + ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize + + ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1); + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + if (DebugDirectoryEntryFileOffset != 0) { + for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) { + // + // Read next debug directory entry + // + Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugDirectoryEntryFileOffset, + &Size, + &DebugEntry + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index); + return RETURN_SUCCESS; + } + } + } + } + + return RETURN_SUCCESS; +} + +/** + Converts an image address to the loaded address + + @param ImageContext The context of the image being loaded + @param Address The address to be converted to the loaded address + + @return NULL if the address can not be converted, otherwise, the converted address + +--*/ +STATIC +VOID * +PeCoffLoaderImageAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Address + ) +{ + if (Address >= ImageContext->ImageSize) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; + return NULL; + } + + return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address); +} + +/** + Relocates a PE/COFF image in memory + + @param This Calling context + @param ImageContext Contains information on the loaded image to relocate + + @retval RETURN_SUCCESS if the PE/COFF image was relocated + @retval RETURN_LOAD_ERROR if the image is not a valid PE/COFF image + @retval RETURN_UNSUPPORTED not support + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_DATA_DIRECTORY *RelocDir; + UINT64 Adjust; + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + CHAR8 *Fixup; + CHAR8 *FixupBase; + UINT16 *F16; + UINT32 *F32; + UINT64 *F64; + CHAR8 *FixupData; + PHYSICAL_ADDRESS BaseAddress; + UINT16 MachineType; + EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader; + + PeHdr = NULL; + TeHdr = NULL; + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + // + // If there are no relocation entries, then we are done + // + if (ImageContext->RelocationsStripped) { + return RETURN_SUCCESS; + } + + // + // Use DestinationAddress field of ImageContext as the relocation address even if it is 0. + // + BaseAddress = ImageContext->DestinationAddress; + + if (!(ImageContext->IsTeImage)) { + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress + + ImageContext->PeCoffHeaderOffset); + OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader); + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase; + OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress; + MachineType = ImageContext->Machine; + // + // Find the relocation block + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if ((RelocDir != NULL) && (RelocDir->Size > 0)) { + RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress); + RelocBaseEnd = PeCoffLoaderImageAddress ( + ImageContext, + RelocDir->VirtualAddress + RelocDir->Size - 1 + ); + if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } else { + Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase; + OptionHeader.Optional64->ImageBase = BaseAddress; + MachineType = ImageContext->Machine; + // + // Find the relocation block + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if ((RelocDir != NULL) && (RelocDir->Size > 0)) { + RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress); + RelocBaseEnd = PeCoffLoaderImageAddress ( + ImageContext, + RelocDir->VirtualAddress + RelocDir->Size - 1 + ); + if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } + } else { + TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress); + Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase); + TeHdr->ImageBase = (UINT64) (BaseAddress); + MachineType = TeHdr->Machine; + + // + // Find the relocation block + // + RelocDir = &TeHdr->DataDirectory[0]; + RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)( + ImageContext->ImageAddress + + RelocDir->VirtualAddress + + sizeof(EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize + ); + RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1); + } + + // + // Run the relocation information and apply the fixups + // + FixupData = ImageContext->FixupData; + while (RelocBase < RelocBaseEnd) { + + Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION)); + RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock); + if (!(ImageContext->IsTeImage)) { + FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress); + if (FixupBase == NULL) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + } else { + FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress + + RelocBase->VirtualAddress + + sizeof(EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize + ); + } + + if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) || + (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + + (UINTN)ImageContext->ImageSize)) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + + // + // Run this relocation record + // + while (Reloc < RelocEnd) { + + Fixup = FixupBase + (*Reloc & 0xFFF); + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_ABSOLUTE: + break; + + case EFI_IMAGE_REL_BASED_HIGH: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16))); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof (UINT16); + } + break; + + case EFI_IMAGE_REL_BASED_LOW: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16) (*F16 + (UINT16) Adjust); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof (UINT16); + } + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + F32 = (UINT32 *) Fixup; + *F32 = *F32 + (UINT32) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32)); + *(UINT32 *) FixupData = *F32; + FixupData = FixupData + sizeof (UINT32); + } + break; + + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *F64 = *F64 + (UINT64) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64)); + *(UINT64 *) FixupData = *F64; + FixupData = FixupData + sizeof (UINT64); + } + break; + + case EFI_IMAGE_REL_BASED_HIGHADJ: + // + // Return the same EFI_UNSUPPORTED return code as + // PeCoffLoaderRelocateImageEx() returns if it does not recognize + // the relocation type. + // + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_UNSUPPORTED; + + default: + switch (MachineType) { + case IMAGE_FILE_MACHINE_I386: + Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust); + break; + case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED: + Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust); + break; + case IMAGE_FILE_MACHINE_RISCV64: + Status = PeCoffLoaderRelocateRiscVImage (Reloc, Fixup, &FixupData, Adjust); + break; + case IMAGE_FILE_MACHINE_LOONGARCH64: + Status = PeCoffLoaderRelocateLoongArch64Image (Reloc, Fixup, &FixupData, Adjust); + break; + default: + Status = RETURN_UNSUPPORTED; + break; + } + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return Status; + } + } + + // + // Next relocation record + // + Reloc += 1; + } + + // + // Next reloc block + // + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + } + + return RETURN_SUCCESS; +} + +/** + Loads a PE/COFF image into memory + + @param This Calling context + @param ImageContext Contains information on image to load into memory + + @retval RETURN_SUCCESS if the PE/COFF image was loaded + @retval RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer + @retval RETURN_LOAD_ERROR if the image is a runtime driver with no relocations + @retval RETURN_INVALID_PARAMETER if the image address is invalid + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_TE_IMAGE_HEADER *TeHdr; + PE_COFF_LOADER_IMAGE_CONTEXT CheckContext; + EFI_IMAGE_SECTION_HEADER *FirstSection; + EFI_IMAGE_SECTION_HEADER *Section; + UINTN NumberOfSections; + UINTN Index; + CHAR8 *Base; + CHAR8 *End; + CHAR8 *MaxEnd; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN Size; + UINT32 TempDebugEntryRva; + EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader; + + PeHdr = NULL; + TeHdr = NULL; + OptionHeader.Header = NULL; + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + // + // Copy the provided context info into our local version, get what we + // can from the original image, and then use that to make sure everything + // is legit. + // + CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); + + Status = PeCoffLoaderGetImageInfo (&CheckContext); + if (RETURN_ERROR (Status)) { + return Status; + } + + // + // Make sure there is enough allocated space for the image being loaded + // + if (ImageContext->ImageSize < CheckContext.ImageSize) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE; + return RETURN_BUFFER_TOO_SMALL; + } + + // + // If there's no relocations, then make sure it's not a runtime driver, + // and that it's being loaded at the linked address. + // + if (CheckContext.RelocationsStripped) { + // + // If the image does not contain relocations and it is a runtime driver + // then return an error. + // + if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return RETURN_LOAD_ERROR; + } + // + // If the image does not contain relocations, and the requested load address + // is not the linked address, then return an error. + // + if (CheckContext.ImageAddress != ImageContext->ImageAddress) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; + return RETURN_INVALID_PARAMETER; + } + } + // + // Make sure the allocated space has the proper section alignment + // + if (!(ImageContext->IsTeImage)) { + if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT; + return RETURN_INVALID_PARAMETER; + } + } + // + // Read the entire PE/COFF or TE header into memory + // + if (!(ImageContext->IsTeImage)) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &ImageContext->SizeOfHeaders, + (VOID *) (UINTN) ImageContext->ImageAddress + ); + + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) + ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset); + + OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader); + + FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN)ImageContext->ImageAddress + + ImageContext->PeCoffHeaderOffset + + sizeof(UINT32) + + sizeof(EFI_IMAGE_FILE_HEADER) + + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections); + } else { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &ImageContext->SizeOfHeaders, + (VOID *) (UINTN) ImageContext->ImageAddress + ); + + TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress); + + FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN)ImageContext->ImageAddress + + sizeof(EFI_TE_IMAGE_HEADER) + ); + NumberOfSections = (UINTN) (TeHdr->NumberOfSections); + + } + + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return RETURN_LOAD_ERROR; + } + + // + // Load each section of the image + // + Section = FirstSection; + for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) { + + // + // Compute sections address + // + Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress); + End = PeCoffLoaderImageAddress ( + ImageContext, + Section->VirtualAddress + Section->Misc.VirtualSize - 1 + ); + + // + // If the base start or end address resolved to 0, then fail. + // + if ((Base == NULL) || (End == NULL)) { + ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED; + return RETURN_LOAD_ERROR; + } + + + if (ImageContext->IsTeImage) { + Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize); + End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize); + } + + if (End > MaxEnd) { + MaxEnd = End; + } + + // + // Read the section + // + Size = (UINTN) Section->Misc.VirtualSize; + if ((Size == 0) || (Size > Section->SizeOfRawData)) { + Size = (UINTN) Section->SizeOfRawData; + } + + if (Section->SizeOfRawData) { + if (!(ImageContext->IsTeImage)) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + Section->PointerToRawData, + &Size, + Base + ); + } else { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize, + &Size, + Base + ); + } + + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + } + + // + // If raw size is less then virt size, zero fill the remaining + // + + if (Size < Section->Misc.VirtualSize) { + ZeroMem (Base + Size, Section->Misc.VirtualSize - Size); + } + + // + // Next Section + // + Section += 1; + } + + // + // Get image's entry point + // + if (!(ImageContext->IsTeImage)) { + ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress ( + ImageContext, + PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint + ); + } else { + ImageContext->EntryPoint = (UINTN)ImageContext->ImageAddress + + (UINTN)TeHdr->AddressOfEntryPoint + + (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - + (UINTN) TeHdr->StrippedSize; + } + + // + // Determine the size of the fixup data + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (!(ImageContext->IsTeImage)) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) + &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); + } else { + ImageContext->FixupDataSize = 0; + } + } else { + if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) + &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); + } else { + ImageContext->FixupDataSize = 0; + } + } + } else { + DirectoryEntry = &TeHdr->DataDirectory[0]; + ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); + } + // + // Consumer must allocate a buffer for the relocation fixup log. + // Only used for runtime drivers. + // + ImageContext->FixupData = NULL; + + // + // Load the Codeview info if present + // + if (ImageContext->DebugDirectoryEntryRva != 0) { + if (!(ImageContext->IsTeImage)) { + DebugEntry = PeCoffLoaderImageAddress ( + ImageContext, + ImageContext->DebugDirectoryEntryRva + ); + } else { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)( + ImageContext->ImageAddress + + ImageContext->DebugDirectoryEntryRva + + sizeof(EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize + ); + } + + if (DebugEntry != NULL) { + TempDebugEntryRva = DebugEntry->RVA; + if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) { + Section--; + if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) { + TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize; + } else { + TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData; + } + } + + if (TempDebugEntryRva != 0) { + if (!(ImageContext->IsTeImage)) { + ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva); + } else { + ImageContext->CodeView = (VOID *)( + (UINTN)ImageContext->ImageAddress + + (UINTN)TempDebugEntryRva + + (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - + (UINTN) TeHdr->StrippedSize + ); + } + + if (ImageContext->CodeView == NULL) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return RETURN_LOAD_ERROR; + } + + if (DebugEntry->RVA == 0) { + Size = DebugEntry->SizeOfData; + if (!(ImageContext->IsTeImage)) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugEntry->FileOffset, + &Size, + ImageContext->CodeView + ); + } else { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize, + &Size, + ImageContext->CodeView + ); + // + // Should we apply fix up to this field according to the size difference between PE and TE? + // Because now we maintain TE header fields unfixed, this field will also remain as they are + // in original PE image. + // + } + + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return RETURN_LOAD_ERROR; + } + + DebugEntry->RVA = TempDebugEntryRva; + } + + switch (*(UINT32 *) ImageContext->CodeView) { + case CODEVIEW_SIGNATURE_NB10: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); + break; + + case CODEVIEW_SIGNATURE_RSDS: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); + break; + + case CODEVIEW_SIGNATURE_MTOC: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY); + + default: + break; + } + } + } + } + + return Status; +} + +/** + Returns a pointer to the PDB file name for a raw PE/COFF image that is not + loaded into system memory with the PE/COFF Loader Library functions. + + Returns the PDB file name for the PE/COFF image specified by Pe32Data. If + the PE/COFF image specified by Pe32Data is not a valid, then NULL is + returned. If the PE/COFF image specified by Pe32Data does not contain a + debug directory entry, then NULL is returned. If the debug directory entry + in the PE/COFF image specified by Pe32Data does not contain a PDB file name, + then NULL is returned. + If Pe32Data is NULL, then return NULL. + + @param Pe32Data Pointer to the PE/COFF image that is loaded in system + memory. + + @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL + if it cannot be retrieved. + +**/ +VOID * +EFIAPI +PeCoffLoaderGetPdbPointer ( + IN VOID *Pe32Data + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN DirCount; + VOID *CodeViewEntryPointer; + INTN TEImageAdjust; + UINT32 NumberOfRvaAndSizes; + UINT16 Magic; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINT32 Index, Index1; + + if (Pe32Data == NULL) { + return NULL; + } + + TEImageAdjust = 0; + DirectoryEntry = NULL; + DebugEntry = NULL; + NumberOfRvaAndSizes = 0; + Index = 0; + Index1 = 0; + SectionHeader = NULL; + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) { + if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { + DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; + TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; + + // + // Get the DebugEntry offset in the raw data image. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1); + Index = Hdr.Te->NumberOfSections; + for (Index1 = 0; Index1 < Index; Index1 ++) { + if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && + (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te + + DirectoryEntry->VirtualAddress - + SectionHeader [Index1].VirtualAddress + + SectionHeader [Index1].PointerToRawData + + TEImageAdjust); + break; + } + } + } + } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) { + // + // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic. + // It is due to backward-compatibility, for some system might + // generate PE32+ image with PE32 Magic. + // + switch (Hdr.Pe32->FileHeader.Machine) { + case IMAGE_FILE_MACHINE_I386: + case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED: + // + // Assume PE32 image with IA32 Machine field. + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + break; + case IMAGE_FILE_MACHINE_X64: + // + // Assume PE32+ image with X64 Machine field + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + default: + // + // For unknown Machine field, use Magic in optional Header + // + Magic = Hdr.Pe32->OptionalHeader.Magic; + } + + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( + (UINT8 *) Hdr.Pe32 + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + Hdr.Pe32->FileHeader.SizeOfOptionalHeader + ); + Index = Hdr.Pe32->FileHeader.NumberOfSections; + + if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) { + // + // Use PE32 offset get Debug Directory Entry + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // + // Use PE32+ offset get Debug Directory Entry + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } + + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) { + DirectoryEntry = NULL; + DebugEntry = NULL; + } else { + // + // Get the DebugEntry offset in the raw data image. + // + for (Index1 = 0; Index1 < Index; Index1 ++) { + if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && + (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ( + (UINTN) Pe32Data + + DirectoryEntry->VirtualAddress - + SectionHeader[Index1].VirtualAddress + + SectionHeader[Index1].PointerToRawData); + break; + } + } + } + } else { + return NULL; + } + + if (NULL == DebugEntry || NULL == DirectoryEntry) { + return NULL; + } + + // + // Scan the directory to find the debug entry. + // + for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) { + if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) { + if (DebugEntry->SizeOfData > 0) { + // + // Get the DebugEntry offset in the raw data image. + // + CodeViewEntryPointer = NULL; + for (Index1 = 0; Index1 < Index; Index1 ++) { + if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) && + (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) { + CodeViewEntryPointer = (VOID *) ( + ((UINTN)Pe32Data) + + (UINTN) DebugEntry->RVA - + SectionHeader[Index1].VirtualAddress + + SectionHeader[Index1].PointerToRawData + + (UINTN)TEImageAdjust); + break; + } + } + if (Index1 >= Index) { + // + // Can't find CodeViewEntryPointer in raw PE/COFF image. + // + continue; + } + switch (* (UINT32 *) CodeViewEntryPointer) { + case CODEVIEW_SIGNATURE_NB10: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)); + case CODEVIEW_SIGNATURE_RSDS: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)); + case CODEVIEW_SIGNATURE_MTOC: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)); + default: + break; + } + } + } + } + + return NULL; +} + + +RETURN_STATUS +EFIAPI +PeCoffLoaderGetEntryPoint ( + IN VOID *Pe32Data, + OUT VOID **EntryPoint, + OUT VOID **BaseOfImage + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + // + // Calculate the entry point relative to the start of the image. + // AddressOfEntryPoint is common for PE32 & PE32+ + // + if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize); + return RETURN_SUCCESS; + } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint; + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase; + } else { + *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase; + } + *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage); + return RETURN_SUCCESS; + } + + return RETURN_UNSUPPORTED; +} diff --git a/tools/src/GenFw/Common/src/BinderFuncs.c b/tools/src/GenFw/Common/src/BinderFuncs.c new file mode 100644 index 0000000..507b70a --- /dev/null +++ b/tools/src/GenFw/Common/src/BinderFuncs.c @@ -0,0 +1,74 @@ +/** @file +Binder function implementations for ANSI C libraries. + +Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BinderFuncs.h" +#include "CommonLib.h" +#include +#include + +// +// Binder Function Implementations +// + +VOID * +CommonLibBinderAllocate ( + IN UINTN Size + ) +{ + return (VOID *) malloc (Size); +} + +VOID +CommonLibBinderFree ( + IN VOID *Pointer + ) +{ + free (Pointer); +} + +VOID +CommonLibBinderCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +{ + memmove (Destination, Source, Length); +} + +VOID +CommonLibBinderSetMem ( + IN VOID *Destination, + IN UINTN Length, + IN UINT8 Value + ) +{ + memset (Destination, Value, Length); +} + +INTN +CommonLibBinderCompareMem ( + IN VOID *MemOne, + IN VOID *MemTwo, + IN UINTN Length + ) +{ + return memcmp (MemOne, MemTwo, Length); +} + +BOOLEAN +CommonLibBinderCompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ) +{ + return CompareGuid (Guid1, Guid2) ? FALSE : TRUE; +} + + + diff --git a/tools/src/GenFw/Common/src/BinderFuncs.h b/tools/src/GenFw/Common/src/BinderFuncs.h new file mode 100644 index 0000000..accd22d --- /dev/null +++ b/tools/src/GenFw/Common/src/BinderFuncs.h @@ -0,0 +1,61 @@ +/** @file +Prototypes for binder functions that allow common code to be written which then +links to implementation of these functions which is appropriate for the specific +environment that they are running under. + +Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef BinderFuncs_h_INCLUDED +#define BinderFuncs_h_INCLUDED + +#include "Common/UefiBaseTypes.h" + +// +// Binder Function Prototypes +// +// These binding functions must be implemented externally as appropriate for +// the environment that the code will be running under. +// + +VOID * +CommonLibBinderAllocate ( + IN UINTN Size + ); + +VOID +CommonLibBinderFree ( + IN VOID *Pointer + ); + +VOID +CommonLibBinderCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ); + +VOID +CommonLibBinderSetMem ( + IN VOID *Destination, + IN UINTN Length, + IN UINT8 Value + ); + +INTN +CommonLibBinderCompareMem ( + IN VOID *MemOne, + IN VOID *MemTwo, + IN UINTN Length + ); + +BOOLEAN +CommonLibBinderCompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ); + +#endif // #ifndef CommonLibs_h_INCLUDED + diff --git a/tools/src/GenFw/Common/src/CommonLib.c b/tools/src/GenFw/Common/src/CommonLib.c new file mode 100644 index 0000000..31d36ea --- /dev/null +++ b/tools/src/GenFw/Common/src/CommonLib.c @@ -0,0 +1,2091 @@ +/** @file +Common basic Library Functions + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#endif +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" + +#define SAFE_STRING_CONSTRAINT_CHECK(Expression, Status) \ + do { \ + ASSERT (Expression); \ + if (!(Expression)) { \ + return Status; \ + } \ + } while (FALSE) + +/** + Set Buffer to zero for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set +**/ +VOID +PeiZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +{ + INT8 *Ptr; + + Ptr = Buffer; + while (Size--) { + *(Ptr++) = 0; + } +} + +/** + Copy Length bytes from Source to Destination. + + @param Destination Target of copy + @param Source Place to copy from + @param Length Number of bytes to copy +**/ +VOID +PeiCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +{ + CHAR8 *Destination8; + CHAR8 *Source8; + + Destination8 = Destination; + Source8 = Source; + while (Length--) { + *(Destination8++) = *(Source8++); + } +} + +VOID +ZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +{ + PeiZeroMem (Buffer, Size); +} + +VOID +CopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +{ + PeiCopyMem (Destination, Source, Length); +} + +/** + Compares to GUIDs + + @param Guid1 guid to compare + @param Guid2 guid to compare + + @retval = 0 if Guid1 == Guid2 + @retval != 0 if Guid1 != Guid2 +**/ +INTN +CompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ) +{ + INT32 *g1; + INT32 *g2; + INT32 r; + + // + // Compare 32 bits at a time + // + g1 = (INT32 *) Guid1; + g2 = (INT32 *) Guid2; + + r = g1[0] - g2[0]; + r |= g1[1] - g2[1]; + r |= g1[2] - g2[2]; + r |= g1[3] - g2[3]; + + return r; +} + +/** + This function opens a file and reads it into a memory buffer. The function + will allocate the memory buffer and returns the size of the buffer. + + @param InputFileName The name of the file to read. + @param InputFileImage A pointer to the memory buffer. + @param BytesRead The size of the memory buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED An error occurred. + @retval EFI_OUT_OF_RESOURCES No resource to complete operations. +**/ +EFI_STATUS +GetFileImage ( + IN CHAR8 *InputFileName, + OUT CHAR8 **InputFileImage, + OUT UINT32 *BytesRead + ) +{ + FILE *InputFile; + UINT32 FileSize; + + // + // Verify input parameters. + // + if (InputFileName == NULL || strlen (InputFileName) == 0 || InputFileImage == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Open the file and copy contents into a memory buffer. + // + // + // Open the file + // + InputFile = fopen (LongFilePath (InputFileName), "rb"); + if (InputFile == NULL) { + Error (NULL, 0, 0001, "Error opening the input file", InputFileName); + return EFI_ABORTED; + } + // + // Go to the end so that we can determine the file size + // + if (fseek (InputFile, 0, SEEK_END)) { + Error (NULL, 0, 0004, "Error reading the input file", InputFileName); + fclose (InputFile); + return EFI_ABORTED; + } + // + // Get the file size + // + FileSize = ftell (InputFile); + if (FileSize == -1) { + Error (NULL, 0, 0003, "Error parsing the input file", InputFileName); + fclose (InputFile); + return EFI_ABORTED; + } + // + // Allocate a buffer + // + *InputFileImage = malloc (FileSize); + if (*InputFileImage == NULL) { + fclose (InputFile); + return EFI_OUT_OF_RESOURCES; + } + // + // Reset to the beginning of the file + // + if (fseek (InputFile, 0, SEEK_SET)) { + Error (NULL, 0, 0004, "Error reading the input file", InputFileName); + fclose (InputFile); + free (*InputFileImage); + *InputFileImage = NULL; + return EFI_ABORTED; + } + // + // Read all of the file contents. + // + *BytesRead = fread (*InputFileImage, sizeof (UINT8), FileSize, InputFile); + if (*BytesRead != sizeof (UINT8) * FileSize) { + Error (NULL, 0, 0004, "Error reading the input file", InputFileName); + fclose (InputFile); + free (*InputFileImage); + *InputFileImage = NULL; + return EFI_ABORTED; + } + // + // Close the file + // + fclose (InputFile); + + return EFI_SUCCESS; +} + +/** + This function opens a file and writes OutputFileImage into the file. + + @param OutputFileName The name of the file to write. + @param OutputFileImage A pointer to the memory buffer. + @param BytesToWrite The size of the memory buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED An error occurred. + @retval EFI_OUT_OF_RESOURCES No resource to complete operations. +**/ +EFI_STATUS +PutFileImage ( + IN CHAR8 *OutputFileName, + IN CHAR8 *OutputFileImage, + IN UINT32 BytesToWrite + ) +{ + FILE *OutputFile; + UINT32 BytesWrote; + + // + // Verify input parameters. + // + if (OutputFileName == NULL || strlen (OutputFileName) == 0 || OutputFileImage == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Open the file and copy contents into a memory buffer. + // + // + // Open the file + // + OutputFile = fopen (LongFilePath (OutputFileName), "wb"); + if (OutputFile == NULL) { + Error (NULL, 0, 0001, "Error opening the output file", OutputFileName); + return EFI_ABORTED; + } + + // + // Write all of the file contents. + // + BytesWrote = fwrite (OutputFileImage, sizeof (UINT8), BytesToWrite, OutputFile); + if (BytesWrote != sizeof (UINT8) * BytesToWrite) { + Error (NULL, 0, 0002, "Error writing the output file", OutputFileName); + fclose (OutputFile); + return EFI_ABORTED; + } + // + // Close the file + // + fclose (OutputFile); + + return EFI_SUCCESS; +} + +/** + This function calculates the value needed for a valid UINT8 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +UINT8 +CalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + return (UINT8) (0x100 - CalculateSum8 (Buffer, Size)); +} + +/** + This function calculates the UINT8 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +UINT8 +CalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT8 Sum; + + Sum = 0; + + // + // Perform the byte sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT8) (Sum + Buffer[Index]); + } + + return Sum; +} + +/** + This function calculates the value needed for a valid UINT16 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum value needed. +**/ +UINT16 +CalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + return (UINT16) (0x10000 - CalculateSum16 (Buffer, Size)); +} + +/** + This function calculates the UINT16 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum +**/ +UINT16 +CalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT16 Sum; + + Sum = 0; + + // + // Perform the word sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT16) (Sum + Buffer[Index]); + } + + return (UINT16) Sum; +} + +/** + This function prints a GUID to STDOUT. + + @param Guid Pointer to a GUID to print. + + @retval EFI_SUCCESS The GUID was printed. + @retval EFI_INVALID_PARAMETER The input was NULL. +**/ +EFI_STATUS +PrintGuid ( + IN EFI_GUID *Guid + ) +{ + if (Guid == NULL) { + Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value"); + return EFI_INVALID_PARAMETER; + } + + printf ( + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + (unsigned) Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + return EFI_SUCCESS; +} + +/** + This function prints a GUID to a buffer + + @param Guid Pointer to a GUID to print. + @param Buffer Pointer to a user-provided buffer to print to + @param BufferLen Size of the Buffer + @param Uppercase If use upper case. + + @retval EFI_SUCCESS The GUID was printed. + @retval EFI_INVALID_PARAMETER The input was NULL. + @retval EFI_BUFFER_TOO_SMALL The input buffer was not big enough +**/ +EFI_STATUS +PrintGuidToBuffer ( + IN EFI_GUID *Guid, + IN OUT UINT8 *Buffer, + IN UINT32 BufferLen, + IN BOOLEAN Uppercase + ) +{ + if (Guid == NULL) { + Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value"); + return EFI_INVALID_PARAMETER; + } + + if (BufferLen < PRINTED_GUID_BUFFER_SIZE) { + Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with invalid buffer size"); + return EFI_BUFFER_TOO_SMALL; + } + + if (Uppercase) { + sprintf ( + (CHAR8 *)Buffer, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + (unsigned) Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + } else { + sprintf ( + (CHAR8 *)Buffer, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (unsigned) Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + } + + return EFI_SUCCESS; +} + +#ifdef __GNUC__ +#ifndef __WIN32__ +size_t _filelength(int fd) +{ + struct stat stat_buf; + fstat(fd, &stat_buf); + return stat_buf.st_size; +} +#endif + +#ifndef __CYGWIN__ +char *strlwr(char *s) +{ + char *p = s; + for(;*s;s++) { + *s = tolower(*s); + } + return p; +} +#endif +#endif + +#define WINDOWS_EXTENSION_PATH "\\\\?\\" +#define WINDOWS_UNC_EXTENSION_PATH "\\\\?\\UNC" + +// +// Global data to store full file path. It is not required to be free. +// +CHAR8 mCommonLibFullPath[MAX_LONG_FILE_PATH]; + +/** + Convert FileName to the long file path, which can support larger than 260 length. + + @param FileName FileName. + + @return LongFilePath A pointer to the converted long file path. +**/ +CHAR8 * +LongFilePath ( + IN CHAR8 *FileName + ) +{ +#ifdef __GNUC__ + // + // __GNUC__ may not be good way to differentiate unix and windows. Need more investigation here. + // unix has no limitation on file path. Just return FileName. + // + return FileName; +#else + CHAR8 *RootPath; + CHAR8 *PathPointer; + CHAR8 *NextPointer; + + PathPointer = (CHAR8 *) FileName; + + if (FileName != NULL) { + // + // Add the extension string first to support long file path. + // + mCommonLibFullPath[0] = 0; + strcpy (mCommonLibFullPath, WINDOWS_EXTENSION_PATH); + + if (strlen (FileName) > 1 && FileName[0] == '\\' && FileName[1] == '\\') { + // + // network path like \\server\share to \\?\UNC\server\share + // + strcpy (mCommonLibFullPath, WINDOWS_UNC_EXTENSION_PATH); + FileName ++; + } else if (strlen (FileName) < 3 || FileName[1] != ':' || (FileName[2] != '\\' && FileName[2] != '/')) { + // + // Relative file path. Convert it to absolute path. + // + RootPath = getcwd (NULL, 0); + if (RootPath != NULL) { + if (strlen (mCommonLibFullPath) + strlen (RootPath) > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 2000, "Invalid parameter", "RootPath is too long!"); + free (RootPath); + return NULL; + } + strncat (mCommonLibFullPath, RootPath, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + if (FileName[0] != '\\' && FileName[0] != '/') { + if (strlen (mCommonLibFullPath) + 1 > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 2000, "Invalid parameter", "RootPath is too long!"); + free (RootPath); + return NULL; + } + // + // Attach directory separator + // + strncat (mCommonLibFullPath, "\\", MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + free (RootPath); + } + } + + // + // Construct the full file path + // + if (strlen (mCommonLibFullPath) + strlen (FileName) > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 2000, "Invalid parameter", "FileName %s is too long!", FileName); + return NULL; + } + strncat (mCommonLibFullPath, FileName, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + + // + // Convert directory separator '/' to '\\' + // + PathPointer = (CHAR8 *) mCommonLibFullPath; + do { + if (*PathPointer == '/') { + *PathPointer = '\\'; + } + } while (*PathPointer ++ != '\0'); + + // + // Convert ":\\\\" to ":\\", because it doesn't work with WINDOWS_EXTENSION_PATH. + // + if ((PathPointer = strstr (mCommonLibFullPath, ":\\\\")) != NULL) { + *(PathPointer + 2) = '\0'; + strncat (mCommonLibFullPath, PathPointer + 3, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + + // + // Convert ".\\" to "", because it doesn't work with WINDOWS_EXTENSION_PATH. + // + while ((PathPointer = strstr (mCommonLibFullPath, ".\\")) != NULL) { + *PathPointer = '\0'; + strncat (mCommonLibFullPath, PathPointer + 2, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + + // + // Convert "\\.\\" to "\\", because it doesn't work with WINDOWS_EXTENSION_PATH. + // + while ((PathPointer = strstr (mCommonLibFullPath, "\\.\\")) != NULL) { + *PathPointer = '\0'; + strncat (mCommonLibFullPath, PathPointer + 2, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + + // + // Convert "\\..\\" to last directory, because it doesn't work with WINDOWS_EXTENSION_PATH. + // + while ((PathPointer = strstr (mCommonLibFullPath, "\\..\\")) != NULL) { + NextPointer = PathPointer + 3; + do { + PathPointer --; + } while (PathPointer > mCommonLibFullPath && *PathPointer != ':' && *PathPointer != '\\'); + + if (*PathPointer == '\\') { + // + // Skip one directory + // + *PathPointer = '\0'; + strncat (mCommonLibFullPath, NextPointer, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } else { + // + // No directory is found. Just break. + // + break; + } + } + + PathPointer = mCommonLibFullPath; + } + + return PathPointer; +#endif +} + +CHAR16 +InternalCharToUpper ( + CHAR16 Char + ) +{ + if (Char >= L'a' && Char <= L'z') { + return (CHAR16) (Char - (L'a' - L'A')); + } + + return Char; +} + +UINTN +StrnLenS ( + CONST CHAR16 *String, + UINTN MaxSize + ) +{ + UINTN Length; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // If String is a null pointer or MaxSize is 0, then the StrnLenS function returns zero. + // + if ((String == NULL) || (MaxSize == 0)) { + return 0; + } + + Length = 0; + while (String[Length] != 0) { + if (Length >= MaxSize - 1) { + return MaxSize; + } + Length++; + } + return Length; +} + + +VOID * +InternalAllocatePool ( + UINTN AllocationSize + ) +{ + VOID * Memory; + + Memory = malloc(AllocationSize); + ASSERT(Memory != NULL); + return Memory; +} + + +VOID * +InternalReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ) +{ + VOID *NewBuffer; + + NewBuffer = AllocateZeroPool (NewSize); + if (NewBuffer != NULL && OldBuffer != NULL) { + memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize)); + free(OldBuffer); + } + return NewBuffer; +} + +VOID * +ReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ) +{ + return InternalReallocatePool (OldSize, NewSize, OldBuffer); +} + +/** + Returns the length of a Null-terminated Unicode string. + + This function returns the number of Unicode characters in the Null-terminated + Unicode string specified by String. + + If String is NULL, then ASSERT(). + If String is not aligned on a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + + @param String A pointer to a Null-terminated Unicode string. + + @return The length of String. + +**/ +UINTN +StrLen ( + CONST CHAR16 *String + ) +{ + UINTN Length; + + ASSERT (String != NULL); + ASSERT (((UINTN) String & BIT0) == 0); + + for (Length = 0; *String != L'\0'; String++, Length++) { + // + // If PcdMaximumUnicodeStringLength is not zero, + // length should not more than PcdMaximumUnicodeStringLength + // + } + return Length; +} + +BOOLEAN +InternalSafeStringIsOverlap ( + IN VOID *Base1, + IN UINTN Size1, + IN VOID *Base2, + IN UINTN Size2 + ) +{ + if ((((UINTN)Base1 >= (UINTN)Base2) && ((UINTN)Base1 < (UINTN)Base2 + Size2)) || + (((UINTN)Base2 >= (UINTN)Base1) && ((UINTN)Base2 < (UINTN)Base1 + Size1))) { + return TRUE; + } + return FALSE; +} + +BOOLEAN +InternalSafeStringNoStrOverlap ( + IN CHAR16 *Str1, + IN UINTN Size1, + IN CHAR16 *Str2, + IN UINTN Size2 + ) +{ + return !InternalSafeStringIsOverlap (Str1, Size1 * sizeof(CHAR16), Str2, Size2 * sizeof(CHAR16)); +} + +/** + Convert a Null-terminated Unicode decimal string to a value of type UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Unicode string specified by String as a decimal number. The format of the + input Unicode string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The function will + ignore the pad space, which includes spaces or tab characters, before + [decimal digits]. The running zero in the beginning of [decimal digits] will + be ignored. Then, the function stops at the first character that is a not a + valid decimal character or a Null-terminator, whichever one comes first. + + If String is NULL, then ASSERT(). + If Data is NULL, then ASSERT(). + If String is not aligned in a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + + If String has no valid decimal digits in the above format, then 0 is stored + at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + decimal digits right after the optional pad spaces, the value of String is + stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +StrDecimalToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, OPTIONAL + UINT64 *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + *Data = 0; + + while (InternalIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINT64 - (*String - L'0'))/10)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = (*Data) * 10 + (*String - L'0'); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode hexadecimal string to a value of type + UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Unicode string specified by String as a hexadecimal number. The format of + the input Unicode string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. + If "x" appears in the input string, it must be prefixed with at least one 0. + The function will ignore the pad space, which includes spaces or tab + characters, before [zeros], [x] or [hexadecimal digit]. The running zero + before [x] or [hexadecimal digit] will be ignored. Then, the decoding starts + after [x] or the first valid hexadecimal digit. Then, the function stops at + the first character that is a not a valid hexadecimal character or NULL, + whichever one comes first. + + If String is NULL, then ASSERT(). + If Data is NULL, then ASSERT(). + If String is not aligned in a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + + If String has no valid hexadecimal digits in the above format, then 0 is + stored at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + hexadecimal digits right after the optional pad spaces, the value of String + is stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +StrHexToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, OPTIONAL + UINT64 *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + if (InternalCharToUpper (*String) == L'X') { + if (*(String - 1) != L'0') { + *Data = 0; + return RETURN_SUCCESS; + } + // + // Skip the 'X' + // + String++; + } + + *Data = 0; + + while (InternalIsHexaDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINT64 - InternalHexCharToUintn (*String))>>4)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = ((*Data) << 4) + InternalHexCharToUintn (*String); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +UINT64 +StrDecimalToUint64 ( + CONST CHAR16 *String + ) +{ + UINT64 Result; + + StrDecimalToUint64S (String, (CHAR16 **) NULL, &Result); + return Result; +} + + +UINT64 +StrHexToUint64 ( + CONST CHAR16 *String + ) +{ + UINT64 Result; + + StrHexToUint64S (String, (CHAR16 **) NULL, &Result); + return Result; +} + +UINTN +StrSize ( + CONST CHAR16 *String + ) +{ + return (StrLen (String) + 1) * sizeof (*String); +} + + +UINT64 +ReadUnaligned64 ( + CONST UINT64 *Buffer + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer; +} + +UINT64 +WriteUnaligned64 ( + UINT64 *Buffer, + UINT64 Value + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer = Value; +} + + +EFI_GUID * +CopyGuid ( + EFI_GUID *DestinationGuid, + CONST EFI_GUID *SourceGuid + ) +{ + WriteUnaligned64 ( + (UINT64*)DestinationGuid, + ReadUnaligned64 ((CONST UINT64*)SourceGuid) + ); + WriteUnaligned64 ( + (UINT64*)DestinationGuid + 1, + ReadUnaligned64 ((CONST UINT64*)SourceGuid + 1) + ); + return DestinationGuid; +} + +UINT16 +SwapBytes16 ( + UINT16 Value + ) +{ + return (UINT16) ((Value<< 8) | (Value>> 8)); +} + + +UINT32 +SwapBytes32 ( + UINT32 Value + ) +{ + UINT32 LowerBytes; + UINT32 HigherBytes; + + LowerBytes = (UINT32) SwapBytes16 ((UINT16) Value); + HigherBytes = (UINT32) SwapBytes16 ((UINT16) (Value >> 16)); + return (LowerBytes << 16 | HigherBytes); +} + +BOOLEAN +InternalIsDecimalDigitCharacter ( + CHAR16 Char + ) +{ + return (BOOLEAN) (Char >= L'0' && Char <= L'9'); +} + +VOID * +InternalAllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ) +{ + VOID *Memory; + + ASSERT (Buffer != NULL); + + Memory = malloc (AllocationSize); + if (Memory != NULL) { + Memory = memcpy (Memory, Buffer, AllocationSize); + } + return Memory; +} + +BOOLEAN +InternalIsHexaDecimalDigitCharacter ( + CHAR16 Char + ) +{ + + return (BOOLEAN) (InternalIsDecimalDigitCharacter (Char) || + (Char >= L'A' && Char <= L'F') || + (Char >= L'a' && Char <= L'f')); +} + +UINTN +InternalHexCharToUintn ( + CHAR16 Char + ) +{ + if (InternalIsDecimalDigitCharacter (Char)) { + return Char - L'0'; + } + + return (10 + InternalCharToUpper (Char) - L'A'); +} + + +/** + Convert a Null-terminated Unicode hexadecimal string to a byte array. + + This function outputs a byte array by interpreting the contents of + the Unicode string specified by String in hexadecimal format. The format of + the input Unicode string String is: + + [XX]* + + X is a hexadecimal digit character in the range [0-9], [a-f] and [A-F]. + The function decodes every two hexadecimal digit characters as one byte. The + decoding stops after Length of characters and outputs Buffer containing + (Length / 2) bytes. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If String is NULL, then ASSERT(). + + If Buffer is NULL, then ASSERT(). + + If Length is not multiple of 2, then ASSERT(). + + If PcdMaximumUnicodeStringLength is not zero and Length is greater than + PcdMaximumUnicodeStringLength, then ASSERT(). + + If MaxBufferSize is less than (Length / 2), then ASSERT(). + + @param String Pointer to a Null-terminated Unicode string. + @param Length The number of Unicode characters to decode. + @param Buffer Pointer to the converted bytes array. + @param MaxBufferSize The maximum size of Buffer. + + @retval RETURN_SUCCESS Buffer is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If Length is not multiple of 2. + If PcdMaximumUnicodeStringLength is not zero, + and Length is greater than + PcdMaximumUnicodeStringLength. + @retval RETURN_UNSUPPORTED If Length of characters from String contain + a character that is not valid hexadecimal + digit characters, or a Null-terminator. + @retval RETURN_BUFFER_TOO_SMALL If MaxBufferSize is less than (Length / 2). +**/ +RETURN_STATUS +StrHexToBytes ( + CONST CHAR16 *String, + UINTN Length, + UINT8 *Buffer, + UINTN MaxBufferSize + ) +{ + UINTN Index; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Buffer shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Length shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. Length shall not be odd. + // + SAFE_STRING_CONSTRAINT_CHECK (((Length & BIT0) == 0), RETURN_INVALID_PARAMETER); + + // + // 4. MaxBufferSize shall equal to or greater than Length / 2. + // + SAFE_STRING_CONSTRAINT_CHECK ((MaxBufferSize >= Length / 2), RETURN_BUFFER_TOO_SMALL); + + // + // 5. String shall not contains invalid hexadecimal digits. + // + for (Index = 0; Index < Length; Index++) { + if (!InternalIsHexaDecimalDigitCharacter (String[Index])) { + break; + } + } + if (Index != Length) { + return RETURN_UNSUPPORTED; + } + + // + // Convert the hex string to bytes. + // + for(Index = 0; Index < Length; Index++) { + + // + // For even characters, write the upper nibble for each buffer byte, + // and for even characters, the lower nibble. + // + if ((Index & BIT0) == 0) { + Buffer[Index / 2] = (UINT8) InternalHexCharToUintn (String[Index]) << 4; + } else { + Buffer[Index / 2] |= (UINT8) InternalHexCharToUintn (String[Index]); + } + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode GUID string to a value of type + EFI_GUID. + + This function outputs a GUID value by interpreting the contents of + the Unicode string specified by String. The format of the input + Unicode string String consists of 36 characters, as follows: + + aabbccdd-eeff-gghh-iijj-kkllmmnnoopp + + The pairs aa - pp are two characters in the range [0-9], [a-f] and + [A-F], with each pair representing a single byte hexadecimal value. + + The mapping between String and the EFI_GUID structure is as follows: + aa Data1[24:31] + bb Data1[16:23] + cc Data1[8:15] + dd Data1[0:7] + ee Data2[8:15] + ff Data2[0:7] + gg Data3[8:15] + hh Data3[0:7] + ii Data4[0:7] + jj Data4[8:15] + kk Data4[16:23] + ll Data4[24:31] + mm Data4[32:39] + nn Data4[40:47] + oo Data4[48:55] + pp Data4[56:63] + + If String is NULL, then ASSERT(). + If Guid is NULL, then ASSERT(). + If String is not aligned in a 16-bit boundary, then ASSERT(). + + @param String Pointer to a Null-terminated Unicode string. + @param Guid Pointer to the converted GUID. + + @retval RETURN_SUCCESS Guid is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If String is not as the above format. + +**/ +RETURN_STATUS +StrToGuid ( + CONST CHAR16 *String, + EFI_GUID *Guid + ) +{ + RETURN_STATUS Status; + EFI_GUID LocalGuid; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Guid != NULL), RETURN_INVALID_PARAMETER); + + // + // Get aabbccdd in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data1), (UINT8 *) &LocalGuid.Data1, sizeof (LocalGuid.Data1)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data1)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data1 = SwapBytes32 (LocalGuid.Data1); + String += 2 * sizeof (LocalGuid.Data1) + 1; + + // + // Get eeff in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data2), (UINT8 *) &LocalGuid.Data2, sizeof (LocalGuid.Data2)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data2)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data2 = SwapBytes16 (LocalGuid.Data2); + String += 2 * sizeof (LocalGuid.Data2) + 1; + + // + // Get gghh in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data3), (UINT8 *) &LocalGuid.Data3, sizeof (LocalGuid.Data3)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data3)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data3 = SwapBytes16 (LocalGuid.Data3); + String += 2 * sizeof (LocalGuid.Data3) + 1; + + // + // Get iijj. + // + Status = StrHexToBytes (String, 2 * 2, &LocalGuid.Data4[0], 2); + if (RETURN_ERROR (Status) || String[2 * 2] != L'-') { + return RETURN_UNSUPPORTED; + } + String += 2 * 2 + 1; + + // + // Get kkllmmnnoopp. + // + Status = StrHexToBytes (String, 2 * 6, &LocalGuid.Data4[2], 6); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + + CopyGuid (Guid, &LocalGuid); + return RETURN_SUCCESS; +} + +/** + Compares up to a specified length the contents of two Null-terminated Unicode strings, + and returns the difference between the first mismatched Unicode characters. + + This function compares the Null-terminated Unicode string FirstString to the + Null-terminated Unicode string SecondString. At most, Length Unicode + characters will be compared. If Length is 0, then 0 is returned. If + FirstString is identical to SecondString, then 0 is returned. Otherwise, the + value returned is the first mismatched Unicode character in SecondString + subtracted from the first mismatched Unicode character in FirstString. + + If Length > 0 and FirstString is NULL, then ASSERT(). + If Length > 0 and FirstString is not aligned on a 16-bit boundary, then ASSERT(). + If Length > 0 and SecondString is NULL, then ASSERT(). + If Length > 0 and SecondString is not aligned on a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and Length is greater than + PcdMaximumUnicodeStringLength, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator, + then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator, + then ASSERT(). + + @param FirstString A pointer to a Null-terminated Unicode string. + @param SecondString A pointer to a Null-terminated Unicode string. + @param Length The maximum number of Unicode characters to compare. + + @retval 0 FirstString is identical to SecondString. + @return others FirstString is not identical to SecondString. + +**/ +INTN +StrnCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString, + UINTN Length + ) +{ + if (Length == 0) { + return 0; + } + + // + // ASSERT both strings are less long than PcdMaximumUnicodeStringLength. + // Length tests are performed inside StrLen(). + // + ASSERT (StrSize (FirstString) != 0); + ASSERT (StrSize (SecondString) != 0); + + while ((*FirstString != L'\0') && + (*SecondString != L'\0') && + (*FirstString == *SecondString) && + (Length > 1)) { + FirstString++; + SecondString++; + Length--; + } + + return *FirstString - *SecondString; +} + +VOID * +AllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ) +{ + return InternalAllocateCopyPool (AllocationSize, Buffer); +} + +INTN +StrCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString + ) +{ + // + // ASSERT both strings are less long than PcdMaximumUnicodeStringLength + // + ASSERT (StrSize (FirstString) != 0); + ASSERT (StrSize (SecondString) != 0); + + while ((*FirstString != L'\0') && (*FirstString == *SecondString)) { + FirstString++; + SecondString++; + } + return *FirstString - *SecondString; +} + +UINT64 +SwapBytes64 ( + UINT64 Value + ) +{ + return InternalMathSwapBytes64 (Value); +} + +UINT64 +InternalMathSwapBytes64 ( + UINT64 Operand + ) +{ + UINT64 LowerBytes; + UINT64 HigherBytes; + + LowerBytes = (UINT64) SwapBytes32 ((UINT32) Operand); + HigherBytes = (UINT64) SwapBytes32 ((UINT32) (Operand >> 32)); + + return (LowerBytes << 32 | HigherBytes); +} + +RETURN_STATUS +StrToIpv4Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv4_ADDRESS *Address, + UINT8 *PrefixLength + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINT64 Uint64; + EFI_IPv4_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CHAR16 *Pointer; + + LocalPrefixLength = MAX_UINT8; + LocalAddress.Addr[0] = 0; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = (CHAR16 *) String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalIsDecimalDigitCharacter (*Pointer)) { + // + // D or P contains invalid characters. + // + break; + } + + // + // Get D or P. + // + Status = StrDecimalToUint64S ((CONST CHAR16 *) Pointer, &Pointer, &Uint64); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // It's P. + // + if (Uint64 > 32) { + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uint64; + } else { + // + // It's D. + // + if (Uint64 > MAX_UINT8) { + return RETURN_UNSUPPORTED; + } + LocalAddress.Addr[AddressIndex] = (UINT8) Uint64; + AddressIndex++; + } + + // + // Check the '.' or '/', depending on the AddressIndex. + // + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + if (*Pointer == L'/') { + // + // '/P' is in the String. + // Skip "/" and get P in next loop. + // + Pointer++; + } else { + // + // '/P' is not in the String. + // + break; + } + } else if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + if (*Pointer == L'.') { + // + // D should be followed by '.' + // + Pointer++; + } else { + return RETURN_UNSUPPORTED; + } + } + } + + if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + return RETURN_UNSUPPORTED; + } + + memcpy (Address, &LocalAddress, sizeof (*Address)); + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = Pointer; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +StrToIpv6Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv6_ADDRESS *Address, + UINT8 *PrefixLength + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINT64 Uint64; + EFI_IPv6_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CONST CHAR16 *Pointer; + CHAR16 *End; + UINTN CompressStart; + BOOLEAN ExpectPrefix; + + LocalPrefixLength = MAX_UINT8; + CompressStart = ARRAY_SIZE (Address->Addr); + ExpectPrefix = FALSE; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer != L':') { + // + // ":" or "/" should be followed by digit characters. + // + return RETURN_UNSUPPORTED; + } + + // + // Meet second ":" after previous ":" or "/" + // or meet first ":" in the beginning of String. + // + if (ExpectPrefix) { + // + // ":" shall not be after "/" + // + return RETURN_UNSUPPORTED; + } + + if (CompressStart != ARRAY_SIZE (Address->Addr) || AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // "::" can only appear once. + // "::" can only appear when address is not full length. + // + return RETURN_UNSUPPORTED; + } else { + // + // Remember the start of zero compressing. + // + CompressStart = AddressIndex; + Pointer++; + + if (CompressStart == 0) { + if (*Pointer != L':') { + // + // Single ":" shall not be in the beginning of String. + // + return RETURN_UNSUPPORTED; + } + Pointer++; + } + } + } + + if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer == L'/') { + // + // Might be optional "/P" after "::". + // + if (CompressStart != AddressIndex) { + return RETURN_UNSUPPORTED; + } + } else { + break; + } + } else { + if (!ExpectPrefix) { + // + // Get X. + // + Status = StrHexToUint64S (Pointer, &End, &Uint64); + if (RETURN_ERROR (Status) || End - Pointer > 4) { + // + // Number of hexadecimal digit characters is no more than 4. + // + return RETURN_UNSUPPORTED; + } + Pointer = End; + // + // Uint64 won't exceed MAX_UINT16 if number of hexadecimal digit characters is no more than 4. + // + ASSERT (AddressIndex + 1 < ARRAY_SIZE (Address->Addr)); + LocalAddress.Addr[AddressIndex] = (UINT8) ((UINT16) Uint64 >> 8); + LocalAddress.Addr[AddressIndex + 1] = (UINT8) Uint64; + AddressIndex += 2; + } else { + // + // Get P, then exit the loop. + // + Status = StrDecimalToUint64S (Pointer, &End, &Uint64); + if (RETURN_ERROR (Status) || End == Pointer || Uint64 > 128) { + // + // Prefix length should not exceed 128. + // + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uint64; + Pointer = End; + break; + } + } + + // + // Skip ':' or "/" + // + if (*Pointer == L'/') { + ExpectPrefix = TRUE; + } else if (*Pointer == L':') { + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // Meet additional ":" after all 8 16-bit address + // + break; + } + } else { + // + // Meet other character that is not "/" or ":" after all 8 16-bit address + // + break; + } + Pointer++; + } + + if ((AddressIndex == ARRAY_SIZE (Address->Addr) && CompressStart != ARRAY_SIZE (Address->Addr)) || + (AddressIndex != ARRAY_SIZE (Address->Addr) && CompressStart == ARRAY_SIZE (Address->Addr)) + ) { + // + // Full length of address shall not have compressing zeros. + // Non-full length of address shall have compressing zeros. + // + return RETURN_UNSUPPORTED; + } + memcpy (&Address->Addr[0], &LocalAddress.Addr[0], CompressStart); + if (AddressIndex > CompressStart) { + memset (&Address->Addr[CompressStart], 0, ARRAY_SIZE (Address->Addr) - AddressIndex); + memcpy ( + &Address->Addr[CompressStart + ARRAY_SIZE (Address->Addr) - AddressIndex], + &LocalAddress.Addr[CompressStart], + AddressIndex - CompressStart + ); + } + + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) Pointer; + } + + return RETURN_SUCCESS; +} + + +RETURN_STATUS +UnicodeStrToAsciiStrS ( + CONST CHAR16 *Source, + CHAR8 *Destination, + UINTN DestMax + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than ASCII_RSIZE_MAX or RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than StrnLenS (Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED); + + // + // convert string + // + while (*Source != '\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + } + *Destination = '\0'; + + return RETURN_SUCCESS; +} + +RETURN_STATUS +StrCpyS ( + CHAR16 *Destination, + UINTN DestMax, + CONST CHAR16 *Source + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than StrnLenS(Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The StrCpyS function copies the string pointed to by Source (including the terminating + // null character) into the array pointed to by Destination. + // + while (*Source != 0) { + *(Destination++) = *(Source++); + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +VOID * +AllocateZeroPool ( + UINTN AllocationSize + ) +{ + VOID * Memory; + Memory = malloc(AllocationSize); + ASSERT (Memory != NULL); + if (Memory == NULL) { + fprintf(stderr, "Not memory for malloc\n"); + } + memset(Memory, 0, AllocationSize); + return Memory; +} + +VOID * +AllocatePool ( + UINTN AllocationSize + ) +{ + return InternalAllocatePool (AllocationSize); +} + +UINT16 +WriteUnaligned16 ( + UINT16 *Buffer, + UINT16 Value + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer = Value; +} + +UINT16 +ReadUnaligned16 ( + CONST UINT16 *Buffer + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer; +} +/** + Return whether the integer string is a hex string. + + @param Str The integer string + + @retval TRUE Hex string + @retval FALSE Decimal string + +**/ +BOOLEAN +IsHexStr ( + CHAR16 *Str + ) +{ + // + // skip preceding white space + // + while ((*Str != 0) && *Str == L' ') { + Str ++; + } + // + // skip preceding zeros + // + while ((*Str != 0) && *Str == L'0') { + Str ++; + } + + return (BOOLEAN) (*Str == L'x' || *Str == L'X'); +} + +/** + + Convert integer string to uint. + + @param Str The integer string. If leading with "0x" or "0X", it's hexadecimal. + + @return A UINTN value represented by Str + +**/ +UINTN +Strtoi ( + CHAR16 *Str + ) +{ + if (IsHexStr (Str)) { + return (UINTN)StrHexToUint64 (Str); + } else { + return (UINTN)StrDecimalToUint64 (Str); + } +} + +/** + + Convert integer string to 64 bit data. + + @param Str The integer string. If leading with "0x" or "0X", it's hexadecimal. + @param Data A pointer to the UINT64 value represented by Str + +**/ +VOID +Strtoi64 ( + CHAR16 *Str, + UINT64 *Data + ) +{ + if (IsHexStr (Str)) { + *Data = StrHexToUint64 (Str); + } else { + *Data = StrDecimalToUint64 (Str); + } +} + +/** + Converts a Unicode string to ASCII string. + + @param Str The equivalent Unicode string + @param AsciiStr On input, it points to destination ASCII string buffer; on output, it points + to the next ASCII string next to it + +**/ +VOID +StrToAscii ( + CHAR16 *Str, + CHAR8 **AsciiStr + ) +{ + CHAR8 *Dest; + + Dest = *AsciiStr; + while (!IS_NULL (*Str)) { + *(Dest++) = (CHAR8) *(Str++); + } + *Dest = 0; + + // + // Return the string next to it + // + *AsciiStr = Dest + 1; +} + +/** + Gets current sub-string from a string list, before return + the list header is moved to next sub-string. The sub-string is separated + by the specified character. For example, the separator is ',', the string + list is "2,0,3", it returns "2", the remain list move to "0,3" + + @param List A string list separated by the specified separator + @param Separator The separator character + + @return A pointer to the current sub-string + +**/ +CHAR16 * +SplitStr ( + CHAR16 **List, + CHAR16 Separator + ) +{ + CHAR16 *Str; + CHAR16 *ReturnStr; + + Str = *List; + ReturnStr = Str; + + if (IS_NULL (*Str)) { + return ReturnStr; + } + + // + // Find first occurrence of the separator + // + while (!IS_NULL (*Str)) { + if (*Str == Separator) { + break; + } + Str++; + } + + if (*Str == Separator) { + // + // Find a sub-string, terminate it + // + *Str = L'\0'; + Str++; + } + + // + // Move to next sub-string + // + *List = Str; + return ReturnStr; +} diff --git a/tools/src/GenFw/Common/src/CommonLib.h b/tools/src/GenFw/Common/src/CommonLib.h new file mode 100644 index 0000000..a3c693b --- /dev/null +++ b/tools/src/GenFw/Common/src/CommonLib.h @@ -0,0 +1,471 @@ +/** @file +Common library assistance routines. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_COMMON_LIB_H +#define _EFI_COMMON_LIB_H + +#include +#include +#include +#ifndef _WIN32 +#include +#endif + +#define PRINTED_GUID_BUFFER_SIZE 37 // including null-termination + +#ifdef PATH_MAX +#define MAX_LONG_FILE_PATH PATH_MAX +#else +#define MAX_LONG_FILE_PATH 500 +#endif + +#define MAX_UINT64 ((UINT64)0xFFFFFFFFFFFFFFFFULL) +#define MAX_UINT32 ((UINT32)0xFFFFFFFF) +#define MAX_UINT16 ((UINT16)0xFFFF) +#define MAX_UINT8 ((UINT8)0xFF) +#define ARRAY_SIZE(Array) (sizeof (Array) / sizeof ((Array)[0])) +#define ASCII_RSIZE_MAX 1000000 +#undef RSIZE_MAX +#define RSIZE_MAX 1000000 + +#define IS_COMMA(a) ((a) == L',') +#define IS_HYPHEN(a) ((a) == L'-') +#define IS_DOT(a) ((a) == L'.') +#define IS_LEFT_PARENTH(a) ((a) == L'(') +#define IS_RIGHT_PARENTH(a) ((a) == L')') +#define IS_SLASH(a) ((a) == L'/') +#define IS_NULL(a) ((a) == L'\0') + +#define ASSERT(x) assert(x) + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Function declarations +// +VOID +PeiZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +; + +VOID +PeiCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +; + +VOID +ZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +; + +VOID +CopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +; + +INTN +CompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ) +; + +EFI_STATUS +GetFileImage ( + IN CHAR8 *InputFileName, + OUT CHAR8 **InputFileImage, + OUT UINT32 *BytesRead + ) +; + +/*++ + +Routine Description: + + This function opens a file and writes OutputFileImage into the file. + +Arguments: + + OutputFileName The name of the file to write. + OutputFileImage A pointer to the memory buffer. + BytesToWrite The size of the memory buffer. + +Returns: + + EFI_SUCCESS The function completed successfully. + EFI_INVALID_PARAMETER One of the input parameters was invalid. + EFI_ABORTED An error occurred. + EFI_OUT_OF_RESOURCES No resource to complete operations. + +**/ +EFI_STATUS +PutFileImage ( + IN CHAR8 *OutputFileName, + IN CHAR8 *OutputFileImage, + IN UINT32 BytesToWrite + ) +; + +UINT8 +CalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +; + +UINT8 +CalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +; + +UINT16 +CalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +; + +UINT16 +CalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +; + +EFI_STATUS +PrintGuid ( + IN EFI_GUID *Guid + ) +; + +#define PRINTED_GUID_BUFFER_SIZE 37 // including null-termination +EFI_STATUS +PrintGuidToBuffer ( + IN EFI_GUID *Guid, + IN OUT UINT8 *Buffer, + IN UINT32 BufferLen, + IN BOOLEAN Uppercase + ) +; + +CHAR8 * +LongFilePath ( + IN CHAR8 *FileName +); + +UINTN +StrLen ( + CONST CHAR16 *String + ); + +VOID * +AllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ); + +INTN +StrnCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString, + UINTN Length + ); + +RETURN_STATUS +StrToGuid ( + CONST CHAR16 *String, + EFI_GUID *Guid + ); + +RETURN_STATUS +StrHexToBytes ( + CONST CHAR16 *String, + UINTN Length, + UINT8 *Buffer, + UINTN MaxBufferSize + ); + +UINTN +InternalHexCharToUintn ( + CHAR16 Char + ); + +VOID * +InternalAllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ); + +BOOLEAN +InternalIsDecimalDigitCharacter ( + CHAR16 Char + ); + +UINT32 +SwapBytes32 ( + UINT32 Value + ); + +UINT16 +SwapBytes16 ( + UINT16 Value + ); + +EFI_GUID * +CopyGuid ( + EFI_GUID *DestinationGuid, + CONST EFI_GUID *SourceGuid + ); + +UINT64 +WriteUnaligned64 ( + UINT64 *Buffer, + UINT64 Value + ); + +UINT64 +ReadUnaligned64 ( + CONST UINT64 *Buffer + ); + +UINTN +StrSize ( + CONST CHAR16 *String + ); + +UINT64 +StrHexToUint64 ( + CONST CHAR16 *String + ); + +UINT64 +StrDecimalToUint64 ( + CONST CHAR16 *String + ); + +RETURN_STATUS +StrHexToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + UINT64 *Data + ); + +RETURN_STATUS +StrDecimalToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, OPTIONAL + UINT64 *Data + ); + +VOID * +ReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ); + +VOID * +InternalReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ); + +VOID * +InternalAllocateZeroPool ( + UINTN AllocationSize + ) ; + +VOID * +InternalAllocatePool ( + UINTN AllocationSize + ); + +UINTN +StrnLenS ( + CONST CHAR16 *String, + UINTN MaxSize + ); + +CHAR16 +InternalCharToUpper ( + CHAR16 Char + ); + +INTN +StrCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString + ); + +UINT64 +SwapBytes64 ( + UINT64 Value + ); + +UINT64 +InternalMathSwapBytes64 ( + UINT64 Operand + ); + +RETURN_STATUS +StrToIpv4Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv4_ADDRESS *Address, + UINT8 *PrefixLength + ); + +RETURN_STATUS +StrToIpv6Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv6_ADDRESS *Address, + UINT8 *PrefixLength + ); + +RETURN_STATUS +StrCpyS ( + CHAR16 *Destination, + UINTN DestMax, + CONST CHAR16 *Source + ); + +RETURN_STATUS +UnicodeStrToAsciiStrS ( + CONST CHAR16 *Source, + CHAR8 *Destination, + UINTN DestMax + ); +VOID * +AllocatePool ( + UINTN AllocationSize + ); + +UINT16 +WriteUnaligned16 ( + UINT16 *Buffer, + UINT16 Value + ); + +UINT16 +ReadUnaligned16 ( + CONST UINT16 *Buffer + ); + +VOID * +AllocateZeroPool ( + UINTN AllocationSize + ); + +BOOLEAN +InternalIsHexaDecimalDigitCharacter ( + CHAR16 Char + ); + +BOOLEAN +InternalSafeStringIsOverlap ( + IN VOID *Base1, + IN UINTN Size1, + IN VOID *Base2, + IN UINTN Size2 + ); + +BOOLEAN +InternalSafeStringNoStrOverlap ( + IN CHAR16 *Str1, + IN UINTN Size1, + IN CHAR16 *Str2, + IN UINTN Size2 + ); + +BOOLEAN +IsHexStr ( + CHAR16 *Str + ); + +UINTN +Strtoi ( + CHAR16 *Str + ); + +VOID +Strtoi64 ( + CHAR16 *Str, + UINT64 *Data + ); + +VOID +StrToAscii ( + CHAR16 *Str, + CHAR8 **AsciiStr + ); + +CHAR16 * +SplitStr ( + CHAR16 **List, + CHAR16 Separator + ); + +/*++ + +Routine Description: + Convert FileName to the long file path, which can support larger than 260 length. + +Arguments: + FileName - FileName. + +Returns: + LongFilePath A pointer to the converted long file path. + +--*/ + +#ifdef __cplusplus +} +#endif + +#ifdef __GNUC__ +#include +#include +#define stricmp strcasecmp +#define _stricmp strcasecmp +#define strnicmp strncasecmp +#define strcmpi strcasecmp +#ifndef __WIN32__ +size_t _filelength(int fd); +#endif +#ifndef __CYGWIN__ +char *strlwr(char *s); +#endif +#endif + +// +// On windows, mkdir only has one parameter. +// On unix, it has two parameters +// +#if defined(__GNUC__) +#define mkdir(dir, perm) mkdir(dir, perm) +#else +#define mkdir(dir, perm) mkdir(dir) +#endif + +#endif diff --git a/tools/src/GenFw/Common/src/Compress.h b/tools/src/GenFw/Common/src/Compress.h new file mode 100644 index 0000000..1777345 --- /dev/null +++ b/tools/src/GenFw/Common/src/Compress.h @@ -0,0 +1,67 @@ +/** @file +Header file for compression routine. +Providing both EFI and Tiano Compress algorithms. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _COMPRESS_H_ +#define _COMPRESS_H_ + +#include +#include + +#include "CommonLib.h" +#include + +/** + Tiano compression routine. +**/ +EFI_STATUS +TianoCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +; + +/** + Efi compression routine. +**/ +EFI_STATUS +EfiCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +; + +/** + The compression routine. + + @param SrcBuffer The buffer storing the source data + @param SrcSize The size of source data + @param DstBuffer The buffer to store the compressed data + @param DstSize On input, the size of DstBuffer; On output, + the size of the actual compressed data. + + @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case, + DstSize contains the size needed. + @retval EFI_SUCCESS Compression is successful. + @retval EFI_OUT_OF_RESOURCES No resource to complete function. + @retval EFI_INVALID_PARAMETER Parameter supplied is wrong. +**/ +typedef +EFI_STATUS +(*COMPRESS_FUNCTION) ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ); + +#endif diff --git a/tools/src/GenFw/Common/src/Crc32.c b/tools/src/GenFw/Common/src/Crc32.c new file mode 100644 index 0000000..b5a154f --- /dev/null +++ b/tools/src/GenFw/Common/src/Crc32.c @@ -0,0 +1,305 @@ +/** @file +CalculateCrc32 routine. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include "Crc32.h" + +UINT32 mCrcTable[256] = { + 0x00000000, + 0x77073096, + 0xEE0E612C, + 0x990951BA, + 0x076DC419, + 0x706AF48F, + 0xE963A535, + 0x9E6495A3, + 0x0EDB8832, + 0x79DCB8A4, + 0xE0D5E91E, + 0x97D2D988, + 0x09B64C2B, + 0x7EB17CBD, + 0xE7B82D07, + 0x90BF1D91, + 0x1DB71064, + 0x6AB020F2, + 0xF3B97148, + 0x84BE41DE, + 0x1ADAD47D, + 0x6DDDE4EB, + 0xF4D4B551, + 0x83D385C7, + 0x136C9856, + 0x646BA8C0, + 0xFD62F97A, + 0x8A65C9EC, + 0x14015C4F, + 0x63066CD9, + 0xFA0F3D63, + 0x8D080DF5, + 0x3B6E20C8, + 0x4C69105E, + 0xD56041E4, + 0xA2677172, + 0x3C03E4D1, + 0x4B04D447, + 0xD20D85FD, + 0xA50AB56B, + 0x35B5A8FA, + 0x42B2986C, + 0xDBBBC9D6, + 0xACBCF940, + 0x32D86CE3, + 0x45DF5C75, + 0xDCD60DCF, + 0xABD13D59, + 0x26D930AC, + 0x51DE003A, + 0xC8D75180, + 0xBFD06116, + 0x21B4F4B5, + 0x56B3C423, + 0xCFBA9599, + 0xB8BDA50F, + 0x2802B89E, + 0x5F058808, + 0xC60CD9B2, + 0xB10BE924, + 0x2F6F7C87, + 0x58684C11, + 0xC1611DAB, + 0xB6662D3D, + 0x76DC4190, + 0x01DB7106, + 0x98D220BC, + 0xEFD5102A, + 0x71B18589, + 0x06B6B51F, + 0x9FBFE4A5, + 0xE8B8D433, + 0x7807C9A2, + 0x0F00F934, + 0x9609A88E, + 0xE10E9818, + 0x7F6A0DBB, + 0x086D3D2D, + 0x91646C97, + 0xE6635C01, + 0x6B6B51F4, + 0x1C6C6162, + 0x856530D8, + 0xF262004E, + 0x6C0695ED, + 0x1B01A57B, + 0x8208F4C1, + 0xF50FC457, + 0x65B0D9C6, + 0x12B7E950, + 0x8BBEB8EA, + 0xFCB9887C, + 0x62DD1DDF, + 0x15DA2D49, + 0x8CD37CF3, + 0xFBD44C65, + 0x4DB26158, + 0x3AB551CE, + 0xA3BC0074, + 0xD4BB30E2, + 0x4ADFA541, + 0x3DD895D7, + 0xA4D1C46D, + 0xD3D6F4FB, + 0x4369E96A, + 0x346ED9FC, + 0xAD678846, + 0xDA60B8D0, + 0x44042D73, + 0x33031DE5, + 0xAA0A4C5F, + 0xDD0D7CC9, + 0x5005713C, + 0x270241AA, + 0xBE0B1010, + 0xC90C2086, + 0x5768B525, + 0x206F85B3, + 0xB966D409, + 0xCE61E49F, + 0x5EDEF90E, + 0x29D9C998, + 0xB0D09822, + 0xC7D7A8B4, + 0x59B33D17, + 0x2EB40D81, + 0xB7BD5C3B, + 0xC0BA6CAD, + 0xEDB88320, + 0x9ABFB3B6, + 0x03B6E20C, + 0x74B1D29A, + 0xEAD54739, + 0x9DD277AF, + 0x04DB2615, + 0x73DC1683, + 0xE3630B12, + 0x94643B84, + 0x0D6D6A3E, + 0x7A6A5AA8, + 0xE40ECF0B, + 0x9309FF9D, + 0x0A00AE27, + 0x7D079EB1, + 0xF00F9344, + 0x8708A3D2, + 0x1E01F268, + 0x6906C2FE, + 0xF762575D, + 0x806567CB, + 0x196C3671, + 0x6E6B06E7, + 0xFED41B76, + 0x89D32BE0, + 0x10DA7A5A, + 0x67DD4ACC, + 0xF9B9DF6F, + 0x8EBEEFF9, + 0x17B7BE43, + 0x60B08ED5, + 0xD6D6A3E8, + 0xA1D1937E, + 0x38D8C2C4, + 0x4FDFF252, + 0xD1BB67F1, + 0xA6BC5767, + 0x3FB506DD, + 0x48B2364B, + 0xD80D2BDA, + 0xAF0A1B4C, + 0x36034AF6, + 0x41047A60, + 0xDF60EFC3, + 0xA867DF55, + 0x316E8EEF, + 0x4669BE79, + 0xCB61B38C, + 0xBC66831A, + 0x256FD2A0, + 0x5268E236, + 0xCC0C7795, + 0xBB0B4703, + 0x220216B9, + 0x5505262F, + 0xC5BA3BBE, + 0xB2BD0B28, + 0x2BB45A92, + 0x5CB36A04, + 0xC2D7FFA7, + 0xB5D0CF31, + 0x2CD99E8B, + 0x5BDEAE1D, + 0x9B64C2B0, + 0xEC63F226, + 0x756AA39C, + 0x026D930A, + 0x9C0906A9, + 0xEB0E363F, + 0x72076785, + 0x05005713, + 0x95BF4A82, + 0xE2B87A14, + 0x7BB12BAE, + 0x0CB61B38, + 0x92D28E9B, + 0xE5D5BE0D, + 0x7CDCEFB7, + 0x0BDBDF21, + 0x86D3D2D4, + 0xF1D4E242, + 0x68DDB3F8, + 0x1FDA836E, + 0x81BE16CD, + 0xF6B9265B, + 0x6FB077E1, + 0x18B74777, + 0x88085AE6, + 0xFF0F6A70, + 0x66063BCA, + 0x11010B5C, + 0x8F659EFF, + 0xF862AE69, + 0x616BFFD3, + 0x166CCF45, + 0xA00AE278, + 0xD70DD2EE, + 0x4E048354, + 0x3903B3C2, + 0xA7672661, + 0xD06016F7, + 0x4969474D, + 0x3E6E77DB, + 0xAED16A4A, + 0xD9D65ADC, + 0x40DF0B66, + 0x37D83BF0, + 0xA9BCAE53, + 0xDEBB9EC5, + 0x47B2CF7F, + 0x30B5FFE9, + 0xBDBDF21C, + 0xCABAC28A, + 0x53B39330, + 0x24B4A3A6, + 0xBAD03605, + 0xCDD70693, + 0x54DE5729, + 0x23D967BF, + 0xB3667A2E, + 0xC4614AB8, + 0x5D681B02, + 0x2A6F2B94, + 0xB40BBE37, + 0xC30C8EA1, + 0x5A05DF1B, + 0x2D02EF8D +}; + +/** + The CalculateCrc32 routine. + + @param Data The buffer containing the data to be processed + @param DataSize The size of data to be processed + @param CrcOut A pointer to the caller allocated UINT32 that on + contains the CRC32 checksum of Data + + @retval EFI_SUCCESS Calculation is successful. + @retval EFI_INVALID_PARAMETER Data / CrcOut = NULL, or DataSize = 0 +**/ +EFI_STATUS +CalculateCrc32 ( + IN UINT8 *Data, + IN UINTN DataSize, + IN OUT UINT32 *CrcOut + ) +{ + UINT32 Crc; + UINTN Index; + UINT8 *Ptr; + + if ((DataSize == 0) || (Data == NULL) || (CrcOut == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Crc = 0xffffffff; + for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) { + Crc = (Crc >> 8) ^ mCrcTable[(UINT8) Crc ^ *Ptr]; + } + + *CrcOut = Crc ^ 0xffffffff; + + return EFI_SUCCESS; +} diff --git a/tools/src/GenFw/Common/src/Crc32.h b/tools/src/GenFw/Common/src/Crc32.h new file mode 100644 index 0000000..b8922fa --- /dev/null +++ b/tools/src/GenFw/Common/src/Crc32.h @@ -0,0 +1,33 @@ +/** @file +Header file for CalculateCrc32 routine + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _CRC32_H +#define _CRC32_H + +#include + +/** + The CalculateCrc32 routine. + + @param Data The buffer containing the data to be processed + @param DataSize The size of data to be processed + @param CrcOut A pointer to the caller allocated UINT32 that on + contains the CRC32 checksum of Data + + @retval EFI_SUCCESS - Calculation is successful. + @retval EFI_INVALID_PARAMETER - Data / CrcOut = NULL, or DataSize = 0 +**/ +EFI_STATUS +CalculateCrc32 ( + IN UINT8 *Data, + IN UINTN DataSize, + IN OUT UINT32 *CrcOut + ) +; + +#endif diff --git a/tools/src/GenFw/Common/src/Decompress.c b/tools/src/GenFw/Common/src/Decompress.c new file mode 100644 index 0000000..27bc04e --- /dev/null +++ b/tools/src/GenFw/Common/src/Decompress.c @@ -0,0 +1,903 @@ +/** @file +Decompressor. Algorithm Ported from OPSD code (Decomp.asm) for Efi and Tiano +compress algorithm. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include +#include +#include +#include "Decompress.h" + +// +// Decompression algorithm begins here +// +#define UINT8_MAX 0xff +#define BITBUFSIZ 32 +#define MAXMATCH 256 +#define THRESHOLD 3 +#define CODE_BIT 16 +#define BAD_TABLE - 1 + +// +// C: Char&Len Set; P: Position Set; T: exTra Set +// +#define NC (0xff + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define EFIPBIT 4 +#define MAXPBIT 5 +#define TBIT 5 +#define MAXNP ((1U << MAXPBIT) - 1) +#define NT (CODE_BIT + 3) +#if NT > MAXNP +#define NPT NT +#else +#define NPT MAXNP +#endif + +typedef struct { + UINT8 *mSrcBase; // Starting address of compressed data + UINT8 *mDstBase; // Starting address of decompressed data + UINT32 mOutBuf; + UINT32 mInBuf; + + UINT16 mBitCount; + UINT32 mBitBuf; + UINT32 mSubBitBuf; + UINT16 mBlockSize; + UINT32 mCompSize; + UINT32 mOrigSize; + + UINT16 mBadTableFlag; + + UINT16 mLeft[2 * NC - 1]; + UINT16 mRight[2 * NC - 1]; + UINT8 mCLen[NC]; + UINT8 mPTLen[NPT]; + UINT16 mCTable[4096]; + UINT16 mPTTable[256]; +} SCRATCH_DATA; + +STATIC UINT16 mPbit = EFIPBIT; + +/** + Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source. + + @param Sd The global scratch data + @param NumOfBit The number of bits to shift and read. +**/ +STATIC +VOID +FillBuf ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfBits + ) +{ + Sd->mBitBuf = (UINT32) (((UINT64)Sd->mBitBuf) << NumOfBits); + + while (NumOfBits > Sd->mBitCount) { + + Sd->mBitBuf |= (UINT32) (((UINT64)Sd->mSubBitBuf) << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount))); + + if (Sd->mCompSize > 0) { + // + // Get 1 byte into SubBitBuf + // + Sd->mCompSize--; + Sd->mSubBitBuf = 0; + Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++]; + Sd->mBitCount = 8; + + } else { + // + // No more bits from the source, just pad zero bit. + // + Sd->mSubBitBuf = 0; + Sd->mBitCount = 8; + + } + } + + Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits); + Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount; +} + +/** + Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent + NumOfBits of bits from source. Returns NumOfBits of bits that are + popped out. + + @param Sd The global scratch data. + @param NumOfBits The number of bits to pop and read. + + @return The bits that are popped out. +**/ +STATIC +UINT32 +GetBits ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfBits + ) +{ + UINT32 OutBits; + + OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); + + FillBuf (Sd, NumOfBits); + + return OutBits; +} + +/** + Creates Huffman Code mapping table according to code length array. + + @param Sd The global scratch data + @param NumOfChar Number of symbols in the symbol set + @param BitLen Code length array + @param TableBits The width of the mapping table + @param Table The table + + @retval 0 - OK. + @retval BAD_TABLE - The table is corrupted. +**/ +STATIC +UINT16 +MakeTable ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfChar, + IN UINT8 *BitLen, + IN UINT16 TableBits, + OUT UINT16 *Table + ) +{ + UINT16 Count[17]; + UINT16 Weight[17]; + UINT16 Start[18]; + UINT16 *Pointer; + UINT16 Index3; + UINT16 Index; + UINT16 Len; + UINT16 Char; + UINT16 JuBits; + UINT16 Avail; + UINT16 NextCode; + UINT16 Mask; + UINT16 MaxTableLength; + + for (Index = 1; Index <= 16; Index++) { + Count[Index] = 0; + } + + for (Index = 0; Index < NumOfChar; Index++) { + if (BitLen[Index] > 16) { + return (UINT16) BAD_TABLE; + } + Count[BitLen[Index]]++; + } + + Start[1] = 0; + + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index))); + } + + if (Start[17] != 0) { + /*(1U << 16)*/ + return (UINT16) BAD_TABLE; + } + + JuBits = (UINT16) (16 - TableBits); + + for (Index = 1; Index <= TableBits; Index++) { + Start[Index] >>= JuBits; + Weight[Index] = (UINT16) (1U << (TableBits - Index)); + } + + while (Index <= 16) { + Weight[Index] = (UINT16) (1U << (16 - Index)); + Index++; + } + + Index = (UINT16) (Start[TableBits + 1] >> JuBits); + + if (Index != 0) { + Index3 = (UINT16) (1U << TableBits); + while (Index != Index3) { + Table[Index++] = 0; + } + } + + Avail = NumOfChar; + Mask = (UINT16) (1U << (15 - TableBits)); + MaxTableLength = (UINT16) (1U << TableBits); + + for (Char = 0; Char < NumOfChar; Char++) { + + Len = BitLen[Char]; + if (Len == 0 || Len >= 17) { + continue; + } + + NextCode = (UINT16) (Start[Len] + Weight[Len]); + + if (Len <= TableBits) { + + if (Start[Len] >= NextCode || NextCode > MaxTableLength){ + return (UINT16) BAD_TABLE; + } + + for (Index = Start[Len]; Index < NextCode; Index++) { + Table[Index] = Char; + } + + } else { + + Index3 = Start[Len]; + Pointer = &Table[Index3 >> JuBits]; + Index = (UINT16) (Len - TableBits); + + while (Index != 0) { + if (*Pointer == 0) { + Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; + *Pointer = Avail++; + } + + if (Index3 & Mask) { + Pointer = &Sd->mRight[*Pointer]; + } else { + Pointer = &Sd->mLeft[*Pointer]; + } + + Index3 <<= 1; + Index--; + } + + *Pointer = Char; + + } + + Start[Len] = NextCode; + } + // + // Succeeds + // + return 0; +} + +/** + Decodes a position value. + + @param Sd the global scratch data + + @return The position value decoded. +**/ +STATIC +UINT32 +DecodeP ( + IN SCRATCH_DATA *Sd + ) +{ + UINT16 Val; + UINT32 Mask; + UINT32 Pos; + + Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + + if (Val >= MAXNP) { + Mask = 1U << (BITBUFSIZ - 1 - 8); + + do { + + if (Sd->mBitBuf & Mask) { + Val = Sd->mRight[Val]; + } else { + Val = Sd->mLeft[Val]; + } + + Mask >>= 1; + } while (Val >= MAXNP); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mPTLen[Val]); + + Pos = Val; + if (Val > 1) { + Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1))); + } + + return Pos; +} + +/** + Reads code lengths for the Extra Set or the Position Set + + @param Sd The global scratch data + @param nn Number of symbols + @param nbit Number of bits needed to represent nn + @param Special The special symbol that needs to be taken care of + + @retval 0 - OK. + @retval BAD_TABLE - Table is corrupted. +**/ +STATIC +UINT16 +ReadPTLen ( + IN SCRATCH_DATA *Sd, + IN UINT16 nn, + IN UINT16 nbit, + IN UINT16 Special + ) +{ + UINT16 Number; + UINT16 CharC; + UINT16 Index; + UINT32 Mask; + + assert (nn <= NPT); + + Number = (UINT16) GetBits (Sd, nbit); + + if (Number == 0) { + CharC = (UINT16) GetBits (Sd, nbit); + + for (Index = 0; Index < 256; Index++) { + Sd->mPTTable[Index] = CharC; + } + + for (Index = 0; Index < nn; Index++) { + Sd->mPTLen[Index] = 0; + } + + return 0; + } + + Index = 0; + + while (Index < Number && Index < NPT) { + + CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3)); + + if (CharC == 7) { + Mask = 1U << (BITBUFSIZ - 1 - 3); + while (Mask & Sd->mBitBuf) { + Mask >>= 1; + CharC += 1; + } + } + + FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3)); + + Sd->mPTLen[Index++] = (UINT8) CharC; + + if (Index == Special) { + CharC = (UINT16) GetBits (Sd, 2); + CharC--; + while ((INT16) (CharC) >= 0 && Index < NPT) { + Sd->mPTLen[Index++] = 0; + CharC--; + } + } + } + + while (Index < nn && Index < NPT) { + Sd->mPTLen[Index++] = 0; + } + + return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); +} + +/** + Reads code lengths for Char&Len Set. + + @param Sd the global scratch data +**/ +STATIC +VOID +ReadCLen ( + SCRATCH_DATA *Sd + ) +{ + UINT16 Number; + UINT16 CharC; + UINT16 Index; + UINT32 Mask; + + Number = (UINT16) GetBits (Sd, CBIT); + + if (Number == 0) { + CharC = (UINT16) GetBits (Sd, CBIT); + + for (Index = 0; Index < NC; Index++) { + Sd->mCLen[Index] = 0; + } + + for (Index = 0; Index < 4096; Index++) { + Sd->mCTable[Index] = CharC; + } + + return ; + } + + Index = 0; + while (Index < Number) { + + CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + if (CharC >= NT) { + Mask = 1U << (BITBUFSIZ - 1 - 8); + + do { + + if (Mask & Sd->mBitBuf) { + CharC = Sd->mRight[CharC]; + } else { + CharC = Sd->mLeft[CharC]; + } + + Mask >>= 1; + + } while (CharC >= NT); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mPTLen[CharC]); + + if (CharC <= 2) { + + if (CharC == 0) { + CharC = 1; + } else if (CharC == 1) { + CharC = (UINT16) (GetBits (Sd, 4) + 3); + } else if (CharC == 2) { + CharC = (UINT16) (GetBits (Sd, CBIT) + 20); + } + + CharC--; + while ((INT16) (CharC) >= 0) { + Sd->mCLen[Index++] = 0; + CharC--; + } + + } else { + + Sd->mCLen[Index++] = (UINT8) (CharC - 2); + + } + } + + while (Index < NC) { + Sd->mCLen[Index++] = 0; + } + + MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable); + + return ; +} + +/** + Decode a character/length value. + + @param Sd The global scratch data. + + @return The value decoded. +**/ +STATIC +UINT16 +DecodeC ( + SCRATCH_DATA *Sd + ) +{ + UINT16 Index2; + UINT32 Mask; + + if (Sd->mBlockSize == 0) { + // + // Starting a new block + // + Sd->mBlockSize = (UINT16) GetBits (Sd, 16); + Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3); + if (Sd->mBadTableFlag != 0) { + return 0; + } + + ReadCLen (Sd); + + Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, mPbit, (UINT16) (-1)); + if (Sd->mBadTableFlag != 0) { + return 0; + } + } + + Sd->mBlockSize--; + Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; + + if (Index2 >= NC) { + Mask = 1U << (BITBUFSIZ - 1 - 12); + + do { + if (Sd->mBitBuf & Mask) { + Index2 = Sd->mRight[Index2]; + } else { + Index2 = Sd->mLeft[Index2]; + } + + Mask >>= 1; + } while (Index2 >= NC); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mCLen[Index2]); + + return Index2; +} + +/** + Decode the source data and put the resulting data into the destination buffer. + + @param Sd The global scratch data + **/ +STATIC +VOID +Decode ( + SCRATCH_DATA *Sd + ) +{ + UINT16 BytesRemain; + UINT32 DataIdx; + UINT16 CharC; + + BytesRemain = (UINT16) (-1); + + DataIdx = 0; + + for (;;) { + CharC = DecodeC (Sd); + if (Sd->mBadTableFlag != 0) { + return ; + } + + if (CharC < 256) { + // + // Process an Original character + // + Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC; + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + + } else { + // + // Process a Pointer + // + CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD)); + + BytesRemain = CharC; + + DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1; + + BytesRemain--; + while ((INT16) (BytesRemain) >= 0) { + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + if (DataIdx >= Sd->mOrigSize) { + Sd->mBadTableFlag = (UINT16) BAD_TABLE; + return ; + } + Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; + + BytesRemain--; + } + // + // Once mOutBuf is fully filled, directly return + // + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + } + } + + return ; +} + +/** + The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER - The source data is corrupted +**/ +EFI_STATUS +GetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +{ + UINT8 *Src; + UINT32 CompSize; + + *ScratchSize = sizeof (SCRATCH_DATA); + + Src = Source; + if (SrcSize < 8) { + return EFI_INVALID_PARAMETER; + } + + CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); + *DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); + + if (SrcSize < CompSize + 8 || (CompSize + 8) < 8) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + The implementation Efi and Tiano Decompress(). + + @param Source - The source buffer containing the compressed data. + @param SrcSize - The size of source buffer + @param Destination - The destination buffer to store the decompressed data + @param DstSize - The size of destination buffer. + @param Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize - The size of scratch buffer. + + @retval EFI_SUCCESS - Decompression is successful + @retval EFI_INVALID_PARAMETER - The source data is corrupted +**/ +EFI_STATUS +Decompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +{ + UINT32 Index; + UINT32 CompSize; + UINT32 OrigSize; + EFI_STATUS Status; + SCRATCH_DATA *Sd; + UINT8 *Src; + UINT8 *Dst; + + Status = EFI_SUCCESS; + Src = Source; + Dst = Destination; + + if (ScratchSize < sizeof (SCRATCH_DATA)) { + return EFI_INVALID_PARAMETER; + } + + Sd = (SCRATCH_DATA *) Scratch; + + if (SrcSize < 8) { + return EFI_INVALID_PARAMETER; + } + + CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); + OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); + + if (SrcSize < CompSize + 8 || (CompSize + 8) < 8) { + return EFI_INVALID_PARAMETER; + } + + if (DstSize != OrigSize) { + return EFI_INVALID_PARAMETER; + } + + Src = Src + 8; + + for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) { + ((UINT8 *) Sd)[Index] = 0; + } + + Sd->mSrcBase = Src; + Sd->mDstBase = Dst; + Sd->mCompSize = CompSize; + Sd->mOrigSize = OrigSize; + + // + // Fill the first BITBUFSIZ bits + // + FillBuf (Sd, BITBUFSIZ); + + // + // Decompress it + // + Decode (Sd); + + if (Sd->mBadTableFlag != 0) { + // + // Something wrong with the source + // + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + The implementation Efi Decompress GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +EfiGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +{ + return GetInfo (Source, SrcSize, DstSize, ScratchSize); +} + +/** + The implementation Tiano Decompress GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +{ + return GetInfo (Source, SrcSize, DstSize, ScratchSize); +} + +/** + The implementation of Efi Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +EfiDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +{ + mPbit = EFIPBIT; + return Decompress (Source, SrcSize, Destination, DstSize, Scratch, ScratchSize); +} + +/** + The implementation of Tiano Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +{ + mPbit = MAXPBIT; + return Decompress (Source, SrcSize, Destination, DstSize, Scratch, ScratchSize); +} + +EFI_STATUS +Extract ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT VOID **Destination, + OUT UINT32 *DstSize, + IN UINTN Algorithm + ) +{ + VOID *Scratch; + UINT32 ScratchSize; + EFI_STATUS Status; + + Scratch = NULL; + Status = EFI_SUCCESS; + + switch (Algorithm) { + case 0: + *Destination = (VOID *)malloc(SrcSize); + if (*Destination != NULL) { + memcpy(*Destination, Source, SrcSize); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + break; + case 1: + Status = EfiGetInfo(Source, SrcSize, DstSize, &ScratchSize); + if (Status == EFI_SUCCESS) { + Scratch = (VOID *)malloc(ScratchSize); + if (Scratch == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Destination = (VOID *)malloc(*DstSize); + if (*Destination == NULL) { + free (Scratch); + return EFI_OUT_OF_RESOURCES; + } + + Status = EfiDecompress(Source, SrcSize, *Destination, *DstSize, Scratch, ScratchSize); + } + break; + case 2: + Status = TianoGetInfo(Source, SrcSize, DstSize, &ScratchSize); + if (Status == EFI_SUCCESS) { + Scratch = (VOID *)malloc(ScratchSize); + if (Scratch == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Destination = (VOID *)malloc(*DstSize); + if (*Destination == NULL) { + free (Scratch); + return EFI_OUT_OF_RESOURCES; + } + + Status = TianoDecompress(Source, SrcSize, *Destination, *DstSize, Scratch, ScratchSize); + } + break; + default: + Status = EFI_INVALID_PARAMETER; + } + + if (Scratch != NULL) { + free (Scratch); + } + + return Status; +} + + diff --git a/tools/src/GenFw/Common/src/Decompress.h b/tools/src/GenFw/Common/src/Decompress.h new file mode 100644 index 0000000..73e3596 --- /dev/null +++ b/tools/src/GenFw/Common/src/Decompress.h @@ -0,0 +1,135 @@ +/** @file +Header file for compression routine + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_DECOMPRESS_H +#define _EFI_DECOMPRESS_H + +#include + +/** + +Routine Description: + + The implementation Efi Decompress GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SrcSize - The size of source buffer + DstSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved. + EFI_INVALID_PARAMETER - The source data is corrupted + +**/ +EFI_STATUS +EfiGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +/** + The implementation of Efi Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +EfiDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +/** + The implementation Tiano Decompress GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +/** + The implementation of Tiano Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +typedef +EFI_STATUS +(*GETINFO_FUNCTION) ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +typedef +EFI_STATUS +(*DECOMPRESS_FUNCTION) ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +EFI_STATUS +Extract ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT VOID **Destination, + OUT UINT32 *DstSize, + IN UINTN Algorithm + ); + +#endif diff --git a/tools/src/GenFw/Common/src/EfiCompress.c b/tools/src/GenFw/Common/src/EfiCompress.c new file mode 100644 index 0000000..913bef7 --- /dev/null +++ b/tools/src/GenFw/Common/src/EfiCompress.c @@ -0,0 +1,1407 @@ +/** @file +Compression routine. The compression algorithm is a mixture of LZ77 and Huffman +coding. LZ77 transforms the source data into a sequence of Original Characters +and Pointers to repeated strings. This sequence is further divided into Blocks +and Huffman codings are applied to each Block. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Compress.h" + + +// +// Macro Definitions +// + +#undef UINT8_MAX +typedef INT16 NODE; +#define UINT8_MAX 0xff +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 13 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define PERC_FLAG 0x8000U +#define CODE_BIT 16 +#define NIL 0 +#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) +#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2) +#define CRCPOLY 0xA001 +#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT) + +// +// C: the Char&Len Set; P: the Position Set; T: the exTra Set +// + +#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define NP (WNDBIT + 1) +#define PBIT 4 +#define NT (CODE_BIT + 3) +#define TBIT 5 +#if NT > NP + #define NPT NT +#else + #define NPT NP +#endif + +// +// Function Prototypes +// + +STATIC +VOID +PutDword( + IN UINT32 Data + ); + +STATIC +EFI_STATUS +AllocateMemory ( + ); + +STATIC +VOID +FreeMemory ( + ); + +STATIC +VOID +InitSlide ( + ); + +STATIC +NODE +Child ( + IN NODE q, + IN UINT8 c + ); + +STATIC +VOID +MakeChild ( + IN NODE q, + IN UINT8 c, + IN NODE r + ); + +STATIC +VOID +Split ( + IN NODE Old + ); + +STATIC +VOID +InsertNode ( + ); + +STATIC +VOID +DeleteNode ( + ); + +STATIC +VOID +GetNextMatch ( + ); + +STATIC +EFI_STATUS +Encode ( + ); + +STATIC +VOID +CountTFreq ( + ); + +STATIC +VOID +WritePTLen ( + IN INT32 n, + IN INT32 nbit, + IN INT32 Special + ); + +STATIC +VOID +WriteCLen ( + ); + +STATIC +VOID +EncodeC ( + IN INT32 c + ); + +STATIC +VOID +EncodeP ( + IN UINT32 p + ); + +STATIC +VOID +SendBlock ( + ); + +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ); + +STATIC +VOID +HufEncodeStart ( + ); + +STATIC +VOID +HufEncodeEnd ( + ); + +STATIC +VOID +MakeCrcTable ( + ); + +STATIC +VOID +PutBits ( + IN INT32 n, + IN UINT32 x + ); + +STATIC +INT32 +FreadCrc ( + OUT UINT8 *p, + IN INT32 n + ); + +STATIC +VOID +InitPutBits ( + ); + +STATIC +VOID +CountLen ( + IN INT32 i + ); + +STATIC +VOID +MakeLen ( + IN INT32 Root + ); + +STATIC +VOID +DownHeap ( + IN INT32 i + ); + +STATIC +VOID +MakeCode ( + IN INT32 n, + IN UINT8 Len[], + OUT UINT16 Code[] + ); + +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[], + OUT UINT16 CodeParm[] + ); + + +// +// Global Variables +// + +STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; + +STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; +STATIC INT16 mHeap[NC + 1]; +STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN; +STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc; +STATIC UINT32 mCompSize, mOrigSize; + +STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], + mCrcTable[UINT8_MAX + 1], mCFreq[2 * NC - 1],mCCode[NC], + mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1]; + +STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; + + +// +// functions +// + +/** + The main compression routine. + + @param SrcBuffer The buffer storing the source data + @param SrcSize The size of source data + @param DstBuffer The buffer to store the compressed data + @param DstSize On input, the size of DstBuffer; On output, + the size of the actual compressed data. + + @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case, + DstSize contains the size needed. + @retval EFI_SUCCESS Compression is successful. + +**/ +EFI_STATUS +EfiCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + // + // Initializations + // + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + + mSrc = SrcBuffer; + mSrcUpperLimit = mSrc + SrcSize; + mDst = DstBuffer; + mDstUpperLimit = mDst + *DstSize; + + PutDword(0L); + PutDword(0L); + + MakeCrcTable (); + + mOrigSize = mCompSize = 0; + mCrc = INIT_CRC; + + // + // Compress it + // + + Status = Encode(); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + + // + // Fill in compressed size and original size + // + mDst = DstBuffer; + PutDword(mCompSize+1); + PutDword(mOrigSize); + + // + // Return + // + + if (mCompSize + 1 + 8 > *DstSize) { + *DstSize = mCompSize + 1 + 8; + return EFI_BUFFER_TOO_SMALL; + } else { + *DstSize = mCompSize + 1 + 8; + return EFI_SUCCESS; + } + +} + +/** + Put a dword to output stream + + @param Data the dword to put +**/ +STATIC +VOID +PutDword( + IN UINT32 Data + ) +{ + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff); + } +} + +/** + Allocate memory spaces for data structures used in compression process + + @retval EFI_SUCCESS Memory is allocated successfully + @retva; EFI_OUT_OF_RESOURCES Allocation fails +**/ +STATIC +EFI_STATUS +AllocateMemory () +{ + UINT32 i; + + mText = malloc (WNDSIZ * 2 + MAXMATCH); + if (mText == NULL) { + return EFI_OUT_OF_RESOURCES; + } + for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) { + mText[i] = 0; + } + + mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel)); + mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount)); + mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition)); + mParent = malloc (WNDSIZ * 2 * sizeof(*mParent)); + mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev)); + mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext)); + if (mLevel == NULL || mChildCount == NULL || mPosition == NULL || + mParent == NULL || mPrev == NULL || mNext == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mBufSiz = 16 * 1024U; + while ((mBuf = malloc(mBufSiz)) == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + } + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +/** + Called when compression is completed to free memory previously allocated. +**/ +VOID +FreeMemory () +{ + if (mText) { + free (mText); + } + + if (mLevel) { + free (mLevel); + } + + if (mChildCount) { + free (mChildCount); + } + + if (mPosition) { + free (mPosition); + } + + if (mParent) { + free (mParent); + } + + if (mPrev) { + free (mPrev); + } + + if (mNext) { + free (mNext); + } + + if (mBuf) { + free (mBuf); + } + + return; +} + +/** + Initialize String Info Log data structures +**/ +STATIC +VOID +InitSlide () +{ + NODE i; + + for (i = WNDSIZ; i <= WNDSIZ + UINT8_MAX; i++) { + mLevel[i] = 1; + mPosition[i] = NIL; /* sentinel */ + } + for (i = WNDSIZ; i < WNDSIZ * 2; i++) { + mParent[i] = NIL; + } + mAvail = 1; + for (i = 1; i < WNDSIZ - 1; i++) { + mNext[i] = (NODE)(i + 1); + } + + mNext[WNDSIZ - 1] = NIL; + for (i = WNDSIZ * 2; i <= MAX_HASH_VAL; i++) { + mNext[i] = NIL; + } +} + +/** + Find child node given the parent node and the edge character + + @param q the parent node + @param c the edge character + + @return The child node (NIL if not found) +**/ +STATIC +NODE +Child ( + IN NODE q, + IN UINT8 c + ) +{ + NODE r; + + r = mNext[HASH(q, c)]; + mParent[NIL] = q; /* sentinel */ + while (mParent[r] != q) { + r = mNext[r]; + } + + return r; +} + +/** + Create a new child for a given parent node. + + @param q the parent node + @param c the edge character + @param r the child node +**/ +STATIC +VOID +MakeChild ( + IN NODE q, + IN UINT8 c, + IN NODE r + ) +{ + NODE h, t; + + h = (NODE)HASH(q, c); + t = mNext[h]; + mNext[h] = r; + mNext[r] = t; + mPrev[t] = r; + mPrev[r] = h; + mParent[r] = q; + mChildCount[q]++; +} + +/** + Split a node. + + @param Old the node to split +**/ +STATIC +VOID +Split ( + NODE Old + ) +{ + NODE New, t; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + t = mPrev[Old]; + mPrev[New] = t; + mNext[t] = New; + t = mNext[Old]; + mNext[New] = t; + mPrev[t] = New; + mParent[New] = mParent[Old]; + mLevel[New] = (UINT8)mMatchLen; + mPosition[New] = mPos; + MakeChild(New, mText[mMatchPos + mMatchLen], Old); + MakeChild(New, mText[mPos + mMatchLen], mPos); +} + +/** + Insert string info for current position into the String Info Log +**/ +STATIC +VOID +InsertNode () +{ + NODE q, r, j, t; + UINT8 c, *t1, *t2; + + if (mMatchLen >= 4) { + + // + // We have just got a long match, the target tree + // can be located by MatchPos + 1. Traverse the tree + // from bottom up to get to a proper starting point. + // The usage of PERC_FLAG ensures proper node deletion + // in DeleteNode() later. + // + + mMatchLen--; + r = (INT16)((mMatchPos + 1) | WNDSIZ); + while ((q = mParent[r]) == NIL) { + r = mNext[r]; + } + while (mLevel[q] >= mMatchLen) { + r = q; q = mParent[q]; + } + t = q; + while (mPosition[t] < 0) { + mPosition[t] = mPos; + t = mParent[t]; + } + if (t < WNDSIZ) { + mPosition[t] = (NODE)(mPos | PERC_FLAG); + } + } else { + + // + // Locate the target tree + // + + q = (INT16)(mText[mPos] + WNDSIZ); + c = mText[mPos + 1]; + if ((r = Child(q, c)) == NIL) { + MakeChild(q, c, mPos); + mMatchLen = 1; + return; + } + mMatchLen = 2; + } + + // + // Traverse down the tree to find a match. + // Update Position value along the route. + // Node split or creation is involved. + // + + for ( ; ; ) { + if (r >= WNDSIZ) { + j = MAXMATCH; + mMatchPos = r; + } else { + j = mLevel[r]; + mMatchPos = (NODE)(mPosition[r] & ~PERC_FLAG); + } + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + t1 = &mText[mPos + mMatchLen]; + t2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < j) { + if (*t1 != *t2) { + Split(r); + return; + } + mMatchLen++; + t1++; + t2++; + } + if (mMatchLen >= MAXMATCH) { + break; + } + mPosition[r] = mPos; + q = r; + if ((r = Child(q, *t1)) == NIL) { + MakeChild(q, *t1, mPos); + return; + } + mMatchLen++; + } + t = mPrev[r]; + mPrev[mPos] = t; + mNext[t] = mPos; + t = mNext[r]; + mNext[mPos] = t; + mPrev[t] = mPos; + mParent[mPos] = q; + mParent[r] = NIL; + + // + // Special usage of 'next' + // + mNext[r] = mPos; + +} + +/** + Delete outdated string info. (The Usage of PERC_FLAG + ensures a clean deletion) +**/ +STATIC +VOID +DeleteNode () +{ + NODE q, r, s, t, u; + + if (mParent[mPos] == NIL) { + return; + } + + r = mPrev[mPos]; + s = mNext[mPos]; + mNext[r] = s; + mPrev[s] = r; + r = mParent[mPos]; + mParent[mPos] = NIL; + if (r >= WNDSIZ || --mChildCount[r] > 1) { + return; + } + t = (NODE)(mPosition[r] & ~PERC_FLAG); + if (t >= mPos) { + t -= WNDSIZ; + } + s = t; + q = mParent[r]; + while ((u = mPosition[q]) & PERC_FLAG) { + u &= ~PERC_FLAG; + if (u >= mPos) { + u -= WNDSIZ; + } + if (u > s) { + s = u; + } + mPosition[q] = (INT16)(s | WNDSIZ); + q = mParent[q]; + } + if (q < WNDSIZ) { + if (u >= mPos) { + u -= WNDSIZ; + } + if (u > s) { + s = u; + } + mPosition[q] = (INT16)(s | WNDSIZ | PERC_FLAG); + } + s = Child(r, mText[t + mLevel[r]]); + t = mPrev[s]; + u = mNext[s]; + mNext[t] = u; + mPrev[u] = t; + t = mPrev[r]; + mNext[t] = s; + mPrev[s] = t; + t = mNext[r]; + mPrev[t] = s; + mNext[s] = t; + mParent[s] = mParent[r]; + mParent[r] = NIL; + mNext[r] = mAvail; + mAvail = r; +} + +/** + Advance the current position (read in new data if needed). + Delete outdated string info. Find a match string for current position. +**/ +STATIC +VOID +GetNextMatch () +{ + INT32 n; + + mRemainder--; + if (++mPos == WNDSIZ * 2) { + memmove(&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); + n = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += n; + mPos = WNDSIZ; + } + DeleteNode(); + InsertNode(); +} + +/** + The main controlling routine for compression process. + + @retval EFI_SUCCESS The compression is successful + @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process +**/ +STATIC +EFI_STATUS +Encode () +{ + EFI_STATUS Status; + INT32 LastMatchLen; + NODE LastMatchPos; + + Status = AllocateMemory(); + if (EFI_ERROR(Status)) { + FreeMemory(); + return Status; + } + + InitSlide(); + + HufEncodeStart(); + + mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH); + + mMatchLen = 0; + mPos = WNDSIZ; + InsertNode(); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + while (mRemainder > 0) { + LastMatchLen = mMatchLen; + LastMatchPos = mMatchPos; + GetNextMatch(); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) { + + // + // Not enough benefits are gained by outputting a pointer, + // so just output the original character + // + + Output(mText[mPos - 1], 0); + } else { + + // + // Outputting a pointer is beneficial enough, do it. + // + + Output(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1)); + while (--LastMatchLen > 0) { + GetNextMatch(); + } + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd(); + FreeMemory(); + return EFI_SUCCESS; +} + +/** + Count the frequencies for the Extra Set +**/ +STATIC +VOID +CountTFreq () +{ + INT32 i, k, n, Count; + + for (i = 0; i < NT; i++) { + mTFreq[i] = 0; + } + n = NC; + while (n > 0 && mCLen[n - 1] == 0) { + n--; + } + i = 0; + while (i < n) { + k = mCLen[i++]; + if (k == 0) { + Count = 1; + while (i < n && mCLen[i] == 0) { + i++; + Count++; + } + if (Count <= 2) { + mTFreq[0] = (UINT16)(mTFreq[0] + Count); + } else if (Count <= 18) { + mTFreq[1]++; + } else if (Count == 19) { + mTFreq[0]++; + mTFreq[1]++; + } else { + mTFreq[2]++; + } + } else { + mTFreq[k + 2]++; + } + } +} + +/** + Outputs the code length array for the Extra Set or the Position Set. + + @param n the number of symbols + @param nbit the number of bits needed to represent 'n' + @param Special the special symbol that needs to be take care of +**/ +STATIC +VOID +WritePTLen ( + IN INT32 n, + IN INT32 nbit, + IN INT32 Special + ) +{ + INT32 i, k; + + while (n > 0 && mPTLen[n - 1] == 0) { + n--; + } + PutBits(nbit, n); + i = 0; + while (i < n) { + k = mPTLen[i++]; + if (k <= 6) { + PutBits(3, k); + } else { + PutBits(k - 3, (1U << (k - 3)) - 2); + } + if (i == Special) { + while (i < 6 && mPTLen[i] == 0) { + i++; + } + PutBits(2, (i - 3) & 3); + } + } +} + +/** + Outputs the code length array for Char&Length Set +**/ +STATIC +VOID +WriteCLen () +{ + INT32 i, k, n, Count; + + n = NC; + while (n > 0 && mCLen[n - 1] == 0) { + n--; + } + PutBits(CBIT, n); + i = 0; + while (i < n) { + k = mCLen[i++]; + if (k == 0) { + Count = 1; + while (i < n && mCLen[i] == 0) { + i++; + Count++; + } + if (Count <= 2) { + for (k = 0; k < Count; k++) { + PutBits(mPTLen[0], mPTCode[0]); + } + } else if (Count <= 18) { + PutBits(mPTLen[1], mPTCode[1]); + PutBits(4, Count - 3); + } else if (Count == 19) { + PutBits(mPTLen[0], mPTCode[0]); + PutBits(mPTLen[1], mPTCode[1]); + PutBits(4, 15); + } else { + PutBits(mPTLen[2], mPTCode[2]); + PutBits(CBIT, Count - 20); + } + } else { + PutBits(mPTLen[k + 2], mPTCode[k + 2]); + } + } +} + +STATIC +VOID +EncodeC ( + IN INT32 c + ) +{ + PutBits(mCLen[c], mCCode[c]); +} + +STATIC +VOID +EncodeP ( + IN UINT32 p + ) +{ + UINT32 c, q; + + c = 0; + q = p; + while (q) { + q >>= 1; + c++; + } + PutBits(mPTLen[c], mPTCode[c]); + if (c > 1) { + PutBits(c - 1, p & (0xFFFFU >> (17 - c))); + } +} + +/** + Huffman code the block and output it. +**/ +STATIC +VOID +SendBlock () +{ + UINT32 i, k, Flags, Root, Pos, Size; + Flags = 0; + + Root = MakeTree(NC, mCFreq, mCLen, mCCode); + Size = mCFreq[Root]; + PutBits(16, Size); + if (Root >= NC) { + CountTFreq(); + Root = MakeTree(NT, mTFreq, mPTLen, mPTCode); + if (Root >= NT) { + WritePTLen(NT, TBIT, 3); + } else { + PutBits(TBIT, 0); + PutBits(TBIT, Root); + } + WriteCLen(); + } else { + PutBits(TBIT, 0); + PutBits(TBIT, 0); + PutBits(CBIT, 0); + PutBits(CBIT, Root); + } + Root = MakeTree(NP, mPFreq, mPTLen, mPTCode); + if (Root >= NP) { + WritePTLen(NP, PBIT, -1); + } else { + PutBits(PBIT, 0); + PutBits(PBIT, Root); + } + Pos = 0; + for (i = 0; i < Size; i++) { + if (i % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } else { + Flags <<= 1; + } + if (Flags & (1U << (UINT8_BIT - 1))) { + EncodeC(mBuf[Pos++] + (1U << UINT8_BIT)); + k = mBuf[Pos++] << UINT8_BIT; + k += mBuf[Pos++]; + EncodeP(k); + } else { + EncodeC(mBuf[Pos++]); + } + } + for (i = 0; i < NC; i++) { + mCFreq[i] = 0; + } + for (i = 0; i < NP; i++) { + mPFreq[i] = 0; + } +} + +/** + Outputs an Original Character or a Pointer + + @param c The original character or the 'String Length' element of a Pointer + @param p The 'Position' field of a Pointer +**/ +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ) +{ + STATIC UINT32 CPos; + + if ((mOutputMask >>= 1) == 0) { + mOutputMask = 1U << (UINT8_BIT - 1); + if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) { + SendBlock(); + mOutputPos = 0; + } + CPos = mOutputPos++; + mBuf[CPos] = 0; + } + mBuf[mOutputPos++] = (UINT8) c; + mCFreq[c]++; + if (c >= (1U << UINT8_BIT)) { + mBuf[CPos] |= mOutputMask; + mBuf[mOutputPos++] = (UINT8)(p >> UINT8_BIT); + mBuf[mOutputPos++] = (UINT8) p; + c = 0; + while (p) { + p >>= 1; + c++; + } + mPFreq[c]++; + } +} + +STATIC +VOID +HufEncodeStart () +{ + INT32 i; + + for (i = 0; i < NC; i++) { + mCFreq[i] = 0; + } + for (i = 0; i < NP; i++) { + mPFreq[i] = 0; + } + mOutputPos = mOutputMask = 0; + InitPutBits(); + return; +} + +STATIC +VOID +HufEncodeEnd () +{ + SendBlock(); + + // + // Flush remaining bits + // + PutBits(UINT8_BIT - 1, 0); + + return; +} + + +STATIC +VOID +MakeCrcTable () +{ + UINT32 i, j, r; + + for (i = 0; i <= UINT8_MAX; i++) { + r = i; + for (j = 0; j < UINT8_BIT; j++) { + if (r & 1) { + r = (r >> 1) ^ CRCPOLY; + } else { + r >>= 1; + } + } + mCrcTable[i] = (UINT16)r; + } +} + +/** + Outputs rightmost n bits of x + + @param n the rightmost n bits of the data is used + @param x the data +**/ +STATIC +VOID +PutBits ( + IN INT32 n, + IN UINT32 x + ) +{ + UINT8 Temp; + + if (n < mBitCount) { + mSubBitBuf |= x << (mBitCount -= n); + } else { + + Temp = (UINT8)(mSubBitBuf | (x >> (n -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + if (n < UINT8_BIT) { + mSubBitBuf = x << (mBitCount = UINT8_BIT - n); + } else { + + Temp = (UINT8)(x >> (n - UINT8_BIT)); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - n); + } + } +} + +/** + Read in source data + + @param p the buffer to hold the data + @param n number of bytes to read + + @return number of bytes actually read +**/ +STATIC +INT32 +FreadCrc ( + OUT UINT8 *p, + IN INT32 n + ) +{ + INT32 i; + + for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) { + *p++ = *mSrc++; + } + n = i; + + p -= n; + mOrigSize += n; + while (--i >= 0) { + UPDATE_CRC(*p++); + } + return n; +} + + +STATIC +VOID +InitPutBits () +{ + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +/** + Count the number of each code length for a Huffman tree. + + @param i the top node +**/ +STATIC +VOID +CountLen ( + IN INT32 i + ) +{ + STATIC INT32 Depth = 0; + + if (i < mN) { + mLenCnt[(Depth < 16) ? Depth : 16]++; + } else { + Depth++; + CountLen(mLeft [i]); + CountLen(mRight[i]); + Depth--; + } +} + +/** + Create code length array for a Huffman tree + + @param Root the root of the tree +**/ +STATIC +VOID +MakeLen ( + IN INT32 Root + ) +{ + INT32 i, k; + UINT32 Cum; + + for (i = 0; i <= 16; i++) { + mLenCnt[i] = 0; + } + CountLen(Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + + Cum = 0; + for (i = 16; i > 0; i--) { + Cum += mLenCnt[i] << (16 - i); + } + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (i = 15; i > 0; i--) { + if (mLenCnt[i] != 0) { + mLenCnt[i]--; + mLenCnt[i+1] += 2; + break; + } + } + Cum--; + } + for (i = 16; i > 0; i--) { + k = mLenCnt[i]; + while (--k >= 0) { + mLen[*mSortPtr++] = (UINT8)i; + } + } +} + +STATIC +VOID +DownHeap ( + IN INT32 i + ) +{ + INT32 j, k; + + // + // priority queue: send i-th entry down heap + // + + k = mHeap[i]; + while ((j = 2 * i) <= mHeapSize) { + if (j < mHeapSize && mFreq[mHeap[j]] > mFreq[mHeap[j + 1]]) { + j++; + } + if (mFreq[k] <= mFreq[mHeap[j]]) { + break; + } + mHeap[i] = mHeap[j]; + i = j; + } + mHeap[i] = (INT16)k; +} + +/** + Assign code to each symbol based on the code length array + + @param n number of symbols + @param Len the code length array + @param Code stores codes for each symbol +**/ +STATIC +VOID +MakeCode ( + IN INT32 n, + IN UINT8 Len[], + OUT UINT16 Code[] + ) +{ + INT32 i; + UINT16 Start[18]; + + Start[1] = 0; + for (i = 1; i <= 16; i++) { + Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1); + } + for (i = 0; i < n; i++) { + Code[i] = Start[Len[i]]++; + } +} + +/** + Generates Huffman codes given a frequency distribution of symbols + + @param NParm number of symbols + @param FreqParm frequency of each symbol + @param LenParm code length for each symbol + @param CodeParm code for each symbol + + @return Root of the Huffman tree. +**/ +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[], + OUT UINT16 CodeParm[] + ) +{ + INT32 i, j, k, Avail; + + // + // make tree, calculate len[], return root + // + + mN = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mN; + mHeapSize = 0; + mHeap[1] = 0; + for (i = 0; i < mN; i++) { + mLen[i] = 0; + if (mFreq[i]) { + mHeap[++mHeapSize] = (INT16)i; + } + } + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + for (i = mHeapSize / 2; i >= 1; i--) { + + // + // make priority queue + // + DownHeap(i); + } + mSortPtr = CodeParm; + do { + i = mHeap[1]; + if (i < mN) { + *mSortPtr++ = (UINT16)i; + } + mHeap[1] = mHeap[mHeapSize--]; + DownHeap(1); + j = mHeap[1]; + if (j < mN) { + *mSortPtr++ = (UINT16)j; + } + k = Avail++; + mFreq[k] = (UINT16)(mFreq[i] + mFreq[j]); + mHeap[1] = (INT16)k; + DownHeap(1); + mLeft[k] = (UINT16)i; + mRight[k] = (UINT16)j; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen(k); + MakeCode(NParm, LenParm, CodeParm); + + // + // return root + // + return k; +} + diff --git a/tools/src/GenFw/Common/src/EfiUtilityMsgs.c b/tools/src/GenFw/Common/src/EfiUtilityMsgs.c new file mode 100644 index 0000000..a40ad93 --- /dev/null +++ b/tools/src/GenFw/Common/src/EfiUtilityMsgs.c @@ -0,0 +1,788 @@ +/** @file +EFI tools utility functions to display warning, error, and informational messages + +Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include +#include +#include +#include +#include + +#include "EfiUtilityMsgs.h" + +// +// Declare module globals for keeping track of the utility's +// name and other settings. +// +STATIC STATUS mStatus = STATUS_SUCCESS; +STATIC CHAR8 mUtilityName[50] = { 0 }; +STATIC UINT64 mPrintLogLevel = INFO_LOG_LEVEL; +STATIC CHAR8 *mSourceFileName = NULL; +STATIC UINT32 mSourceFileLineNum = 0; +STATIC UINT32 mErrorCount = 0; +STATIC UINT32 mWarningCount = 0; +STATIC UINT32 mMaxErrors = 0; +STATIC UINT32 mMaxWarnings = 0; +STATIC UINT32 mMaxWarningsPlusErrors = 0; +STATIC INT8 mPrintLimitsSet = 0; + +STATIC +VOID +PrintLimitExceeded ( + VOID + ); + +/** + Prints an error message. + + All arguments are optional, though the printed message may be useless if + at least something valid is not specified. + + @note: + We print the following (similar to the Warn() and Debug() + W + Typical error/warning message format: + + bin\VfrCompile.cpp(330) : error C2660: 'AddVfrDataStructField' : function does not take 2 parameters + + BUGBUG -- these three utility functions are almost identical, and + should be modified to share code. + + Visual Studio does not find error messages with: + + " error :" + " error 1:" + " error c1:" + " error 1000:" + " error c100:" + + It does find: + " error c1000:" + + @param FileName name of the file or application. If not specified, then the + utility name (as set by the utility calling SetUtilityName() + earlier) is used. Otherwise "Unknown utility" is used. + + @param LineNumber the line number of error, typically used by parsers. If the + utility is not a parser, then 0 should be specified. Otherwise + the FileName and LineNumber info can be used to cause + MS Visual Studio to jump to the error. + + @param MessageCode an application-specific error code that can be referenced in + other documentation. + + @param Text the text in question, typically used by parsers. + + @param MsgFmt the format string for the error message. Can contain formatting + controls for use with the varargs. +**/ +VOID +Error ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If limits have been set, then check that we have not exceeded them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our error count + // + if (mMaxErrors != 0) { + if (mErrorCount > mMaxErrors) { + PrintLimitExceeded (); + return ; + } + } + } + + mErrorCount++; + va_start (List, MsgFmt); + PrintMessage ("ERROR", FileName, LineNumber, MessageCode, Text, MsgFmt, List); + va_end (List); +} + +/** + Print a parser error, using the source file name and line number + set by a previous call to SetParserPosition(). + + @param MessageCode application-specific error code + @param Text text to print in the error message + @param MsgFmt format string to print at the end of the error message +**/ +VOID +ParserError ( + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If limits have been set, then check them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our error count + // + if (mMaxErrors != 0) { + if (mErrorCount > mMaxErrors) { + PrintLimitExceeded (); + return ; + } + } + } + + mErrorCount++; + va_start (List, MsgFmt); + PrintMessage ("ERROR", mSourceFileName, mSourceFileLineNum, MessageCode, Text, MsgFmt, List); + va_end (List); +} + +/** + Print a parser warning, using the source file name and line number + set by a previous call to SetParserPosition(). + + @param ErrorCode application-specific error code + @param OffendingText text to print in the warning message + @param MsgFmt format string to print at the end of the warning message +**/ +VOID +ParserWarning ( + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If limits have been set, then check them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our warning count + // + if (mMaxWarnings != 0) { + if (mWarningCount > mMaxWarnings) { + PrintLimitExceeded (); + return ; + } + } + } + + mWarningCount++; + va_start (List, MsgFmt); + PrintMessage ("WARNING", mSourceFileName, mSourceFileLineNum, ErrorCode, OffendingText, MsgFmt, List); + va_end (List); + // + // Don't set warning status accordingly + // + // if (mStatus < STATUS_WARNING) { + // mStatus = STATUS_WARNING; + // } +} + +/** + Print a warning message. + + @param FileName name of the file where the warning was detected, or the name + of the application that detected the warning + @param LineNumber the line number where the warning was detected (parsers). + 0 should be specified if the utility is not a parser. + @param MessageCode an application-specific warning code that can be referenced in + other documentation. + @param Text the text in question (parsers) + @param MsgFmt the format string for the warning message. Can contain formatting + controls for use with varargs. +**/ +VOID +Warning ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + + // + // Current Print Level not output warning information. + // + if (WARNING_LOG_LEVEL < mPrintLogLevel) { + return; + } + // + // If limits have been set, then check them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our warning count + // + if (mMaxWarnings != 0) { + if (mWarningCount > mMaxWarnings) { + PrintLimitExceeded (); + return ; + } + } + } + + mWarningCount++; + va_start (List, MsgFmt); + PrintMessage ("WARNING", FileName, LineNumber, MessageCode, Text, MsgFmt, List); + va_end (List); +} + +/** + Print a Debug message. + + @param FileName typically the name of the utility printing the debug message, but + can be the name of a file being parsed. + @param LineNumber the line number in FileName (parsers) + @param MsgLevel Debug message print level (0~9) + @param Text the text in question (parsers) + @param MsgFmt the format string for the debug message. Can contain formatting + controls for use with varargs. + +**/ +VOID +DebugMsg ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT64 MsgLevel, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (MsgLevel < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintMessage ("DEBUG", FileName, LineNumber, 0, Text, MsgFmt, List); + va_end (List); +} + +/** + Worker routine for all the utility printing services. Prints the message in + a format that Visual Studio will find when scanning build outputs for + errors or warnings. + + @note: + If FileName == NULL then this utility will use the string passed into SetUtilityName(). + + LineNumber is only used if the caller is a parser, in which case FileName refers to the + file being parsed. + + Text and MsgFmt are both optional, though it would be of little use calling this function with + them both NULL. + + Output will typically be of the form: + () : : : + + Parser (LineNumber != 0) + VfrCompile.cpp(330) : error E2660: AddVfrDataStructField : function does not take 2 parameters + Generic utility (LineNumber == 0) + UtilityName : error E1234 : Text string : MsgFmt string and args + + @param Type "warning" or "error" string to insert into the message to be + printed. The first character of this string (converted to uppercase) + is used to precede the MessageCode value in the output string. + @param FileName name of the file where the warning was detected, or the name + of the application that detected the warning + @param LineNumber the line number where the warning was detected (parsers). + 0 should be specified if the utility is not a parser. + @param MessageCode an application-specific warning code that can be referenced in + other documentation. + @param Text part of the message to print + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +PrintMessage ( + CHAR8 *Type, + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + va_list List + ) +{ + CHAR8 Line[MAX_LINE_LEN]; + CHAR8 Line2[MAX_LINE_LEN]; + CHAR8 *Cptr; + struct tm *NewTime; + time_t CurrentTime; + + // + // init local variable + // + Line[0] = '\0'; + Line2[0] = '\0'; + + // + // If given a filename, then add it (and the line number) to the string. + // If there's no filename, then use the program name if provided. + // + if (FileName != NULL) { + Cptr = FileName; + } else { + Cptr = NULL; + } + + if (strcmp (Type, "DEBUG") == 0) { + // + // Debug Message requires current time. + // + time (&CurrentTime); + NewTime = localtime (&CurrentTime); + if (NewTime != NULL) { + fprintf (stdout, "%04d-%02d-%02d %02d:%02d:%02d", + NewTime->tm_year + 1900, + NewTime->tm_mon + 1, + NewTime->tm_mday, + NewTime->tm_hour, + NewTime->tm_min, + NewTime->tm_sec + ); + } + if (Cptr != NULL) { + strcpy (Line, ": "); + strncat (Line, Cptr, MAX_LINE_LEN - strlen (Line) - 1); + if (LineNumber != 0) { + sprintf (Line2, "(%u)", (unsigned) LineNumber); + strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1); + } + } + } else { + // + // Error and Warning Information. + // + if (Cptr != NULL) { + if (mUtilityName[0] != '\0') { + fprintf (stdout, "%s...\n", mUtilityName); + } + strncpy (Line, Cptr, MAX_LINE_LEN - 1); + Line[MAX_LINE_LEN - 1] = 0; + if (LineNumber != 0) { + sprintf (Line2, "(%u)", (unsigned) LineNumber); + strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1); + } + } else { + if (mUtilityName[0] != '\0') { + strncpy (Line, mUtilityName, MAX_LINE_LEN - 1); + Line[MAX_LINE_LEN - 1] = 0; + } + } + + if (strcmp (Type, "ERROR") == 0) { + // + // Set status accordingly for ERROR information. + // + if (mStatus < STATUS_ERROR) { + mStatus = STATUS_ERROR; + } + } + } + + // + // Have to print an error code or Visual Studio won't find the + // message for you. It has to be decimal digits too. + // + strncat (Line, ": ", MAX_LINE_LEN - strlen (Line) - 1); + strncat (Line, Type, MAX_LINE_LEN - strlen (Line) - 1); + if (MessageCode != 0) { + sprintf (Line2, " %04u", (unsigned) MessageCode); + strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1); + } + fprintf (stdout, "%s", Line); + // + // If offending text was provided, then print it + // + if (Text != NULL) { + fprintf (stdout, ": %s", Text); + } + fprintf (stdout, "\n"); + + // + // Print formatted message if provided + // + if (MsgFmt != NULL) { + vsprintf (Line2, MsgFmt, List); + fprintf (stdout, " %s\n", Line2); + } + +} + +/** + Print message into stdout. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +STATIC +VOID +PrintSimpleMessage ( + CHAR8 *MsgFmt, + va_list List + ) +{ + CHAR8 Line[MAX_LINE_LEN]; + // + // Print formatted message if provided + // + if (MsgFmt != NULL) { + vsprintf (Line, MsgFmt, List); + fprintf (stdout, "%s\n", Line); + } +} + +/** + Set the position in a file being parsed. This can be used to + print error messages deeper down in a parser. + + @param SourceFileName name of the source file being parsed + @param LineNum line number of the source file being parsed +**/ +VOID +ParserSetPosition ( + CHAR8 *SourceFileName, + UINT32 LineNum + ) +{ + mSourceFileName = SourceFileName; + mSourceFileLineNum = LineNum; +} + +/** + All printed error/warning/debug messages follow the same format, and + typically will print a filename or utility name followed by the error + text. However if a filename is not passed to the print routines, then + they'll print the utility name if you call this function early in your + app to set the utility name. + + @param UtilityName name of the utility, which will be printed with all + error/warning/debug messages. +**/ +VOID +SetUtilityName ( + CHAR8 *UtilityName + ) +{ + // + // Save the name of the utility in our local variable. Make sure its + // length does not exceed our buffer. + // + if (UtilityName != NULL) { + if (strlen (UtilityName) >= sizeof (mUtilityName)) { + Error (UtilityName, 0, 0, "application error", "utility name length exceeds internal buffer size"); + } + strncpy (mUtilityName, UtilityName, sizeof (mUtilityName) - 1); + mUtilityName[sizeof (mUtilityName) - 1] = 0; + } else { + Error (NULL, 0, 0, "application error", "SetUtilityName() called with NULL utility name"); + } +} + +/** + When you call Error() or Warning(), this module keeps track of it and + sets a local mStatus to STATUS_ERROR or STATUS_WARNING. When the utility + exits, it can call this function to get the status and use it as a return + value. + + @return Worst-case status reported, as defined by which print function was called. +**/ +STATUS +GetUtilityStatus ( + VOID + ) +{ + return mStatus; +} + +/** + Set the printing message Level. This is used by the PrintMsg() function + to determine when/if a message should be printed. + + @param LogLevel 0~50 to specify the different level message. +**/ +VOID +SetPrintLevel ( + UINT64 LogLevel + ) +{ + mPrintLogLevel = LogLevel; +} + +/** + Print a verbose level message. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +VerboseMsg ( + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (VERBOSE_LOG_LEVEL < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintSimpleMessage (MsgFmt, List); + va_end (List); +} + +/** + Print a default level message. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +NormalMsg ( + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (INFO_LOG_LEVEL < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintSimpleMessage (MsgFmt, List); + va_end (List); +} + +/** + Print a key level message. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +KeyMsg ( + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (KEY_LOG_LEVEL < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintSimpleMessage (MsgFmt, List); + va_end (List); +} + +/** + Set the limits of how many errors, warnings, and errors+warnings + we will print. + + @param MaxErrors maximum number of error messages to print + @param MaxWarnings maximum number of warning messages to print + @param MaxWarningsPlusErrors + maximum number of errors+warnings to print +**/ +VOID +SetPrintLimits ( + UINT32 MaxErrors, + UINT32 MaxWarnings, + UINT32 MaxWarningsPlusErrors + ) +{ + mMaxErrors = MaxErrors; + mMaxWarnings = MaxWarnings; + mMaxWarningsPlusErrors = MaxWarningsPlusErrors; + mPrintLimitsSet = 1; +} + +STATIC +VOID +PrintLimitExceeded ( + VOID + ) +{ + STATIC INT8 mPrintLimitExceeded = 0; + // + // If we've already printed the message, do nothing. Otherwise + // temporarily increase our print limits so we can pass one + // more message through. + // + if (mPrintLimitExceeded == 0) { + mPrintLimitExceeded++; + mMaxErrors++; + mMaxWarnings++; + mMaxWarningsPlusErrors++; + Error (NULL, 0, 0, "error/warning print limit exceeded", NULL); + mMaxErrors--; + mMaxWarnings--; + mMaxWarningsPlusErrors--; + } +} + +#if 0 +VOID +TestUtilityMessages ( + VOID + ) +{ + CHAR8 *ArgStr = "ArgString"; + int ArgInt; + + ArgInt = 0x12345678; + // + // Test without setting utility name + // + fprintf (stdout, "* Testing without setting utility name\n"); + fprintf (stdout, "** Test debug message not printed\n"); + DebugMsg (NULL, 0, 0x00000001, NULL, NULL); + fprintf (stdout, "** Test warning with two strings and two args\n"); + Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + fprintf (stdout, "** Test error with two strings and two args\n"); + Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + fprintf (stdout, "** Test parser warning with nothing\n"); + ParserWarning (0, NULL, NULL); + fprintf (stdout, "** Test parser error with nothing\n"); + ParserError (0, NULL, NULL); + // + // Test with utility name set now + // + fprintf (stdout, "** Testingin with utility name set\n"); + SetUtilityName ("MyUtilityName"); + // + // Test debug prints + // + SetDebugMsgMask (2); + fprintf (stdout, "** Test debug message with one string\n"); + DebugMsg (NULL, 0, 0x00000002, "Text1", NULL); + fprintf (stdout, "** Test debug message with one string\n"); + DebugMsg (NULL, 0, 0x00000002, NULL, "Text2"); + fprintf (stdout, "** Test debug message with two strings\n"); + DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2"); + fprintf (stdout, "** Test debug message with two strings and two args\n"); + DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + // + // Test warning prints + // + fprintf (stdout, "** Test warning with no strings\n"); + Warning (NULL, 0, 1234, NULL, NULL); + fprintf (stdout, "** Test warning with one string\n"); + Warning (NULL, 0, 1234, "Text1", NULL); + fprintf (stdout, "** Test warning with one string\n"); + Warning (NULL, 0, 1234, NULL, "Text2"); + fprintf (stdout, "** Test warning with two strings and two args\n"); + Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + // + // Test error prints + // + fprintf (stdout, "** Test error with no strings\n"); + Error (NULL, 0, 1234, NULL, NULL); + fprintf (stdout, "** Test error with one string\n"); + Error (NULL, 0, 1234, "Text1", NULL); + fprintf (stdout, "** Test error with one string\n"); + Error (NULL, 0, 1234, NULL, "Text2"); + fprintf (stdout, "** Test error with two strings and two args\n"); + Error (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + // + // Test parser prints + // + fprintf (stdout, "** Test parser errors\n"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, NULL, NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, "Text1", NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, NULL, "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, "Text1", "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + + fprintf (stdout, "** Test parser warnings\n"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, NULL, NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, "Text1", NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, NULL, "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, "Text1", "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); +} +#endif diff --git a/tools/src/GenFw/Common/src/EfiUtilityMsgs.h b/tools/src/GenFw/Common/src/EfiUtilityMsgs.h new file mode 100644 index 0000000..406cc70 --- /dev/null +++ b/tools/src/GenFw/Common/src/EfiUtilityMsgs.h @@ -0,0 +1,164 @@ +/** @file +Defines and prototypes for common EFI utility error and debug messages. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_UTILITY_MSGS_H_ +#define _EFI_UTILITY_MSGS_H_ + +#include + +// +// Log message print Level +// +#define VERBOSE_LOG_LEVEL 15 +#define WARNING_LOG_LEVEL 15 +#define INFO_LOG_LEVEL 20 +#define KEY_LOG_LEVEL 40 +#define ERROR_LOG_LEVLE 50 + +// +// Status codes returned by EFI utility programs and functions +// +#define STATUS_SUCCESS 0 +#define STATUS_WARNING 1 +#define STATUS_ERROR 2 +#define VOID void + +typedef int STATUS; + +#define MAX_LINE_LEN 0x200 +#define MAXIMUM_INPUT_FILE_NUM 10 + +#ifdef __cplusplus +extern "C" { +#endif +// +// When we call Error() or Warning(), the module keeps track of the worst +// case reported. GetUtilityStatus() will get the worst-case results, which +// can be used as the return value from the app. +// +STATUS +GetUtilityStatus ( + VOID + ); + +// +// If someone prints an error message and didn't specify a source file name, +// then we print the utility name instead. However they must tell us the +// utility name early on via this function. +// +VOID +SetUtilityName ( + CHAR8 *ProgramName + ) +; + +VOID +PrintMessage ( + CHAR8 *Type, + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + va_list List + ); + +VOID +Error ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +Warning ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 WarningCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +DebugMsg ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT64 MsgLevel, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +VerboseMsg ( + CHAR8 *MsgFmt, + ... + ); + +VOID +NormalMsg ( + CHAR8 *MsgFmt, + ... + ); + +VOID +KeyMsg ( + CHAR8 *MsgFmt, + ... + ); + +VOID +SetPrintLevel ( + UINT64 LogLevel + ); + +VOID +ParserSetPosition ( + CHAR8 *SourceFileName, + UINT32 LineNum + ) +; + +VOID +ParserError ( + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +ParserWarning ( + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +SetPrintLimits ( + UINT32 NumErrors, + UINT32 NumWarnings, + UINT32 NumWarningsPlusErrors + ) +; + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef _EFI_UTILITY_MSGS_H_ diff --git a/tools/src/GenFw/Common/src/FirmwareVolumeBuffer.c b/tools/src/GenFw/Common/src/FirmwareVolumeBuffer.c new file mode 100644 index 0000000..f8f117b --- /dev/null +++ b/tools/src/GenFw/Common/src/FirmwareVolumeBuffer.c @@ -0,0 +1,1518 @@ +/** @file +EFI Firmware Volume routines which work on a Fv image in buffers. + +Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FirmwareVolumeBufferLib.h" +#include "BinderFuncs.h" + +// +// Local macros +// +#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \ + ( \ + (BOOLEAN) ( \ + (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \ + ) \ + ) + + +// +// Local prototypes +// + +STATIC +UINT32 +FvBufGetSecHdrLen( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + if (SectionHeader == NULL) { + return 0; + } + if (FvBufExpand3ByteSize(SectionHeader->Size) == 0xffffff) { + return sizeof(EFI_COMMON_SECTION_HEADER2); + } + return sizeof(EFI_COMMON_SECTION_HEADER); +} + +STATIC +UINT32 +FvBufGetSecFileLen ( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + UINT32 Length; + if (SectionHeader == NULL) { + return 0; + } + Length = FvBufExpand3ByteSize(SectionHeader->Size); + if (Length == 0xffffff) { + Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize; + } + return Length; +} + +// +// Local prototypes +// + +STATIC +UINT16 +FvBufCalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ); + +STATIC +UINT8 +FvBufCalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ); + +// +// Procedures start +// + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv Address of the Fv in memory, this firmware volume will + be modified, if SourceFfsFile exists + @param SourceFfsFile Input FFS file to replace + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufRemoveFileNew ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* FileToRm; + UINTN FileToRmLength; + + Status = FvBufFindFileByName( + Fv, + Name, + (VOID **)&FileToRm + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FileToRmLength = FvBufGetFfsFileSize (FileToRm); + + CommonLibBinderSetMem ( + FileToRm, + FileToRmLength, + (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) + ? 0xFF : 0 + ); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv Address of the Fv in memory, this firmware volume will + be modified, if SourceFfsFile exists + @param SourceFfsFile Input FFS file to replace + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufRemoveFile ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *NextFile; + EFI_FIRMWARE_VOLUME_HEADER *TempFv; + UINTN FileKey; + UINTN FvLength; + + Status = FvBufFindFileByName( + Fv, + Name, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufGetSize (Fv, &FvLength); + if (EFI_ERROR (Status)) { + return Status; + } + + TempFv = NULL; + Status = FvBufDuplicate (Fv, (VOID **)&TempFv); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufClearAllFiles (TempFv); + if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + + // TempFv has been allocated. It must now be freed + // before returning. + + FileKey = 0; + while (TRUE) { + + Status = FvBufFindNextFile (Fv, &FileKey, (VOID **)&NextFile); + if (Status == EFI_NOT_FOUND) { + break; + } else if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + + if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) { + continue; + } + else { + Status = FvBufAddFile (TempFv, NextFile); + if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + } + } + + CommonLibBinderCopyMem (Fv, TempFv, FvLength); + CommonLibBinderFree (TempFv); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFfsFile Input FFS file to update the checksum for + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufChecksumFile ( + IN OUT VOID *FfsFile + ) +{ + EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile; + EFI_FFS_FILE_STATE StateBackup; + UINT32 FileSize; + + FileSize = FvBufGetFfsFileSize (File); + + // + // Fill in checksums and state, they must be 0 for checksumming. + // + File->IntegrityCheck.Checksum.Header = 0; + File->IntegrityCheck.Checksum.File = 0; + StateBackup = File->State; + File->State = 0; + + File->IntegrityCheck.Checksum.Header = + FvBufCalculateChecksum8 ( + (UINT8 *) File, + FvBufGetFfsHeaderSize (File) + ); + + if (File->Attributes & FFS_ATTRIB_CHECKSUM) { + File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 ( + (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)), + FileSize - FvBufGetFfsHeaderSize (File) + ); + } else { + File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + File->State = StateBackup; + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv Address of the Fv in memory, this firmware volume will + be modified, if SourceFfsFile exists + @param SourceFfsFile Input FFS file to replace + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufChecksumHeader ( + IN OUT VOID *Fv + ) +{ + EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + FvHeader->Checksum = 0; + FvHeader->Checksum = + FvBufCalculateChecksum16 ( + (UINT16*) FvHeader, + FvHeader->HeaderLength / sizeof (UINT16) + ); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv - Address of the Fv in memory + @param DestinationFv - Output for destination Fv + DestinationFv == NULL - invalid parameter + *DestinationFv == NULL - memory will be allocated + *DestinationFv != NULL - this address will be the destination + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufDuplicate ( + IN VOID *SourceFv, + IN OUT VOID **DestinationFv + ) +{ + EFI_STATUS Status; + UINTN size; + + if (DestinationFv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (SourceFv, &size); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*DestinationFv == NULL) { + *DestinationFv = CommonLibBinderAllocate (size); + if (*DestinationFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + CommonLibBinderCopyMem (*DestinationFv, SourceFv, size); + + return EFI_SUCCESS; +} + +/** + Extends a firmware volume by the given number of bytes. + + BUGBUG: Does not handle the case where the firmware volume has a + VTF (Volume Top File). The VTF will not be moved to the + end of the extended FV. + + @param Fv Source and destination firmware volume. + Note: The original firmware volume buffer is freed! + + @param Size The minimum size that the firmware volume is to be extended by. + The FV may be extended more than this size. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufExtend ( + IN VOID **Fv, + IN UINTN Size + ) +{ + EFI_STATUS Status; + UINTN OldSize; + UINTN NewSize; + UINTN BlockCount; + VOID* NewFv; + + EFI_FIRMWARE_VOLUME_HEADER* hdr; + EFI_FV_BLOCK_MAP_ENTRY* blk; + + Status = FvBufGetSize (*Fv, &OldSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Locate the block map in the fv header + // + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv; + blk = hdr->BlockMap; + + // + // Calculate the number of blocks needed to achieve the requested + // size extension + // + BlockCount = ((Size + (blk->Length - 1)) / blk->Length); + + // + // Calculate the new size from the number of blocks that will be added + // + NewSize = OldSize + (BlockCount * blk->Length); + + NewFv = CommonLibBinderAllocate (NewSize); + if (NewFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the old data + // + CommonLibBinderCopyMem (NewFv, *Fv, OldSize); + + // + // Free the old fv buffer + // + CommonLibBinderFree (*Fv); + + // + // Locate the block map in the new fv header + // + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv; + hdr->FvLength = NewSize; + blk = hdr->BlockMap; + + // + // Update the block map for the new fv + // + blk->NumBlocks += (UINT32)BlockCount; + + // + // Update the FV header checksum + // + FvBufChecksumHeader (NewFv); + + // + // Clear out the new area of the FV + // + CommonLibBinderSetMem ( + (UINT8*)NewFv + OldSize, + (NewSize - OldSize), + (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0 + ); + + // + // Set output with new fv that was created + // + *Fv = NewFv; + + return EFI_SUCCESS; + +} + +/** + Clears out all files from the Fv buffer in memory + + @param Fv Address of the Fv in memory + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufClearAllFiles ( + IN OUT VOID *Fv + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_STATUS Status; + UINTN size = 0; + + Status = FvBufGetSize (Fv, &size); + if (EFI_ERROR (Status)) { + return Status; + } + + CommonLibBinderSetMem( + (UINT8*)hdr + hdr->HeaderLength, + size - hdr->HeaderLength, + (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0 + ); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param Fv Address of the Fv in memory + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufGetSize ( + IN VOID *Fv, + OUT UINTN *Size + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap; + + *Size = 0; + + while (blk->Length != 0 || blk->NumBlocks != 0) { + *Size = *Size + (blk->Length * blk->NumBlocks); + if (*Size >= 0x40000000) { + // If size is greater than 1GB, then assume it is corrupted + return EFI_VOLUME_CORRUPTED; + } + blk++; + } + + if (*Size == 0) { + // If size is 0, then assume the volume is corrupted + return EFI_VOLUME_CORRUPTED; + } + + return EFI_SUCCESS; +} + +/** + Adds a new FFS file + + @param Fv Address of the Fv in memory + @param File FFS file to add to Fv + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufAddFile ( + IN OUT VOID *Fv, + IN VOID *File + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER *fhdr = NULL; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN offset; + UINTN fsize; + UINTN newSize; + UINTN clearLoop; + + EFI_STATUS Status; + UINTN fvSize; + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + FvbAttributes = hdr->Attributes; + newSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + + for( + offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8); + offset + newSize <= fvSize; + offset = (UINTN)ALIGN_POINTER (offset, 8) + ) { + + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset); + + if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) + ) { + // BUGBUG: Need to make sure that the new file does not already + // exist. + + fsize = FvBufGetFfsFileSize (fhdr); + if (fsize == 0 || (offset + fsize > fvSize)) { + return EFI_VOLUME_CORRUPTED; + } + + offset = offset + fsize; + continue; + } + + clearLoop = 0; + while ((clearLoop < newSize) && + (((UINT8*)fhdr)[clearLoop] == + (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0) + ) + ) { + clearLoop++; + } + + // + // We found a place in the FV which is empty and big enough for + // the new file + // + if (clearLoop >= newSize) { + break; + } + + offset = offset + 1; // Make some forward progress + } + + if (offset + newSize > fvSize) { + return EFI_OUT_OF_RESOURCES; + } + + CommonLibBinderCopyMem (fhdr, File, newSize); + + return EFI_SUCCESS; +} + +/** + Adds a new FFS file. Extends the firmware volume if needed. + + @param Fv Source and destination firmware volume. + Note: If the FV is extended, then the original firmware volume + buffer is freed! + + @param Size The minimum size that the firmware volume is to be extended by. + The FV may be extended more than this size. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufAddFileWithExtend ( + IN OUT VOID **Fv, + IN VOID *File + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* NewFile; + + NewFile = (EFI_FFS_FILE_HEADER*)File; + + // + // Try to add to the capsule volume + // + Status = FvBufAddFile (*Fv, NewFile); + if (Status == EFI_OUT_OF_RESOURCES) { + // + // Try to extend the capsule volume by the size of the file + // + Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size)); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now, try to add the file again + // + Status = FvBufAddFile (*Fv, NewFile); + } + + return Status; +} + +/** + Adds a new FFS VFT (Volume Top File) file. In other words, adds the + file to the end of the firmware volume. + + @param Fv Address of the Fv in memory + @param File FFS file to add to Fv + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufAddVtfFile ( + IN OUT VOID *Fv, + IN VOID *File + ) +{ + EFI_STATUS Status; + + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER* NewFile; + UINTN NewFileSize; + + UINT8 erasedUint8; + UINTN clearLoop; + + EFI_FFS_FILE_HEADER *LastFile; + UINTN LastFileSize; + + UINTN fvSize; + UINTN Key; + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0); + NewFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + + if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) { + return EFI_INVALID_PARAMETER; + } + + // + // Find the last file in the FV + // + Key = 0; + LastFile = NULL; + LastFileSize = 0; + do { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&LastFile); + LastFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + } while (!EFI_ERROR (Status)); + + // + // If no files were found, then we start at the beginning of the FV + // + if (LastFile == NULL) { + LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength); + } + + // + // We want to put the new file (VTF) at the end of the FV + // + NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize)); + + // + // Check to see if there is enough room for the VTF after the last file + // found in the FV + // + if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Loop to determine if the end of the FV is empty + // + clearLoop = 0; + while ((clearLoop < NewFileSize) && + (((UINT8*)NewFile)[clearLoop] == erasedUint8) + ) { + clearLoop++; + } + + // + // Check to see if there was not enough room for the file + // + if (clearLoop < NewFileSize) { + return EFI_OUT_OF_RESOURCES; + } + + CommonLibBinderCopyMem (NewFile, File, NewFileSize); + + return EFI_SUCCESS; +} + +/** + Expands the 3 byte size commonly used in Firmware Volume data structures + + @param Size Address of the 3 byte array representing the size + + @return UINT32 +**/ +VOID +FvBufCompact3ByteSize ( + OUT VOID* SizeDest, + IN UINT32 Size + ) +{ + ((UINT8*)SizeDest)[0] = (UINT8)Size; + ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8); + ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16); +} + +/** + Get the FFS file size. + + @param Ffs Pointer to FFS header + + @return UINT32 +**/ +UINT32 +FvBufGetFfsFileSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ) +{ + if (Ffs == NULL) { + return 0; + } + if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) { + return (UINT32) ((EFI_FFS_FILE_HEADER2 *)Ffs)->ExtendedSize; + } + return FvBufExpand3ByteSize(Ffs->Size); +} + +/** + Get the FFS header size. + + @param Ffs Pointer to FFS header + + @return UINT32 +**/ +UINT32 +FvBufGetFfsHeaderSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ) +{ + if (Ffs == NULL) { + return 0; + } + if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) { + return sizeof(EFI_FFS_FILE_HEADER2); + } + return sizeof(EFI_FFS_FILE_HEADER); +} + +/** + Expands the 3 byte size commonly used in Firmware Volume data structures + + @param Size Address of the 3 byte array representing the size + + @return UINT32 +**/ +UINT32 +FvBufExpand3ByteSize ( + IN VOID* Size + ) +{ + return (((UINT8*)Size)[2] << 16) + + (((UINT8*)Size)[1] << 8) + + ((UINT8*)Size)[0]; +} + +/** + Iterates through the files contained within the firmware volume + + @param Fv Address of the Fv in memory + @param Key Should be 0 to get the first file. After that, it should be + passed back in without modifying its contents to retrieve + subsequent files. + @param File Output file pointer + File == NULL - invalid parameter + otherwise - *File will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindNextFile ( + IN VOID *Fv, + IN OUT UINTN *Key, + OUT VOID **File + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER *fhdr = NULL; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN fsize; + + EFI_STATUS Status; + UINTN fvSize; + + if (Fv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*Key == 0) { + *Key = hdr->HeaderLength; + } + + FvbAttributes = hdr->Attributes; + + for( + *Key = (UINTN)ALIGN_POINTER (*Key, 8); + (*Key + sizeof (*fhdr)) < fvSize; + *Key = (UINTN)ALIGN_POINTER (*Key, 8) + ) { + + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key); + fsize = FvBufGetFfsFileSize (fhdr); + + if (!EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_INVALID + ) + ) { + *Key = *Key + 1; // Make some forward progress + continue; + } else if( + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_MARKED_FOR_UPDATE + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DELETED + ) + ) { + *Key = *Key + fsize; + continue; + } else if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DATA_VALID + ) + ) { + *File = (UINT8*)hdr + *Key; + *Key = *Key + fsize; + return EFI_SUCCESS; + } + + *Key = *Key + 1; // Make some forward progress + } + + return EFI_NOT_FOUND; +} + +/** + Searches the Fv for a file by its name + + @param Fv Address of the Fv in memory + @param Name Guid filename to search for in the firmware volume + @param File Output file pointer + File == NULL - Only determine if the file exists, based on return + value from the function call. + otherwise - *File will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindFileByName ( + IN VOID *Fv, + IN EFI_GUID *Name, + OUT VOID **File + ) +{ + EFI_STATUS Status; + UINTN Key; + EFI_FFS_FILE_HEADER *NextFile; + + Key = 0; + while (TRUE) { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) { + if (File != NULL) { + *File = NextFile; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Searches the Fv for a file by its type + + @param Fv Address of the Fv in memory + @param Type FFS FILE type to search for + @param File Output file pointer + (File == NULL) -> Only determine if the file exists, based on return + value from the function call. + otherwise -> *File will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindFileByType ( + IN VOID *Fv, + IN EFI_FV_FILETYPE Type, + OUT VOID **File + ) +{ + EFI_STATUS Status; + UINTN Key; + EFI_FFS_FILE_HEADER *NextFile; + + Key = 0; + while (TRUE) { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Type == NextFile->Type) { + if (File != NULL) { + *File = NextFile; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Searches the requested file for raw data. + + This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file, + or finds the EFI_SECTION_RAW section within the file and returns its data. + + @param FfsFile Address of the FFS file in memory + @param RawData Pointer to the raw data within the file + (This is NOT allocated. It is within the file.) + @param RawDataSize Size of the raw data within the file + + @return EFI_STATUS +**/ +EFI_STATUS +FvBufGetFileRawData ( + IN VOID* FfsFile, + OUT VOID** RawData, + OUT UINTN* RawDataSize + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* File; + EFI_RAW_SECTION* Section; + + File = (EFI_FFS_FILE_HEADER*)FfsFile; + + // + // Is the file type == EFI_FV_FILETYPE_RAW? + // + if (File->Type == EFI_FV_FILETYPE_RAW) { + // + // Raw filetypes don't have sections, so we just return the raw data + // + *RawData = (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)); + *RawDataSize = FvBufGetFfsFileSize (File) - FvBufGetFfsHeaderSize (File); + return EFI_SUCCESS; + } + + // + // Within the file, we now need to find the EFI_SECTION_RAW section. + // + Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, (VOID **)&Section); + if (EFI_ERROR (Status)) { + return Status; + } + + *RawData = (VOID*)((UINT8 *)Section + FvBufGetSecHdrLen(Section)); + *RawDataSize = + FvBufGetSecFileLen (Section) - FvBufGetSecHdrLen(Section); + + return EFI_SUCCESS; + +} + +/** + Packages up a FFS file containing the input raw data. + + The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will + contain one EFI_FV_FILETYPE_RAW section. + + @param RawData Pointer to the raw data to be packed + @param RawDataSize Size of the raw data to be packed + @param FfsFile Address of the packaged FFS file. + Note: The called must deallocate this memory! + + @return EFI_STATUS +**/ +EFI_STATUS +FvBufPackageFreeformRawFile ( + IN EFI_GUID* Filename, + IN VOID* RawData, + IN UINTN RawDataSize, + OUT VOID** FfsFile + ) +{ + EFI_FFS_FILE_HEADER* NewFile; + UINT32 NewFileSize; + EFI_RAW_SECTION* NewSection; + UINT32 NewSectionSize; + UINT32 FfsHdrLen; + UINT32 SecHdrLen; + + // + // The section size is the DataSize + the size of the section header + // + NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize; + SecHdrLen = sizeof (EFI_RAW_SECTION); + if (NewSectionSize >= MAX_SECTION_SIZE) { + NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION2) + (UINT32)RawDataSize; + SecHdrLen = sizeof (EFI_RAW_SECTION2); + } + + // + // The file size is the size of the file header + the section size + // + NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize; + FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER); + if (NewFileSize >= MAX_FFS_SIZE) { + NewFileSize = sizeof (EFI_FFS_FILE_HEADER2) + NewSectionSize; + FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER2); + } + + // + // Try to allocate a buffer to build the new FFS file in + // + NewFile = CommonLibBinderAllocate (NewFileSize); + if (NewFile == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CommonLibBinderSetMem (NewFile, NewFileSize, 0); + + // + // The NewSection follow right after the FFS file header + // + NewSection = (EFI_RAW_SECTION*)((UINT8*)NewFile + FfsHdrLen); + if (NewSectionSize >= MAX_SECTION_SIZE) { + FvBufCompact3ByteSize (NewSection->Size, 0xffffff); + ((EFI_RAW_SECTION2 *)NewSection)->ExtendedSize = NewSectionSize; + } else { + FvBufCompact3ByteSize (NewSection->Size, NewSectionSize); + } + NewSection->Type = EFI_SECTION_RAW; + + // + // Copy the actual file data into the buffer + // + CommonLibBinderCopyMem ((UINT8 *)NewSection + SecHdrLen, RawData, RawDataSize); + + // + // Initialize the FFS file header + // + CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID)); + NewFile->Attributes = 0; + if (NewFileSize >= MAX_FFS_SIZE) { + FvBufCompact3ByteSize (NewFile->Size, 0x0); + ((EFI_FFS_FILE_HEADER2 *)NewFile)->ExtendedSize = NewFileSize; + NewFile->Attributes |= FFS_ATTRIB_LARGE_FILE; + } else { + FvBufCompact3ByteSize (NewFile->Size, NewFileSize); + } + NewFile->Type = EFI_FV_FILETYPE_FREEFORM; + NewFile->IntegrityCheck.Checksum.Header = + FvBufCalculateChecksum8 ((UINT8*)NewFile, FfsHdrLen); + NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION | + EFI_FILE_HEADER_VALID | + EFI_FILE_DATA_VALID + ); + + *FfsFile = NewFile; + + return EFI_SUCCESS; +} + +/** + Iterates through the sections contained within a given array of sections + + @param SectionsStart Address of the start of the FFS sections array + @param TotalSectionsSize Total size of all the sections + @param Key Should be 0 to get the first section. After that, it should be + passed back in without modifying its contents to retrieve + subsequent files. + @param Section Output section pointer + (Section == NULL) -> invalid parameter + otherwise -> *Section will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindNextSection ( + IN VOID *SectionsStart, + IN UINTN TotalSectionsSize, + IN OUT UINTN *Key, + OUT VOID **Section + ) +{ + EFI_COMMON_SECTION_HEADER *sectionHdr; + UINTN sectionSize; + + *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned + + if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) { + return EFI_NOT_FOUND; + } + + sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key); + sectionSize = FvBufGetSecFileLen (sectionHdr); + + if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) { + return EFI_NOT_FOUND; + } + + if ((*Key + sectionSize) > TotalSectionsSize) { + return EFI_NOT_FOUND; + } + + *Section = (UINT8*)sectionHdr; + *Key = *Key + sectionSize; + return EFI_SUCCESS; + +} + +/** + Searches the FFS file and counts the number of sections found. + The sections are NOT recursed. + + @param FfsFile Address of the FFS file in memory + @param Count The location to store the section count in + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufCountSections ( + IN VOID* FfsFile, + IN UINTN* Count + ) +{ + EFI_STATUS Status; + UINTN Key; + VOID* SectionStart; + UINTN TotalSectionsSize; + EFI_COMMON_SECTION_HEADER* NextSection; + + SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile)); + TotalSectionsSize = + FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) - + FvBufGetFfsHeaderSize(FfsFile); + Key = 0; + *Count = 0; + while (TRUE) { + Status = FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&NextSection + ); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } else if (EFI_ERROR (Status)) { + return Status; + } + + // + // Increment the section counter + // + *Count += 1; + + } + + return EFI_NOT_FOUND; +} + +/** + Searches the FFS file for a section by its type + + @param FfsFile Address of the FFS file in memory + @param Type FFS FILE section type to search for + @param Section Output section pointer + (Section == NULL) -> Only determine if the section exists, based on return + value from the function call. + otherwise -> *Section will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindSectionByType ( + IN VOID *FfsFile, + IN UINT8 Type, + OUT VOID **Section + ) +{ + EFI_STATUS Status; + UINTN Key; + VOID* SectionStart; + UINTN TotalSectionsSize; + EFI_COMMON_SECTION_HEADER* NextSection; + + SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile)); + TotalSectionsSize = + FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) - + FvBufGetFfsHeaderSize(FfsFile); + Key = 0; + while (TRUE) { + Status = FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&NextSection + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Type == NextSection->Type) { + if (Section != NULL) { + *Section = NextSection; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Shrinks a firmware volume (in place) to provide a minimal FV. + + BUGBUG: Does not handle the case where the firmware volume has a + VTF (Volume Top File). The VTF will not be moved to the + end of the extended FV. + + @param Fv Firmware volume. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufShrinkWrap ( + IN VOID *Fv + ) +{ + EFI_STATUS Status; + UINTN OldSize; + UINT32 BlockCount; + UINT32 NewBlockSize = 128; + UINTN Key; + EFI_FFS_FILE_HEADER* FileIt; + VOID* EndOfLastFile; + + EFI_FIRMWARE_VOLUME_HEADER* FvHdr; + + Status = FvBufGetSize (Fv, &OldSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufUnifyBlockSizes (Fv, NewBlockSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Locate the block map in the fv header + // + FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + // + // Find the end of the last file + // + Key = 0; + EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength; + while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, (VOID **)&FileIt))) { + EndOfLastFile = + (VOID*)((UINT8*)FileIt + FvBufGetFfsFileSize (FileIt)); + } + + // + // Set the BlockCount to have the minimal number of blocks for the Fv. + // + BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv); + BlockCount = BlockCount + NewBlockSize - 1; + BlockCount = BlockCount / NewBlockSize; + + // + // Adjust the block count to shrink the Fv in place. + // + FvHdr->BlockMap[0].NumBlocks = BlockCount; + FvHdr->FvLength = BlockCount * NewBlockSize; + + // + // Update the FV header checksum + // + FvBufChecksumHeader (Fv); + + return EFI_SUCCESS; + +} + +/** + Searches the FFS file for a section by its type + + @param Fv Address of the Fv in memory + @param BlockSize The size of the blocks to convert the Fv to. If the total size + of the Fv is not evenly divisible by this size, then + EFI_INVALID_PARAMETER will be returned. + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufUnifyBlockSizes ( + IN OUT VOID *Fv, + IN UINTN BlockSize + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap; + UINT32 Size; + + Size = 0; + + // + // Scan through the block map list, performing error checking, and adding + // up the total Fv size. + // + while( blk->Length != 0 || + blk->NumBlocks != 0 + ) { + Size = Size + (blk->Length * blk->NumBlocks); + blk++; + if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) { + return EFI_VOLUME_CORRUPTED; + } + } + + // + // Make sure that the Fv size is a multiple of the new block size. + // + if ((Size % BlockSize) != 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Zero out the entire block map. + // + CommonLibBinderSetMem ( + &hdr->BlockMap, + (UINTN)blk - (UINTN)&hdr->BlockMap, + 0 + ); + + // + // Write out the single block map entry. + // + hdr->BlockMap[0].Length = (UINT32)BlockSize; + hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize; + + return EFI_SUCCESS; +} + +/** + This function calculates the UINT16 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum +**/ +STATIC +UINT16 +FvBufCalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT16 Sum; + + Sum = 0; + + // + // Perform the word sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT16) (Sum + Buffer[Index]); + } + + return (UINT16) Sum; +} + +/** + This function calculates the value needed for a valid UINT16 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum value needed. +**/ +STATIC +UINT16 +FvBufCalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size)); +} + +/** + This function calculates the UINT8 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +STATIC +UINT8 +FvBufCalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT8 Sum; + + Sum = 0; + + // + // Perform the byte sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT8) (Sum + Buffer[Index]); + } + + return Sum; +} + +/** + This function calculates the value needed for a valid UINT8 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +STATIC +UINT8 +FvBufCalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size)); +} + + diff --git a/tools/src/GenFw/Common/src/FirmwareVolumeBufferLib.h b/tools/src/GenFw/Common/src/FirmwareVolumeBufferLib.h new file mode 100644 index 0000000..6ba9e80 --- /dev/null +++ b/tools/src/GenFw/Common/src/FirmwareVolumeBufferLib.h @@ -0,0 +1,163 @@ +/** @file +EFI Firmware Volume routines which work on a Fv image in buffers. + +Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef FirmwareVolumeBuffer_h_INCLUDED +#define FirmwareVolumeBuffer_h_INCLUDED + +#include "Common/UefiBaseTypes.h" +#include "Common/PiFirmwareFile.h" +#include "Common/PiFirmwareVolume.h" + +EFI_STATUS +FvBufAddFile ( + IN OUT VOID *Fv, + IN VOID *File + ); + +EFI_STATUS +FvBufAddFileWithExtend ( + IN OUT VOID **Fv, + IN VOID *File + ); + +EFI_STATUS +FvBufAddVtfFile ( + IN OUT VOID *Fv, + IN VOID *File + ); + +EFI_STATUS +FvBufChecksumFile ( + IN OUT VOID *FfsFile + ); + +EFI_STATUS +FvBufChecksumHeader ( + IN OUT VOID *Fv + ); + +EFI_STATUS +FvBufClearAllFiles ( + IN OUT VOID *Fv + ); + +VOID +FvBufCompact3ByteSize ( + OUT VOID* SizeDest, + IN UINT32 Size + ); + +EFI_STATUS +FvBufCountSections ( + IN VOID* FfsFile, + IN UINTN* Count + ); + +EFI_STATUS +FvBufDuplicate ( + IN VOID *SourceFv, + IN OUT VOID **DestinationFv + ); + +UINT32 +FvBufExpand3ByteSize ( + IN VOID* Size + ); + +UINT32 +FvBufGetFfsFileSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ); + +UINT32 +FvBufGetFfsHeaderSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ); + +EFI_STATUS +FvBufExtend ( + IN VOID **Fv, + IN UINTN Size + ); + +EFI_STATUS +FvBufFindFileByName ( + IN VOID *Fv, + IN EFI_GUID *Name, + OUT VOID **File + ); + +EFI_STATUS +FvBufFindFileByType ( + IN VOID *Fv, + IN EFI_FV_FILETYPE Type, + OUT VOID **File + ); + +EFI_STATUS +FvBufFindNextFile ( + IN VOID *Fv, + IN OUT UINTN *Key, + OUT VOID **File + ); + +EFI_STATUS +FvBufFindNextSection ( + IN VOID *SectionsStart, + IN UINTN TotalSectionsSize, + IN OUT UINTN *Key, + OUT VOID **Section + ); + +EFI_STATUS +FvBufFindSectionByType ( + IN VOID *FfsFile, + IN UINT8 Type, + OUT VOID **Section + ); + +EFI_STATUS +FvBufGetFileRawData ( + IN VOID* FfsFile, + OUT VOID** RawData, + OUT UINTN* RawDataSize + ); + +EFI_STATUS +FvBufGetSize ( + IN VOID *Fv, + OUT UINTN *Size + ); + +EFI_STATUS +FvBufPackageFreeformRawFile ( + IN EFI_GUID* Filename, + IN VOID* RawData, + IN UINTN RawDataSize, + OUT VOID** FfsFile + ); + +EFI_STATUS +FvBufRemoveFile ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ); + +EFI_STATUS +FvBufUnifyBlockSizes ( + IN OUT VOID *Fv, + IN UINTN BlockSize + ); + +EFI_STATUS +FvBufShrinkWrap ( + IN VOID *Fv + ); + +#endif // #ifndef FirmwareVolumeBuffer_h_INCLUDED + diff --git a/tools/src/GenFw/Common/src/FvLib.c b/tools/src/GenFw/Common/src/FvLib.c new file mode 100644 index 0000000..2b1b774 --- /dev/null +++ b/tools/src/GenFw/Common/src/FvLib.c @@ -0,0 +1,828 @@ +/** @file +These functions assist in parsing and manipulating a Firmware Volume. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Include files +// +#include "FvLib.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" + +// +// Module global variables +// +EFI_FIRMWARE_VOLUME_HEADER *mFvHeader = NULL; +UINT32 mFvLength = 0; + +// +// External function implementations +// + +/** + This initializes the FV lib with a pointer to the FV and length. It does not + verify the FV in any way. + + @param Fv Buffer containing the FV. + @param FvLength Length of the FV + + @retval EFI_SUCCESS Function Completed successfully. + @retval EFI_INVALID_PARAMETER A required parameter was NULL. +**/ +EFI_STATUS +InitializeFvLib ( + IN VOID *Fv, + IN UINT32 FvLength + ) +{ + // + // Verify input arguments + // + if (Fv == NULL) { + return EFI_INVALID_PARAMETER; + } + + mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv; + mFvLength = FvLength; + + return EFI_SUCCESS; +} + +/** + This function returns a pointer to the current FV and the size. + + @param FvHeader Pointer to the FV buffer. + @param FvLength Length of the FV + + @retval EFI_SUCCESS Function Completed successfully. + @retval EFI_INVALID_PARAMETER A required parameter was NULL. + @retvalEFI_ABORTED The library needs to be initialized. +**/ +EFI_STATUS +GetFvHeader ( + OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader, + OUT UINT32 *FvLength + ) +{ + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input arguments + // + if (FvHeader == NULL) { + return EFI_INVALID_PARAMETER; + } + + *FvHeader = mFvHeader; + *FvLength = mFvLength; + return EFI_SUCCESS; +} + +/** + This function returns the next file. If the current file is NULL, it returns + the first file in the FV. If the function returns EFI_SUCCESS and the file + pointer is NULL, then there are no more files in the FV. + + @param CurrentFile Pointer to the current file, must be within the current FV. + @param NextFile Pointer to the next file in the FV. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_INVALID_PARAMETER A required parameter was NULL or is out of range. + @retval EFI_ABORTED The library needs to be initialized. +**/ +EFI_STATUS +GetNextFile ( + IN EFI_FFS_FILE_HEADER *CurrentFile, + OUT EFI_FFS_FILE_HEADER **NextFile + ) +{ + EFI_STATUS Status; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input arguments + // + if (NextFile == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Get first file + // + if (CurrentFile == NULL) { + CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength); + + // + // Verify file is valid + // + Status = VerifyFfsFile (CurrentFile); + if (EFI_ERROR (Status)) { + // + // no files in this FV + // + *NextFile = NULL; + return EFI_SUCCESS; + } else { + // + // Verify file is in this FV. + // + if ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) { + *NextFile = NULL; + return EFI_SUCCESS; + } + + *NextFile = CurrentFile; + return EFI_SUCCESS; + } + } + // + // Verify current file is in range + // + if (((UINTN) CurrentFile < (UINTN) mFvHeader + mFvHeader->HeaderLength) || + ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) + ) { + return EFI_INVALID_PARAMETER; + } + // + // Get next file, compensate for 8 byte alignment if necessary. + // + *NextFile = (EFI_FFS_FILE_HEADER *) ((((UINTN) CurrentFile - (UINTN) mFvHeader + GetFfsFileLength(CurrentFile) + 0x07) & (~(UINTN) 7)) + (UINT8 *) mFvHeader); + + // + // Verify file is in this FV. + // + if (((UINTN) *NextFile + GetFfsHeaderLength(*NextFile) >= (UINTN) mFvHeader + mFvLength) || + ((UINTN) *NextFile + GetFfsFileLength (*NextFile) > (UINTN) mFvHeader + mFvLength) + ) { + *NextFile = NULL; + return EFI_SUCCESS; + } + // + // Verify file is valid + // + Status = VerifyFfsFile (*NextFile); + if (EFI_ERROR (Status)) { + // + // no more files in this FV + // + *NextFile = NULL; + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +/** + Find a file by name. The function will return NULL if the file is not found. + + @param FileName The GUID file name of the file to search for. + @param File Return pointer. In the case of an error, contents are undefined. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ABORTED An error was encountered. + @retval EFI_INVALID_PARAMETER One of the parameters was NULL. +**/ +EFI_STATUS +GetFileByName ( + IN EFI_GUID *FileName, + OUT EFI_FFS_FILE_HEADER **File + ) +{ + EFI_FFS_FILE_HEADER *CurrentFile; + EFI_STATUS Status; + CHAR8 FileGuidString[80]; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input parameters + // + if (FileName == NULL || File == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // File Guid String Name + // + PrintGuidToBuffer (FileName, (UINT8 *)FileGuidString, sizeof (FileGuidString), TRUE); + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Get the first file + // + Status = GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString); + return EFI_ABORTED; + } + // + // Loop as long as we have a valid file + // + while (CurrentFile) { + if (!CompareGuid (&CurrentFile->Name, FileName)) { + *File = CurrentFile; + return EFI_SUCCESS; + } + + Status = GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString); + return EFI_ABORTED; + } + } + // + // File not found in this FV. + // + *File = NULL; + return EFI_SUCCESS; +} + +/** + Find a file by type and instance. An instance of 1 is the first instance. + The function will return NULL if a matching file cannot be found. + File type EFI_FV_FILETYPE_ALL means any file type is valid. + + @param FileType Type of file to search for. + @param Instance Instance of the file type to return. + @param File Return pointer. In the case of an error, contents are undefined. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ABORTED An error was encountered. + @retval EFI_INVALID_PARAMETER One of the parameters was NULL. +**/ +EFI_STATUS +GetFileByType ( + IN EFI_FV_FILETYPE FileType, + IN UINTN Instance, + OUT EFI_FFS_FILE_HEADER **File + ) +{ + EFI_FFS_FILE_HEADER *CurrentFile; + EFI_STATUS Status; + UINTN FileCount; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input parameters + // + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Initialize the number of matching files found. + // + FileCount = 0; + + // + // Get the first file + // + Status = GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType); + return EFI_ABORTED; + } + // + // Loop as long as we have a valid file + // + while (CurrentFile) { + if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) { + FileCount++; + } + + if (FileCount == Instance) { + *File = CurrentFile; + return EFI_SUCCESS; + } + + Status = GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType); + return EFI_ABORTED; + } + } + + *File = NULL; + return EFI_SUCCESS; +} + +/** + Helper function to search a sequence of sections from the section pointed + by FirstSection to SearchEnd for the Instance-th section of type SectionType. + The current counter is saved in StartIndex and when the section is found, it's + saved in Section. GUID-defined sections, if special processing is not required, + are searched recursively in a depth-first manner. + + @param FirstSection The first section to start searching from. + @param SearchEnd The end address to stop search. + @param SectionType The type of section to search. + @param StartIndex The current counter is saved. + @param Instance The requested n-th section number. + @param Section The found section returned. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The section is not found. +**/ +EFI_STATUS +SearchSectionByType ( + IN EFI_FILE_SECTION_POINTER FirstSection, + IN UINT8 *SearchEnd, + IN EFI_SECTION_TYPE SectionType, + IN OUT UINTN *StartIndex, + IN UINTN Instance, + OUT EFI_FILE_SECTION_POINTER *Section + ) +{ + EFI_FILE_SECTION_POINTER CurrentSection; + EFI_FILE_SECTION_POINTER InnerSection; + EFI_STATUS Status; + UINTN SectionSize; + UINT16 GuidSecAttr; + UINT16 GuidDataOffset; + + GuidSecAttr = 0; + GuidDataOffset = 0; + CurrentSection = FirstSection; + + while ((UINTN) CurrentSection.CommonHeader < (UINTN) SearchEnd) { + if (CurrentSection.CommonHeader->Type == SectionType) { + (*StartIndex)++; + } + + if (*StartIndex == Instance) { + *Section = CurrentSection; + return EFI_SUCCESS; + } + // + // If the requesting section is not GUID-defined and + // we find a GUID-defined section that doesn't need + // special processing, go ahead to search the requesting + // section inside the GUID-defined section. + // + if (CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED) { + if (GetLength(CurrentSection.CommonHeader->Size) == 0xffffff) { + GuidSecAttr = CurrentSection.GuidDefinedSection2->Attributes; + GuidDataOffset = CurrentSection.GuidDefinedSection2->DataOffset; + } else { + GuidSecAttr = CurrentSection.GuidDefinedSection->Attributes; + GuidDataOffset = CurrentSection.GuidDefinedSection->DataOffset; + } + } + if (SectionType != EFI_SECTION_GUID_DEFINED && + CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED && + !(GuidSecAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) { + InnerSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) + ((UINTN) CurrentSection.CommonHeader + GuidDataOffset); + SectionSize = GetSectionFileLength(CurrentSection.CommonHeader); + Status = SearchSectionByType ( + InnerSection, + (UINT8 *) ((UINTN) CurrentSection.CommonHeader + SectionSize), + SectionType, + StartIndex, + Instance, + Section + ); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + } + // + // Find next section (including compensating for alignment issues. + // + CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetSectionFileLength(CurrentSection.CommonHeader) + 0x03) & (~(UINTN) 3)); + } + + return EFI_NOT_FOUND; +} + +/** + Find a section in a file by type and instance. An instance of 1 is the first + instance. The function will return NULL if a matching section cannot be found. + GUID-defined sections, if special processing is not needed, are handled in a + depth-first manner. + + @param File The file to search. + @param SectionType Type of file to search for. + @param Instance Instance of the section to return. + @param Section Return pointer. In the case of an error, contents are undefined. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ABORTED An error was encountered. + @retval EFI_INVALID_PARAMETER One of the parameters was NULL. + @retval EFI_NOT_FOUND No found. +**/ +EFI_STATUS +GetSectionByType ( + IN EFI_FFS_FILE_HEADER *File, + IN EFI_SECTION_TYPE SectionType, + IN UINTN Instance, + OUT EFI_FILE_SECTION_POINTER *Section + ) +{ + EFI_FILE_SECTION_POINTER CurrentSection; + EFI_STATUS Status; + UINTN SectionCount; + + // + // Verify input parameters + // + if (File == NULL || Instance == 0) { + return EFI_INVALID_PARAMETER; + } + // + // Verify FFS header + // + Status = VerifyFfsFile (File); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0006, "invalid FFS file", NULL); + return EFI_ABORTED; + } + // + // Initialize the number of matching sections found. + // + SectionCount = 0; + + // + // Get the first section + // + CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + GetFfsHeaderLength(File)); + + // + // Depth-first manner to find section file. + // + Status = SearchSectionByType ( + CurrentSection, + (UINT8 *) ((UINTN) File + GetFfsFileLength (File)), + SectionType, + &SectionCount, + Instance, + Section + ); + + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } else { + // + // Section not found + // + (*Section).Code16Section = NULL; + return EFI_NOT_FOUND; + } +} + +// +// will not parse compressed sections +// + +/** + Verify the current pointer points to a valid FV header. + + @param FvHeader Pointer to an alleged FV file. + + @retval EFI_SUCCESS The FV header is valid. + @retval EFI_VOLUME_CORRUPTED The FV header is not valid. + @retval EFI_INVALID_PARAMETER A required parameter was NULL. + @retval EFI_ABORTED Operation aborted. +**/ +EFI_STATUS +VerifyFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +{ + UINT16 Checksum; + + // + // Verify input parameters + // + if (FvHeader == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (FvHeader->Signature != EFI_FVH_SIGNATURE) { + Error (NULL, 0, 0006, "invalid FV header signature", NULL); + return EFI_VOLUME_CORRUPTED; + } + // + // Verify header checksum + // + Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); + + if (Checksum != 0) { + Error (NULL, 0, 0006, "invalid FV header checksum", NULL); + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + Verify the current pointer points to a FFS file header. + + @param FfsHeader Pointer to an alleged FFS file. + + @retval EFI_SUCCESS The Ffs header is valid. + @retval EFI_NOT_FOUND This "file" is the beginning of free space. + @retval EFI_VOLUME_CORRUPTED The Ffs header is not valid. + @retval EFI_ABORTED The erase polarity is not known. +**/ +EFI_STATUS +VerifyFfsFile ( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + BOOLEAN ErasePolarity; + EFI_STATUS Status; + EFI_FFS_FILE_HEADER2 BlankHeader; + UINT8 Checksum; + UINT32 FileLength; + UINT8 SavedChecksum; + UINT8 SavedState; + UINT8 FileGuidString[80]; + UINT32 FfsHeaderSize; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Get the erase polarity. + // + Status = GetErasePolarity (&ErasePolarity); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + FfsHeaderSize = GetFfsHeaderLength(FfsHeader); + // + // Check if we have free space + // + if (ErasePolarity) { + memset (&BlankHeader, -1, FfsHeaderSize); + } else { + memset (&BlankHeader, 0, FfsHeaderSize); + } + + if (memcmp (&BlankHeader, FfsHeader, FfsHeaderSize) == 0) { + return EFI_NOT_FOUND; + } + // + // Convert the GUID to a string so we can at least report which file + // if we find an error. + // + PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE); + // + // Verify file header checksum + // + SavedState = FfsHeader->State; + FfsHeader->State = 0; + SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File; + FfsHeader->IntegrityCheck.Checksum.File = 0; + Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FfsHeaderSize); + FfsHeader->State = SavedState; + FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum; + if (Checksum != 0) { + Error (NULL, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString); + return EFI_ABORTED; + } + // + // Verify file checksum + // + if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Verify file data checksum + // + FileLength = GetFfsFileLength (FfsHeader); + Checksum = CalculateSum8 ((UINT8 *) ((UINT8 *)FfsHeader + FfsHeaderSize), FileLength - FfsHeaderSize); + Checksum = Checksum + FfsHeader->IntegrityCheck.Checksum.File; + if (Checksum != 0) { + Error (NULL, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString); + return EFI_ABORTED; + } + } else { + // + // File does not have a checksum + // Verify contents are 0xAA as spec'd + // + if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) { + Error (NULL, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString); + return EFI_ABORTED; + } + } + + return EFI_SUCCESS; +} + +UINT32 +GetFfsHeaderLength( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + if (FfsHeader == NULL) { + return 0; + } + if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) { + return sizeof(EFI_FFS_FILE_HEADER2); + } + return sizeof(EFI_FFS_FILE_HEADER); +} + +UINT32 +GetSectionHeaderLength( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + if (SectionHeader == NULL) { + return 0; + } + if (GetLength(SectionHeader->Size) == 0xffffff) { + return sizeof(EFI_COMMON_SECTION_HEADER2); + } + return sizeof(EFI_COMMON_SECTION_HEADER); +} + +/** + Get FFS file length including FFS header. + + @param FfsHeader Pointer to EFI_FFS_FILE_HEADER. + + @return UINT32 Length of FFS file header. +**/ +UINT32 +GetFfsFileLength ( + EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + if (FfsHeader == NULL) { + return 0; + } + if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) { + return (UINT32) ((EFI_FFS_FILE_HEADER2 *)FfsHeader)->ExtendedSize; + } else { + return GetLength(FfsHeader->Size); + } +} + +UINT32 +GetSectionFileLength ( + EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + UINT32 Length; + if (SectionHeader == NULL) { + return 0; + } + Length = GetLength(SectionHeader->Size); + if (Length == 0xffffff) { + Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize; + } + return Length; +} + +/** + Converts a three byte length value into a UINT32. + + @param ThreeByteLength Pointer to the first of the 3 byte length. + + @return UINT32 Size of the section +**/ +UINT32 +GetLength ( + UINT8 *ThreeByteLength + ) +{ + UINT32 Length; + + if (ThreeByteLength == NULL) { + return 0; + } + + Length = *((UINT32 *) ThreeByteLength); + Length = Length & 0x00FFFFFF; + + return Length; +} + +/** + This function returns with the FV erase polarity. If the erase polarity + for a bit is 1, the function return TRUE. + + @param ErasePolarity A pointer to the erase polarity. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED Operation aborted. +**/ +EFI_STATUS +GetErasePolarity ( + OUT BOOLEAN *ErasePolarity + ) +{ + EFI_STATUS Status; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Verify input parameters. + // + if (ErasePolarity == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mFvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + *ErasePolarity = TRUE; + } else { + *ErasePolarity = FALSE; + } + + return EFI_SUCCESS; +} + +/** + This function returns a the highest state bit in the FFS that is set. + It in no way validate the FFS file. + + @param ErasePolarity The erase polarity for the file state bits. + @param FfsHeader Pointer to a FFS file. + + @retval UINT8 The hightest set state of the file. +**/ +UINT8 +GetFileState ( + IN BOOLEAN ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + UINT8 FileState; + UINT8 HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity) { + FileState = (UINT8)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} diff --git a/tools/src/GenFw/Common/src/FvLib.h b/tools/src/GenFw/Common/src/FvLib.h new file mode 100644 index 0000000..0128779 --- /dev/null +++ b/tools/src/GenFw/Common/src/FvLib.h @@ -0,0 +1,189 @@ +/** @file +These functions assist in parsing and manipulating a Firmware Volume. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_FV_LIB_H +#define _EFI_FV_LIB_H + +// +// Include files +// +#include + +#include +#include +#include + +EFI_STATUS +InitializeFvLib ( + IN VOID *Fv, + IN UINT32 FvLength + ) +; + +EFI_STATUS +GetFvHeader ( + OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader, + OUT UINT32 *FvLength + ) +; + +EFI_STATUS +GetNextFile ( + IN EFI_FFS_FILE_HEADER *CurrentFile, + OUT EFI_FFS_FILE_HEADER **NextFile + ) +; + +EFI_STATUS +GetFileByName ( + IN EFI_GUID *FileName, + OUT EFI_FFS_FILE_HEADER **File + ) +; + +EFI_STATUS +GetFileByType ( + IN EFI_FV_FILETYPE FileType, + IN UINTN Instance, + OUT EFI_FFS_FILE_HEADER **File + ) +; + +EFI_STATUS +GetSectionByType ( + IN EFI_FFS_FILE_HEADER *File, + IN EFI_SECTION_TYPE SectionType, + IN UINTN Instance, + OUT EFI_FILE_SECTION_POINTER *Section + ) +; +// +// will not parse compressed sections +// +EFI_STATUS +VerifyFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +; + +EFI_STATUS +VerifyFfsFile ( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +UINT32 +GetFfsFileLength ( + EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +UINT32 +GetSectionFileLength ( + EFI_COMMON_SECTION_HEADER *SectionHeader + ) +; + +UINT32 +GetFfsHeaderLength( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +UINT32 +GetSectionHeaderLength( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +; + +/*++ + +Routine Description: + + Verify the current pointer points to a FFS file header. + +Arguments: + + FfsHeader Pointer to an alleged FFS file. + +Returns: + + EFI_SUCCESS The Ffs header is valid. + EFI_NOT_FOUND This "file" is the beginning of free space. + EFI_VOLUME_CORRUPTED The Ffs header is not valid. + +--*/ +UINT32 +GetLength ( + UINT8 *ThreeByteLength + ) +; + +/*++ + +Routine Description: + + Converts a three byte length value into a UINT32. + +Arguments: + + ThreeByteLength Pointer to the first of the 3 byte length. + +Returns: + + UINT32 Size of the section + +--*/ +EFI_STATUS +GetErasePolarity ( + OUT BOOLEAN *ErasePolarity + ) +; + +/*++ + +Routine Description: + + This function returns with the FV erase polarity. If the erase polarity + for a bit is 1, the function return TRUE. + +Arguments: + + ErasePolarity A pointer to the erase polarity. + +Returns: + + EFI_SUCCESS The function completed successfully. + EFI_INVALID_PARAMETER One of the input parameters was invalid. + +--*/ +UINT8 +GetFileState ( + IN BOOLEAN ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +/*++ + +Routine Description: + + This function returns a the highest state bit in the FFS that is set. + It in no way validate the FFS file. + +Arguments: + + ErasePolarity The erase polarity for the file state bits. + FfsHeader Pointer to a FFS file. + +Returns: + + UINT8 The hightest set state of the file. + +--*/ +#endif diff --git a/tools/src/GenFw/Common/src/MemoryFile.c b/tools/src/GenFw/Common/src/MemoryFile.c new file mode 100644 index 0000000..556d1a3 --- /dev/null +++ b/tools/src/GenFw/Common/src/MemoryFile.c @@ -0,0 +1,225 @@ +/** @file +This contains some useful functions for accessing files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include "CommonLib.h" +#include "MemoryFile.h" + + +// +// Local (static) function prototypes +// +STATIC +VOID +CheckMemoryFileState ( + IN EFI_HANDLE InputMemoryFile + ); + +// +// Function implementations +// + +/** + This opens a file, reads it into memory and returns a memory file + object. + + @param InputFile Memory file image. + @param OutputMemoryFile Handle to memory file + + @return EFI_STATUS + OutputMemoryFile is valid if !EFI_ERROR +**/ +EFI_STATUS +GetMemoryFile ( + IN CHAR8 *InputFileName, + OUT EFI_HANDLE *OutputMemoryFile + ) +{ + EFI_STATUS Status; + CHAR8 *InputFileImage; + UINT32 BytesRead; + MEMORY_FILE *NewMemoryFile; + + Status = GetFileImage (InputFileName, &InputFileImage, &BytesRead); + if (EFI_ERROR (Status)) { + return Status; + } + + NewMemoryFile = malloc (sizeof (*NewMemoryFile)); + if (NewMemoryFile == NULL) { + free (InputFileImage); + return EFI_OUT_OF_RESOURCES; + } + + NewMemoryFile->FileImage = InputFileImage; + NewMemoryFile->CurrentFilePointer = InputFileImage; + NewMemoryFile->Eof = InputFileImage + BytesRead; + + *OutputMemoryFile = (EFI_HANDLE)NewMemoryFile; + + CheckMemoryFileState (*OutputMemoryFile); + + return EFI_SUCCESS; +} + +/** + Frees all memory associated with the input memory file. + + @param InputMemoryFile Handle to memory file + + @return EFI_STATUS +**/ +EFI_STATUS +FreeMemoryFile ( + IN EFI_HANDLE InputMemoryFile + ) +{ + MEMORY_FILE *MemoryFile; + + CheckMemoryFileState (InputMemoryFile); + + MemoryFile = (MEMORY_FILE*)InputMemoryFile; + + free (MemoryFile->FileImage); + + // + // Invalidate state of MEMORY_FILE structure to catch invalid usage. + // + memset (MemoryFile, 0xcc, sizeof (*MemoryFile)); + MemoryFile->Eof -= 1; + + free (MemoryFile); + + return EFI_SUCCESS; +} + +/** + This function reads a line from the memory file. The newline characters + are stripped and a null terminated string is returned. + + If the string pointer returned is non-NULL, then the caller must free the + memory associated with this string. + + @param InputMemoryFile Handle to memory file + + @retval NULL if error or EOF + @retval NULL character termincated string otherwise (MUST BE FREED BY CALLER) +**/ +CHAR8 * +ReadMemoryFileLine ( + IN EFI_HANDLE InputMemoryFile + ) +{ + CHAR8 *EndOfLine; + UINTN CharsToCopy; + MEMORY_FILE *InputFile; + UINTN BytesToEof; + CHAR8 *OutputString; + + // + // Verify input parameters are not null + // + CheckMemoryFileState (InputMemoryFile); + + InputFile = (MEMORY_FILE*)InputMemoryFile; + + // + // Check for end of file condition + // + if (InputFile->CurrentFilePointer >= InputFile->Eof) { + return NULL; + } + + // + // Determine the number of bytes remaining until the EOF + // + BytesToEof = InputFile->Eof - InputFile->CurrentFilePointer; + + // + // Find the next newline char + // + EndOfLine = memchr (InputFile->CurrentFilePointer, '\n', BytesToEof); + + // + // Determine the number of characters to copy. + // + if (EndOfLine == 0) { + // + // If no newline found, copy to the end of the file. + // + CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; + } else { + // + // Newline found in the file. + // + CharsToCopy = EndOfLine - InputFile->CurrentFilePointer; + } + + OutputString = malloc (CharsToCopy + 1); + if (OutputString == NULL) { + return NULL; + } + + // + // Copy the line. + // + memcpy (OutputString, InputFile->CurrentFilePointer, CharsToCopy); + + // + // Add the null termination over the 0x0D + // + if (OutputString[CharsToCopy - 1] == '\r') { + + OutputString[CharsToCopy - 1] = '\0'; + + } else { + + OutputString[CharsToCopy] = '\0'; + + } + + // + // Increment the current file pointer (include the 0x0A) + // + InputFile->CurrentFilePointer += CharsToCopy + 1; + if (InputFile->CurrentFilePointer > InputFile->Eof) { + InputFile->CurrentFilePointer = InputFile->Eof; + } + CheckMemoryFileState (InputMemoryFile); + + // + // Return the string + // + return OutputString; +} + + +STATIC +VOID +CheckMemoryFileState ( + IN EFI_HANDLE InputMemoryFile + ) +{ + MEMORY_FILE *MemoryFile; + + assert (InputMemoryFile != NULL); + + MemoryFile = (MEMORY_FILE*)InputMemoryFile; + + assert (MemoryFile->FileImage != NULL); + assert (MemoryFile->CurrentFilePointer != NULL); + assert (MemoryFile->Eof != NULL); + assert (MemoryFile->Eof >= MemoryFile->FileImage); + assert (MemoryFile->CurrentFilePointer >= MemoryFile->FileImage); + assert (MemoryFile->CurrentFilePointer <= MemoryFile->Eof); +} + + diff --git a/tools/src/GenFw/Common/src/MemoryFile.h b/tools/src/GenFw/Common/src/MemoryFile.h new file mode 100644 index 0000000..a466bbf --- /dev/null +++ b/tools/src/GenFw/Common/src/MemoryFile.h @@ -0,0 +1,79 @@ +/** @file +Header file for helper functions useful for accessing files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_MEMORY_FILE_H +#define _EFI_MEMORY_FILE_H + +#include +#include +#include + +// +// Common data structures +// +typedef struct { + CHAR8 *FileImage; + CHAR8 *Eof; + CHAR8 *CurrentFilePointer; +} MEMORY_FILE; + + +// +// Functions declarations +// + +/** + This opens a file, reads it into memory and returns a memory file + object. + + @param InputFile Memory file image. + @param OutputMemoryFile Handle to memory file + + @return EFI_STATUS + OutputMemoryFile is valid if !EFI_ERROR +**/ +EFI_STATUS +GetMemoryFile ( + IN CHAR8 *InputFileName, + OUT EFI_HANDLE *OutputMemoryFile + ) +; + +/** + Frees all memory associated with the input memory file. + + @param InputMemoryFile Handle to memory file + + @return EFI_STATUS +**/ +EFI_STATUS +FreeMemoryFile ( + IN EFI_HANDLE InputMemoryFile + ) +; + +/** + This function reads a line from the memory file. The newline characters + are stripped and a null terminated string is returned. + + If the string pointer returned is non-NULL, then the caller must free the + memory associated with this string. + + @param InputMemoryFile Handle to memory file + + @retval NULL if error or EOF + @retval NULL character termincated string otherwise (MUST BE FREED BY CALLER) +**/ +CHAR8 * +ReadMemoryFileLine ( + IN EFI_HANDLE InputMemoryFile + ) +; + + +#endif diff --git a/tools/src/GenFw/Common/src/MyAlloc.c b/tools/src/GenFw/Common/src/MyAlloc.c new file mode 100644 index 0000000..d2ebcb2 --- /dev/null +++ b/tools/src/GenFw/Common/src/MyAlloc.c @@ -0,0 +1,489 @@ +/** @file +File for memory allocation tracking functions. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MyAlloc.h" + +#if USE_MYALLOC +// +// Get back to original alloc/free calls. +// +#undef malloc +#undef calloc +#undef realloc +#undef free +// +// Start of allocation list. +// +STATIC MY_ALLOC_STRUCT *MyAllocData = NULL; + +// +// +// +STATIC UINT32 MyAllocHeadMagik = MYALLOC_HEAD_MAGIK; +STATIC UINT32 MyAllocTailMagik = MYALLOC_TAIL_MAGIK; + +/** + Check for corruptions in the allocated memory chain. If a corruption + is detection program operation stops w/ an exit(1) call. + + @param Final When FALSE, MyCheck() returns if the allocated memory chain + has not been corrupted. When TRUE, MyCheck() returns if there + are no un-freed allocations. If there are un-freed allocations, + they are displayed and exit(1) is called. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyCheck ( + BOOLEAN Final, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + + // + // Check parameters. + // + if (File == NULL) { + printf ( + "\nMyCheck(Final=%u, File=NULL, Line=%u)" + "Invalid parameter(s).\n", + Final, + (unsigned)Line + ); + + exit (1); + } + + if (Line == 0) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)" + "Invalid parameter(s).\n", + Final, + File, + (unsigned)Line + ); + + exit (1); + } + + if (strlen ((CHAR8 *)File) == 0) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)" + "Invalid parameter.\n", + Final, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Check structure contents. + // + for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { + if (memcmp(Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik) || + memcmp(&Tmp->Buffer[Tmp->Size + sizeof(UINT32)], &MyAllocTailMagik, sizeof MyAllocTailMagik)) { + break; + } + } + // + // If Tmp is not NULL, the structure is corrupt. + // + if (Tmp != NULL) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)""\nStructure corrupted!" + "\nFile=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", + Final, + File, + (unsigned)Line, + Tmp->File, + (unsigned) Tmp->Line, + (unsigned) Tmp->Size, + (unsigned) *(UINT32 *) (Tmp->Buffer), + (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) + ); + + exit (1); + } + // + // If Final is TRUE, display the state of the structure chain. + // + if (Final) { + if (MyAllocData != NULL) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)" + "\nSome allocated items have not been freed.\n", + Final, + File, + (unsigned)Line + ); + + for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { + printf ( + "File=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", + Tmp->File, + (unsigned) Tmp->Line, + (unsigned) Tmp->Size, + (unsigned) *(UINT32 *) (Tmp->Buffer), + (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) + ); + } + } + } +} + +/** + Allocate a new link in the allocation chain along with enough storage + for the File[] string, requested Size and alignment overhead. If + memory cannot be allocated or the allocation chain has been corrupted, + exit(1) will be called. + + @param Size Number of bytes (UINT8) requested by the called. + Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to the caller's buffer. +**/ +VOID * +MyAlloc ( + UINTN Size, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + UINTN Len; + + // + // Check for invalid parameters. + // + if (File == NULL) { + printf ( + "\nMyAlloc(Size=%u, File=NULL, Line=%u)" + "\nInvalid parameter(s).\n", + (unsigned)Size, + (unsigned)Line + ); + + exit (1); + } + + if (Size == 0 || Line == 0) { + printf ( + "\nMyAlloc(Size=%u, File=%s, Line=%u)" + "\nInvalid parameter(s).\n", + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + + Len = strlen ((CHAR8 *)File); + if (Len == 0) { + printf ( + "\nMyAlloc(Size=%u, File=%s, Line=%u)" + "\nInvalid parameter.\n", + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Check the allocation list for corruption. + // + MyCheck (0, (UINT8 *)__FILE__, __LINE__); + + // + // Allocate a new entry. + // + Tmp = calloc ( + 1, + sizeof (MY_ALLOC_STRUCT) + Len + 1 + sizeof (UINT64) + Size + (sizeof MyAllocHeadMagik) + (sizeof MyAllocTailMagik) + ); + + if (Tmp == NULL) { + printf ( + "\nMyAlloc(Size=%u, File=%s, Line=%u)" + "\nOut of memory.\n", + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Fill in the new entry. + // + Tmp->File = ((UINT8 *) Tmp) + sizeof (MY_ALLOC_STRUCT); + strcpy ((CHAR8 *)Tmp->File, (CHAR8 *)File); + Tmp->Line = Line; + Tmp->Size = Size; + Tmp->Buffer = (UINT8 *) (((UINTN) Tmp + Len + 9) &~7); + + memcpy (Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik); + + memcpy ( + &Tmp->Buffer[Size + sizeof (UINT32)], + &MyAllocTailMagik, + sizeof MyAllocTailMagik + ); + + Tmp->Next = MyAllocData; + Tmp->Cksum = (UINTN) Tmp + (UINTN) (Tmp->Next) + Tmp->Line + Tmp->Size + (UINTN) (Tmp->File) + (UINTN) (Tmp->Buffer); + + MyAllocData = Tmp; + + return Tmp->Buffer + sizeof (UINT32); +} + +/** + This does a MyAlloc(), memcpy() and MyFree(). There is no optimization + for shrinking or expanding buffers. An invalid parameter will cause + MyRealloc() to fail with a call to exit(1). + + @param Ptr Pointer to the caller's buffer to be re-allocated. + @param Size Size of new buffer. Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to new caller's buffer. +**/ +VOID * +MyRealloc ( + VOID *Ptr, + UINTN Size, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + VOID *Buffer; + + // + // Check for invalid parameter(s). + // + if (File == NULL) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=NULL, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + (unsigned)Size, + (unsigned)Line + ); + + exit (1); + } + + if (Size == 0 || Line == 0) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + + if (strlen ((CHAR8 *)File) == 0) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" + "\nInvalid parameter.\n", + Ptr, + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Find existing buffer in allocation list. + // + if (Ptr == NULL) { + Tmp = NULL; + } else if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { + Tmp = MyAllocData; + } else { + for (Tmp = MyAllocData;; Tmp = Tmp->Next) { + if (Tmp->Next == NULL) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" + "\nCould not find buffer.\n", + Ptr, + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + + Tmp = Tmp->Next; + } + } + // + // Allocate new buffer, copy old data, free old buffer. + // + Buffer = MyAlloc (Size, File, Line); + + if (Buffer != NULL && Tmp != NULL) { + memcpy ( + Buffer, + &Tmp->Buffer[sizeof (UINT32)], + ((Size <= Tmp->Size) ? Size : Tmp->Size) + ); + + MyFree (Ptr, (UINT8 *)__FILE__, __LINE__); + } + + return Buffer; +} + +/** + Release a previously allocated buffer. Invalid parameters will cause + MyFree() to fail with an exit(1) call. + + @param Ptr Pointer to the caller's buffer to be freed. + A NULL pointer will be ignored. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyFree ( + VOID *Ptr, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + MY_ALLOC_STRUCT *Tmp2; + + // + // Check for invalid parameter(s). + // + if (File == NULL) { + printf ( + "\nMyFree(Ptr=%p, File=NULL, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + (unsigned)Line + ); + + exit (1); + } + + if (Line == 0) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + + if (strlen ((CHAR8 *)File) == 0) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)" + "\nInvalid parameter.\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Freeing NULL is always valid. + // + if (Ptr == NULL) { + return ; + } + // + // Fail if nothing is allocated. + // + if (MyAllocData == NULL) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)" + "\nCalled before memory allocated.\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Check for corrupted allocation list. + // + MyCheck (0, (UINT8 *)__FILE__, __LINE__); + + // + // Need special check for first item in list. + // + if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { + // + // Unlink first item in list. + // + Tmp = MyAllocData; + MyAllocData = MyAllocData->Next; + } else { + // + // Walk list looking for matching item. + // + for (Tmp = MyAllocData;; Tmp = Tmp->Next) { + // + // Fail if end of list is reached. + // + if (Tmp->Next == NULL) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)\n" + "\nNot found.\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Leave loop when match is found. + // + if (&Tmp->Next->Buffer[sizeof (UINT32)] == Ptr) { + break; + } + } + // + // Unlink item from list. + // + Tmp2 = Tmp->Next; + Tmp->Next = Tmp->Next->Next; + Tmp = Tmp2; + } + // + // Release item. + // + free (Tmp); +} + +#endif /* USE_MYALLOC */ + +/* eof - MyAlloc.c */ diff --git a/tools/src/GenFw/Common/src/MyAlloc.h b/tools/src/GenFw/Common/src/MyAlloc.h new file mode 100644 index 0000000..4ef6995 --- /dev/null +++ b/tools/src/GenFw/Common/src/MyAlloc.h @@ -0,0 +1,163 @@ +/** @file +Header file for memory allocation tracking functions. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _MYALLOC_H_ +#define _MYALLOC_H_ + +#include +#include +#include + +#include + +// +// Default operation is to use the memory allocation tracking functions. +// To over-ride add "#define USE_MYALLOC 0" to your program header and/or +// source files as needed. Or, just do not include this header file in +// your project. +// +#ifndef USE_MYALLOC +#define USE_MYALLOC 1 +#endif + +#if USE_MYALLOC +// +// Replace C library allocation routines with MyAlloc routines. +// +#define malloc(size) MyAlloc ((size), __FILE__, __LINE__) +#define calloc(count, size) MyAlloc ((count) * (size), __FILE__, __LINE__) +#define realloc(ptr, size) MyRealloc ((ptr), (size), __FILE__, __LINE__) +#define free(ptr) MyFree ((ptr), __FILE__, __LINE__) +#define alloc_check(final) MyCheck ((final), __FILE__, __LINE__) + +// +// Structure for checking/tracking memory allocations. +// +typedef struct MyAllocStruct { + UINTN Cksum; + struct MyAllocStruct *Next; + UINTN Line; + UINTN Size; + UINT8 *File; + UINT8 *Buffer; +} MY_ALLOC_STRUCT; +// +// Cksum := (UINTN)This + (UINTN)Next + Line + Size + (UINTN)File + +// (UINTN)Buffer; +// +// Next := Pointer to next allocation structure in the list. +// +// Line := __LINE__ +// +// Size := Size of allocation request. +// +// File := Pointer to __FILE__ string stored immediately following +// MY_ALLOC_STRUCT in memory. +// +// Buffer := Pointer to UINT32 aligned storage immediately following +// the NULL terminated __FILE__ string. This is UINT32 +// aligned because the underflow signature is 32-bits and +// this will place the first caller address on a 64-bit +// boundary. +// +// +// Signatures used to check for buffer overflow/underflow conditions. +// +#define MYALLOC_HEAD_MAGIK 0xBADFACED +#define MYALLOC_TAIL_MAGIK 0xDEADBEEF + +/** + Check for corruptions in the allocated memory chain. If a corruption + is detection program operation stops w/ an exit(1) call. + + @param Final When FALSE, MyCheck() returns if the allocated memory chain + has not been corrupted. When TRUE, MyCheck() returns if there + are no un-freed allocations. If there are un-freed allocations, + they are displayed and exit(1) is called. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyCheck ( + BOOLEAN Final, + UINT8 File[], + UINTN Line + ) +; + +/** + Allocate a new link in the allocation chain along with enough storage + for the File[] string, requested Size and alignment overhead. If + memory cannot be allocated or the allocation chain has been corrupted, + exit(1) will be called. + + @param Size Number of bytes (UINT8) requested by the called. + Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to the caller's buffer. +**/ +VOID * +MyAlloc ( + UINTN Size, + UINT8 File[], + UINTN Line + ) +; + +/** + This does a MyAlloc(), memcpy() and MyFree(). There is no optimization + for shrinking or expanding buffers. An invalid parameter will cause + MyRealloc() to fail with a call to exit(1). + + @param Ptr Pointer to the caller's buffer to be re-allocated. + Ptr cannot be NULL. + @param Size Size of new buffer. Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to new caller's buffer. +**/ +VOID * +MyRealloc ( + VOID *Ptr, + UINTN Size, + UINT8 File[], + UINTN Line + ) +; + +/** + Release a previously allocated buffer. Invalid parameters will cause + MyFree() to fail with an exit(1) call. + + @param Ptr Pointer to the caller's buffer to be freed. + A NULL pointer will be ignored. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyFree ( + VOID *Ptr, + UINT8 File[], + UINTN Line + ) +; + +#else /* USE_MYALLOC */ + +// +// Nothing to do when USE_MYALLOC is zero. +// +#define alloc_check(final) + +#endif /* USE_MYALLOC */ +#endif /* _MYALLOC_H_ */ + +/* eof - MyAlloc.h */ diff --git a/tools/src/GenFw/Common/src/OsPath.c b/tools/src/GenFw/Common/src/OsPath.c new file mode 100644 index 0000000..5dcb0dc --- /dev/null +++ b/tools/src/GenFw/Common/src/OsPath.c @@ -0,0 +1,264 @@ +/** @file +Functions useful to operate file directories by parsing file path. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include "CommonLib.h" +#include "OsPath.h" + +// +// Functions implementations +// + +#if 0 + // + // BUGBUG: Not fully implemented yet. + // + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/c" -> "a/b" + "a/b/c/" -> "a/b" + "a" -> "." + "." -> ".." + "/" -> NULL + + This function does not check for the existence of the file. + + The caller must free the string returned. + + @param FilePath Path name of file to get the parent directory for. + + @return NULL if error +**/ +CHAR8* +OsPathDirName ( + IN CHAR8 *FilePath + ) + +{ + CHAR8 *Return; + CHAR8 *Pos; + CHAR8 Char; + UINTN Length; + INTN Offset; + + Length = strlen (FilePath); + + if (Length == 0) { + return NULL; + } + + // + // Check for the root directory case + // + if ( + (Length == 3 && isalpha (FilePath[0]) && (strcmp(FilePath + 1, ":\\") == 0)) || + (strcmp(FilePath, "/") == 0) + ) { + return NULL; + } + + // + // If the path ends with a path separator, then just append ".." + // + Char = FilePath[Length - 1]; + if (Char == '/' || Char == '\\') { + return OsPathJoin (FilePath, ".."); + } + + // + // + // + for (Offset = Length; Offset > 0; Offset--) { + if ((Return[Offset] == '/') || (Return[Offset] == '\\')) { + Return[Offset] = '\0'; + return Return; + } + } +} +#endif + + +#if 0 + // + // BUGBUG: Not fully implemented yet. + // + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/../c" -> "a/c" + "a/b//c" -> "a/b/c" + "a/./b" -> "a/b" + + This function does not check for the existence of the file. + + @param Path Path name of file to normalize + + @return The string is altered in place. +**/ +VOID +OsPathNormPathInPlace ( + IN CHAR8 *Path + ) +{ + CHAR8 *Pos; + INTN Offset; + BOOLEAN TryAgain; + UINTN Length; + UINTN Remaining; + UINTN SubLength; + + do { + TryAgain = FALSE; + Length = strlen (Path); + + for (Offset = 0; Offset < Length; Offset++) { + Remaining = Length - Offset; + + // + // Collapse '//' -> '/' + // + if ( + (Remaining >= 2) && + ((Offset > 0) || (Path[0] != '\\')) && + IsDirSep (Path[Offset]) && IsDirSep (Path[Offset + 1]) + ) { + memmove (&Path[Offset], &Path[Offset + 1], Remaining); + TryAgain = TRUE; + break; + } + + // + // Collapse '/./' -> '/' + // + if ((Remaining >= 3) && IsDirSep (Path[Offset]) && + (Path[Offset + 1] == '.') && IsDirSep (Path[Offset + 2]) + ) { + memmove (&Path[Offset], &Path[Offset + 1], Remaining); + TryAgain = TRUE; + break; + } + + // + // Collapse 'a/../b' -> 'b' + // + // BUGBUG: Not implemented yet + + } + + } while (TryAgain); + + Return = CloneString (FilePath); + if (Return == NULL) { + return NULL; + } + + Length = strlen (Return); + + // + // Check for the root directory case + // + if ( + (Length == 3 && isalpha (Return[0]) && (strcmp(Return + 1, ":\\") == 0)) || + (strcmp(Return, "/") == 0) + ) { + free (Return); + return NULL; + } + + // + // + // + for (Offset = Length; Offset > 0; Offset--) { + if ((Return[Offset] == '/') || (Return[Offset] == '\\')) { + Return[Offset] = '\0'; + return Return; + } + } +} +#endif + +/** + This function replaces the final portion of a path with an alternative + 'peer' filename. For example: + "a/b/../c", "peer" -> "a/b/../peer" + "a/b/", "peer" -> "a/b/peer" + "/a", "peer" -> "/peer" + "a", "peer" -> "peer" + + This function does not check for the existence of the file. + + @param OldPath Path name of replace the final segment + @param Peer The new path name to concatenate to become the peer path + + @return A CHAR8* string, which must be freed by the caller +**/ +CHAR8* +OsPathPeerFilePath ( + IN CHAR8 *OldPath, + IN CHAR8 *Peer + ) +{ + CHAR8 *Result; + INTN Offset; + + Result = (CHAR8 *) malloc (strlen (OldPath) + strlen (Peer) + 1); + if (Result == NULL) { + return NULL; + } + + strcpy (Result, OldPath); + + // + // Search for the last '/' or '\' in the string. If found, replace + // everything following it with Peer + // + for (Offset = strlen (Result); Offset >= 0; Offset--) { + if ((Result[Offset] == '/') || (Result[Offset] == '\\')) { + Result[Offset + 1] = '\0'; + strcat (Result, Peer); + return Result; + } + } + + // + // Neither a '/' nor a '\' was found. Therefore, we simply return Peer. + // + strcpy (Result, Peer); + return Result; +} + +/** + Checks if a file exists + + @param InputFileName The name of the file to check for existence + + @retval TRUE The file exists + @retval FALSE The file does not exist +**/ +BOOLEAN +OsPathExists ( + IN CHAR8 *InputFileName + ) +{ + FILE *InputFile; + InputFile = fopen (LongFilePath (InputFileName), "rb"); + if (InputFile == NULL) { + return FALSE; + } else { + fclose (InputFile); + return TRUE; + } +} + + + diff --git a/tools/src/GenFw/Common/src/OsPath.h b/tools/src/GenFw/Common/src/OsPath.h new file mode 100644 index 0000000..7b17b6f --- /dev/null +++ b/tools/src/GenFw/Common/src/OsPath.h @@ -0,0 +1,97 @@ +/** @file +Header file for helper functions useful to operate file directories by parsing +file path. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_OS_PATH_H +#define _EFI_OS_PATH_H + +#include + +// +// Functions declarations +// + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/c" -> "a/b" + "a/b/c/" -> "a/b" + "a" -> "." + "." -> ".." + "/" -> NULL + + This function does not check for the existence of the file. + + The caller must free the string returned. + + @param FilePath Path name of file to get the parent directory for. + + @return NULL if error +**/ +CHAR8* +OsPathDirName ( + IN CHAR8 *FilePath + ) +; + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/../c" -> "a/c" + "a/b//c" -> "a/b/c" + "a/./b" -> "a/b" + + This function does not check for the existence of the file. + + @param Path Path name of file to normalize + + @return The string is altered in place. +**/ +VOID +OsPathNormPathInPlace ( + IN CHAR8 *Path + ) +; + +/** + This function replaces the final portion of a path with an alternative + 'peer' filename. For example: + "a/b/../c", "peer" -> "a/b/../peer" + "a/b/", "peer" -> "a/b/peer" + "/a", "peer" -> "/peer" + "a", "peer" -> "peer" + + This function does not check for the existence of the file. + + @param OldPath Path name of replace the final segment + @param Peer The new path name to concatenate to become the peer path + + @return A CHAR8* string, which must be freed by the caller +**/ +CHAR8* +OsPathPeerFilePath ( + IN CHAR8 *OldPath, + IN CHAR8 *Peer + ) +; + +/** + Checks if a file exists + + @param InputFileName The name of the file to check for existence + + @retval TRUE The file exists + @retval FALSE The file does not exist +**/ +BOOLEAN +OsPathExists ( + IN CHAR8 *InputFileName + ) +; + +#endif diff --git a/tools/src/GenFw/Common/src/ParseGuidedSectionTools.c b/tools/src/GenFw/Common/src/ParseGuidedSectionTools.c new file mode 100644 index 0000000..f274bc4 --- /dev/null +++ b/tools/src/GenFw/Common/src/ParseGuidedSectionTools.c @@ -0,0 +1,179 @@ +/** @file +Helper functions for parsing GuidedSectionTools.txt + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include "MemoryFile.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "ParseInf.h" +#include "ParseGuidedSectionTools.h" +#include "StringFuncs.h" + + +// +// Local types / structures +// + +typedef struct _GUID_SEC_TOOL_ENTRY { + EFI_GUID Guid; + CHAR8* Name; + CHAR8* Path; + struct _GUID_SEC_TOOL_ENTRY *Next; +} GUID_SEC_TOOL_ENTRY; + +// +// Function Implementation +// + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedGuidedSectionToolsHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Path name of file to read + + @retval NULL if error parsing + @retval A non-NULL EFI_HANDLE otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsFile ( + IN CHAR8 *InputFile + ) +{ + EFI_STATUS Status; + EFI_HANDLE MemoryFile; + EFI_HANDLE ParsedGuidedSectionTools; + + Status = GetMemoryFile (InputFile, &MemoryFile); + if (EFI_ERROR (Status)) { + return NULL; + } + + ParsedGuidedSectionTools = ParseGuidedSectionToolsMemoryFile (MemoryFile); + + FreeMemoryFile (MemoryFile); + + return ParsedGuidedSectionTools; +} + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedGuidedSectionToolsHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Memory file image. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsMemoryFile ( + IN EFI_HANDLE InputFile + ) +{ + EFI_STATUS Status; + CHAR8 *NextLine; + STRING_LIST *Tool; + EFI_GUID Guid; + GUID_SEC_TOOL_ENTRY *FirstGuidTool; + GUID_SEC_TOOL_ENTRY *LastGuidTool; + GUID_SEC_TOOL_ENTRY *NewGuidTool; + + FirstGuidTool = NULL; + LastGuidTool = NULL; + + while (TRUE) { + NextLine = ReadMemoryFileLine (InputFile); + if (NextLine == NULL) { + break; + } + + Status = StripInfDscStringInPlace (NextLine); + if (EFI_ERROR (Status)) { + free (NextLine); + break; + } + + if (NextLine[0] == '\0') { + free (NextLine); + continue; + } + + Tool = SplitStringByWhitespace (NextLine); + if ((Tool != NULL) && + (Tool->Count == 3) + ) { + Status = StringToGuid (Tool->Strings[0], &Guid); + if (!EFI_ERROR (Status)) { + NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY)); + if (NewGuidTool != NULL) { + memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid)); + NewGuidTool->Name = CloneString(Tool->Strings[1]); + NewGuidTool->Path = CloneString(Tool->Strings[2]); + NewGuidTool->Next = NULL; + + if (FirstGuidTool == NULL) { + FirstGuidTool = NewGuidTool; + } else { + LastGuidTool->Next = NewGuidTool; + } + LastGuidTool = NewGuidTool; + } + } + } + + if (Tool != NULL) { + FreeStringList (Tool); + } + free (NextLine); + } + + return FirstGuidTool; +} + +/** + This function looks up the appropriate tool to use for extracting + a GUID defined FV section. + + @param ParsedGuidedSectionToolsHandle A parsed GUID section tools handle. + @param SectionGuid The GUID for the section. + + @retval NULL if no tool is found or there is another error + @retval Non-NULL The tool to use to access the section contents. (The caller + must free the memory associated with this string.) +**/ +CHAR8* +LookupGuidedSectionToolPath ( + IN EFI_HANDLE ParsedGuidedSectionToolsHandle, + IN EFI_GUID *SectionGuid + ) +{ + GUID_SEC_TOOL_ENTRY *GuidTool; + + GuidTool = (GUID_SEC_TOOL_ENTRY*)ParsedGuidedSectionToolsHandle; + if (GuidTool == NULL) { + return NULL; + } + + for ( ; GuidTool != NULL; GuidTool = GuidTool->Next) { + if (CompareGuid (&(GuidTool->Guid), SectionGuid) == 0) { + return CloneString (GuidTool->Path); + } + } + + return NULL; +} + + diff --git a/tools/src/GenFw/Common/src/ParseGuidedSectionTools.h b/tools/src/GenFw/Common/src/ParseGuidedSectionTools.h new file mode 100644 index 0000000..5c96ea6 --- /dev/null +++ b/tools/src/GenFw/Common/src/ParseGuidedSectionTools.h @@ -0,0 +1,87 @@ +/** @file +Header file for helper functions for parsing GuidedSectionTools.txt + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PARSE_GUIDED_SECTION_TOOLS_H +#define _EFI_PARSE_GUIDED_SECTION_TOOLS_H + +#include + +// +// Functions declarations +// + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedToolsDefHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Path name of file to read + + @retval NULL if error parsing + @retval A non-NULL EFI_HANDLE otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsFile ( + IN CHAR8 *InputFile + ) +; + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedToolsDefHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Memory file image. + + @retval NULL if error parsing + @retval A non-NULL EFI_HANDLE otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsMemoryFile ( + IN EFI_HANDLE InputFile + ) +; + +/** + This function looks up the appropriate tool to use for extracting + a GUID defined FV section. + + @param ParsedGuidedSectionToolsHandle A parsed GUID section tools handle. + @param SectionGuid The GUID for the section. + + @retval NULL if no tool is found or there is another error + @retval Non-NULL The tool to use to access the section contents. (The caller + must free the memory associated with this string.) +**/ +CHAR8* +LookupGuidedSectionToolPath ( + IN EFI_HANDLE ParsedGuidedSectionToolsHandle, + IN EFI_GUID *SectionGuid + ) +; + +/** + Frees resources that were allocated by ParseGuidedSectionToolsFile. + After freeing these resources, the information that was parsed + is no longer accessible. + + @param ParsedToolDefHandle Handle returned from ParseGuidedSectionToolsFile + + @return EFI_STATUS +**/ +EFI_STATUS +FreeParsedGuidedSectionToolsHandle ( + IN EFI_HANDLE ParsedGuidedSectionToolsHandle + ) +; + +#endif diff --git a/tools/src/GenFw/Common/src/ParseInf.c b/tools/src/GenFw/Common/src/ParseInf.c new file mode 100644 index 0000000..ca3c414 --- /dev/null +++ b/tools/src/GenFw/Common/src/ParseInf.c @@ -0,0 +1,640 @@ +/** @file +This contains some useful functions for parsing INF files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include "EfiUtilityMsgs.h" +#include "ParseInf.h" +#include "CommonLib.h" + +/** + This function reads a line, stripping any comments. + The function reads a string from the input stream argument and stores it in + the input string. ReadLine reads characters from the current file position + to and including the first newline character, to the end of the stream, or + until the number of characters read is equal to MaxLength - 1, whichever + comes first. The newline character, if read, is replaced with a \0. + + @param InputFile Memory file image. + @param InputBuffer Buffer to read into, must be MaxLength size. + @param MaxLength The maximum size of the input buffer. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLine ( + IN MEMORY_FILE *InputFile, + IN OUT CHAR8 *InputBuffer, + IN UINTN MaxLength + ) + +{ + CHAR8 *CharPtr; + CHAR8 *EndOfLine; + UINTN CharsToCopy; + + // + // Verify input parameters are not null + // + assert (InputBuffer); + assert (InputFile->FileImage); + assert (InputFile->Eof); + assert (InputFile->CurrentFilePointer); + + // + // Check for end of file condition + // + if (InputFile->CurrentFilePointer >= InputFile->Eof) { + return NULL; + } + // + // Find the next newline char + // + EndOfLine = strchr (InputFile->CurrentFilePointer, '\n'); + + // + // Determine the number of characters to copy. + // + if (EndOfLine == 0) { + // + // If no newline found, copy to the end of the file. + // + CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; + } else if (EndOfLine >= InputFile->Eof) { + // + // If the newline found was beyond the end of file, copy to the eof. + // + CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; + } else { + // + // Newline found in the file. + // + CharsToCopy = EndOfLine - InputFile->CurrentFilePointer; + } + // + // If the end of line is too big for the current buffer, set it to the max + // size of the buffer (leaving room for the \0. + // + if (CharsToCopy > MaxLength - 1) { + CharsToCopy = MaxLength - 1; + } + // + // Copy the line. + // + memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy); + + // + // Add the null termination over the 0x0D + // + if (InputBuffer[CharsToCopy - 1] == '\r') { + + InputBuffer[CharsToCopy - 1] = '\0'; + + } else { + + InputBuffer[CharsToCopy] = '\0'; + + } + + // + // Increment the current file pointer (include the 0x0A) + // + InputFile->CurrentFilePointer += CharsToCopy + 1; + + // + // Strip any comments + // + CharPtr = strstr (InputBuffer, "//"); + if (CharPtr != 0) { + CharPtr[0] = 0; + } + // + // Return the string + // + return InputBuffer; +} + +/** + This function parses a file from the beginning to find a section. + The section string may be anywhere within a line. + + @param InputFile Memory file image. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSection ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section + ) +{ + CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; + CHAR8 *CurrentToken; + + // + // Verify input is not NULL + // + assert (InputFile->FileImage); + assert (InputFile->Eof); + assert (InputFile->CurrentFilePointer); + assert (Section); + + // + // Rewind to beginning of file + // + InputFile->CurrentFilePointer = InputFile->FileImage; + + // + // Read lines until the section is found + // + while (InputFile->CurrentFilePointer < InputFile->Eof) { + // + // Read a line + // + ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH); + + // + // Check if the section is found + // + CurrentToken = strstr (InputBuffer, Section); + if (CurrentToken != NULL) { + return TRUE; + } + } + + return FALSE; +} + +/** + Finds a token value given the section and token to search for. + + @param InputFile Memory file image. + @param Section The section to search for, a string within []. + @param Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file. + @param Instance The instance of the token to search for. Zero is the first instance. + @param Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size. + + @retval EFI_SUCCESS Value found. + @retval EFI_ABORTED Format error detected in INF file. + @retval EFI_INVALID_PARAMETER Input argument was null. + @retval EFI_LOAD_ERROR Error reading from the file. + @retval EFI_NOT_FOUND Section/Token/Value not found. +**/ +EFI_STATUS +FindToken ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section, + IN CHAR8 *Token, + IN UINTN Instance, + OUT CHAR8 *Value + ) +{ + CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; + CHAR8 *CurrentToken; + CHAR8 *Delimiter; + BOOLEAN ParseError; + BOOLEAN ReadError; + UINTN Occurrence; + + // + // Check input parameters + // + if (InputFile->FileImage == NULL || + InputFile->Eof == NULL || + InputFile->CurrentFilePointer == NULL || + Section == NULL || + strlen (Section) == 0 || + Token == NULL || + strlen (Token) == 0 || + Value == NULL + ) { + return EFI_INVALID_PARAMETER; + } + // + // Initialize error codes + // + ParseError = FALSE; + ReadError = FALSE; + + // + // Initialize our instance counter for the search token + // + Occurrence = 0; + + if (FindSection (InputFile, Section)) { + // + // Found the desired section, find and read the desired token + // + do { + // + // Read a line from the file + // + if (ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH) == NULL) { + // + // Error reading from input file + // + ReadError = TRUE; + break; + } + // + // Get the first non-whitespace string + // + Delimiter = strchr (InputBuffer, '='); + if (Delimiter != NULL) { + *Delimiter = 0; + } + + CurrentToken = strtok (InputBuffer, " \t\n"); + if (CurrentToken == NULL || Delimiter == NULL) { + // + // Whitespace line found (or comment) so continue + // + CurrentToken = InputBuffer; + continue; + } + // + // Make sure we have not reached the end of the current section + // + if (CurrentToken[0] == '[') { + break; + } + // + // Compare the current token with the desired token + // + if (strcmp (CurrentToken, Token) == 0) { + // + // Found it + // + // + // Check if it is the correct instance + // + if (Instance == Occurrence) { + // + // Copy the contents following the = + // + CurrentToken = Delimiter + 1; + if (*CurrentToken == 0) { + // + // Nothing found, parsing error + // + ParseError = TRUE; + } else { + // + // Strip leading white space + // + while (*CurrentToken == ' ' || *CurrentToken == '\t') { + CurrentToken++; + } + // + // Copy the current token to the output value + // + strcpy (Value, CurrentToken); + // + // Strip trailing white space + // + while (strlen(Value) > 0 && (*(Value + strlen(Value) - 1) == ' ' || *(Value + strlen(Value) - 1) == '\t')) { + *(Value + strlen(Value) - 1) = 0; + } + return EFI_SUCCESS; + } + } else { + // + // Increment the occurrence found + // + Occurrence++; + } + } + } while ( + !ParseError && + !ReadError && + InputFile->CurrentFilePointer < InputFile->Eof && + CurrentToken[0] != '[' && + Occurrence <= Instance + ); + } + // + // Distinguish between read errors and INF file format errors. + // + if (ReadError) { + return EFI_LOAD_ERROR; + } + + if (ParseError) { + return EFI_ABORTED; + } + + return EFI_NOT_FOUND; +} + +/** + Converts a string to an EFI_GUID. The string must be in the + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format. + + @param AsciiGuidBuffer pointer to ascii string + @param GuidBuffer pointer to destination Guid + + @retval EFI_ABORTED Could not convert the string + @retval EFI_SUCCESS The string was successfully converted + @retval EFI_INVALID_PARAMETER Input parameter is invalid. +**/ +EFI_STATUS +StringToGuid ( + IN CHAR8 *AsciiGuidBuffer, + OUT EFI_GUID *GuidBuffer + ) +{ + INT32 Index; + int Data1; + int Data2; + int Data3; + int Data4[8]; + + if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // + for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) { + if (Index == 8 || Index == 13 || Index == 18 || Index == 23) { + if (AsciiGuidBuffer[Index] != '-') { + break; + } + } else { + if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) || + ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) || + ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) { + continue; + } else { + break; + } + } + } + + if (Index < 36 || AsciiGuidBuffer[36] != '\0') { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer); + return EFI_ABORTED; + } + + // + // Scan the guid string into the buffer + // + Index = sscanf ( + AsciiGuidBuffer, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &Data1, + &Data2, + &Data3, + &Data4[0], + &Data4[1], + &Data4[2], + &Data4[3], + &Data4[4], + &Data4[5], + &Data4[6], + &Data4[7] + ); + + // + // Verify the correct number of items were scanned. + // + if (Index != 11) { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer); + return EFI_ABORTED; + } + // + // Copy the data into our GUID. + // + GuidBuffer->Data1 = (UINT32) Data1; + GuidBuffer->Data2 = (UINT16) Data2; + GuidBuffer->Data3 = (UINT16) Data3; + GuidBuffer->Data4[0] = (UINT8) Data4[0]; + GuidBuffer->Data4[1] = (UINT8) Data4[1]; + GuidBuffer->Data4[2] = (UINT8) Data4[2]; + GuidBuffer->Data4[3] = (UINT8) Data4[3]; + GuidBuffer->Data4[4] = (UINT8) Data4[4]; + GuidBuffer->Data4[5] = (UINT8) Data4[5]; + GuidBuffer->Data4[6] = (UINT8) Data4[6]; + GuidBuffer->Data4[7] = (UINT8) Data4[7]; + + return EFI_SUCCESS; +} + +/** + Converts a null terminated ascii string that represents a number into a + UINT64 value. A hex number may be preceded by a 0x, but may not be + succeeded by an h. A number without 0x or 0X is considered to be base 10 + unless the IsHex input is true. + + @param AsciiString The string to convert. + @param IsHex Force the string to be treated as a hex number. + @param ReturnValue The return value. + + @retval EFI_SUCCESS Number successfully converted. + @retval EFI_ABORTED Invalid character encountered. +**/ +EFI_STATUS +AsciiStringToUint64 ( + IN CONST CHAR8 *AsciiString, + IN BOOLEAN IsHex, + OUT UINT64 *ReturnValue + ) +{ + UINT8 Index; + UINT64 Value; + CHAR8 CurrentChar; + + // + // Initialize the result + // + Value = 0; + Index = 0; + + // + // Check input parameter + // + if (AsciiString == NULL || ReturnValue == NULL || strlen(AsciiString) > 0xFF) { + return EFI_INVALID_PARAMETER; + } + while (AsciiString[Index] == ' ') { + Index ++; + } + + // + // Add each character to the result + // + + // + // Skip first two chars only if the string starts with '0x' or '0X' + // + if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) { + IsHex = TRUE; + Index += 2; + } + if (IsHex) { + // + // Convert the hex string. + // + for (; AsciiString[Index] != '\0'; Index++) { + CurrentChar = AsciiString[Index]; + if (CurrentChar == ' ') { + break; + } + // + // Verify Hex string + // + if (isxdigit ((int)CurrentChar) == 0) { + return EFI_ABORTED; + } + // + // Add hex value + // + Value *= 16; + if (CurrentChar >= '0' && CurrentChar <= '9') { + Value += CurrentChar - '0'; + } else if (CurrentChar >= 'a' && CurrentChar <= 'f') { + Value += CurrentChar - 'a' + 10; + } else if (CurrentChar >= 'A' && CurrentChar <= 'F') { + Value += CurrentChar - 'A' + 10; + } + } + + *ReturnValue = Value; + } else { + // + // Convert dec string is a number + // + for (; Index < strlen (AsciiString); Index++) { + CurrentChar = AsciiString[Index]; + if (CurrentChar == ' ') { + break; + } + // + // Verify Dec string + // + if (isdigit ((int)CurrentChar) == 0) { + return EFI_ABORTED; + } + // + // Add dec value + // + Value = Value * 10; + Value += CurrentChar - '0'; + } + + *ReturnValue = Value; + } + + return EFI_SUCCESS; +} + +/** + This function reads a line, stripping any comments. + // BUGBUG: This is obsolete once genmake goes away... + + @param InputFile Stream pointer. + @param InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLineInStream ( + IN FILE *InputFile, + IN OUT CHAR8 *InputBuffer + ) +{ + CHAR8 *CharPtr; + + // + // Verify input parameters are not null + // + assert (InputFile); + assert (InputBuffer); + + // + // Read a line + // + if (fgets (InputBuffer, MAX_LONG_FILE_PATH, InputFile) == NULL) { + return NULL; + } + // + // Strip any comments + // + CharPtr = strstr (InputBuffer, "//"); + if (CharPtr != 0) { + CharPtr[0] = 0; + } + + CharPtr = strstr (InputBuffer, "#"); + if (CharPtr != 0) { + CharPtr[0] = 0; + } + // + // Return the string + // + return InputBuffer; +} + +/** + This function parses a stream file from the beginning to find a section. + The section string may be anywhere within a line. + // BUGBUG: This is obsolete once genmake goes away... + + @param InputFile Stream pointer. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSectionInStream ( + IN FILE *InputFile, + IN CHAR8 *Section + ) +{ + CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; + CHAR8 *CurrentToken; + + // + // Verify input is not NULL + // + assert (InputFile); + assert (Section); + + // + // Rewind to beginning of file + // + if (fseek (InputFile, 0, SEEK_SET) != 0) { + return FALSE; + } + // + // Read lines until the section is found + // + while (feof (InputFile) == 0) { + // + // Read a line + // + ReadLineInStream (InputFile, InputBuffer); + + // + // Check if the section is found + // + CurrentToken = strstr (InputBuffer, Section); + if (CurrentToken != NULL) { + return TRUE; + } + } + + return FALSE; +} diff --git a/tools/src/GenFw/Common/src/ParseInf.h b/tools/src/GenFw/Common/src/ParseInf.h new file mode 100644 index 0000000..3778fe9 --- /dev/null +++ b/tools/src/GenFw/Common/src/ParseInf.h @@ -0,0 +1,164 @@ +/** @file +Header file for helper functions useful for parsing INF files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PARSE_INF_H +#define _EFI_PARSE_INF_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +// +// Functions declarations +// + +/** + This function reads a line, stripping any comments. + The function reads a string from the input stream argument and stores it in + the input string. ReadLine reads characters from the current file position + to and including the first newline character, to the end of the stream, or + until the number of characters read is equal to MaxLength - 1, whichever + comes first. The newline character, if read, is replaced with a \0. + + @param InputFile Memory file image. + @param InputBuffer Buffer to read into, must be MaxLength size. + @param MaxLength The maximum size of the input buffer. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLine ( + IN MEMORY_FILE *InputFile, + IN OUT CHAR8 *InputBuffer, + IN UINTN MaxLength + ) +; + +/** + This function parses a file from the beginning to find a section. + The section string may be anywhere within a line. + + @param InputFile Memory file image. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSection ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section + ) +; + +/** + Finds a token value given the section and token to search for. + + @param InputFile Memory file image. + @param Section The section to search for, a string within []. + @param Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file. + @param Instance The instance of the token to search for. Zero is the first instance. + @param Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size. + + @retval EFI_SUCCESS Value found. + @retval EFI_ABORTED Format error detected in INF file. + @retval EFI_INVALID_PARAMETER Input argument was null. + @retval EFI_LOAD_ERROR Error reading from the file. + @retval EFI_NOT_FOUND Section/Token/Value not found. +**/ +EFI_STATUS +FindToken ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section, + IN CHAR8 *Token, + IN UINTN Instance, + OUT CHAR8 *Value + ) +; + +/** + Converts a string to an EFI_GUID. The string must be in the + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format. + + @param GuidBuffer pointer to destination Guid + @param AsciiGuidBuffer pointer to ascii string + + @retval EFI_ABORTED Could not convert the string + @retval EFI_SUCCESS The string was successfully converted +**/ +EFI_STATUS +StringToGuid ( + IN CHAR8 *AsciiGuidBuffer, + OUT EFI_GUID *GuidBuffer + ) +; + +/** + Converts a null terminated ascii string that represents a number into a + UINT64 value. A hex number may be preceded by a 0x, but may not be + succeeded by an h. A number without 0x or 0X is considered to be base 10 + unless the IsHex input is true. + + @param AsciiString The string to convert. + @param IsHex Force the string to be treated as a hex number. + @param ReturnValue The return value. + + @retval EFI_SUCCESS Number successfully converted. + @retval EFI_ABORTED Invalid character encountered. +**/ +EFI_STATUS +AsciiStringToUint64 ( + IN CONST CHAR8 *AsciiString, + IN BOOLEAN IsHex, + OUT UINT64 *ReturnValue + ) +; + +/** + This function reads a line, stripping any comments. + + @param InputFile Stream pointer. + @param InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLineInStream ( + IN FILE *InputFile, + IN OUT CHAR8 *InputBuffer + ) +; + +/** + This function parses a stream file from the beginning to find a section. + The section string may be anywhere within a line. + + @param InputFile Stream pointer. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSectionInStream ( + IN FILE *InputFile, + IN CHAR8 *Section + ) +; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/src/GenFw/Common/src/PcdValueCommon.c b/tools/src/GenFw/Common/src/PcdValueCommon.c new file mode 100644 index 0000000..8f4bcee --- /dev/null +++ b/tools/src/GenFw/Common/src/PcdValueCommon.c @@ -0,0 +1,678 @@ +/** @file +This file contains the PcdValue structure definition. + +Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include "CommonLib.h" +#include "PcdValueCommon.h" + +typedef enum { + PcdDataTypeBoolean, + PcdDataTypeUint8, + PcdDataTypeUint16, + PcdDataTypeUint32, + PcdDataTypeUint64, + PcdDataTypePointer +} PCD_DATA_TYPE; + +typedef struct { + CHAR8 *SkuName; + CHAR8 *DefaultValueName; + CHAR8 *TokenSpaceGuidName; + CHAR8 *TokenName; + CHAR8 *DataType; + CHAR8 *Value; + PCD_DATA_TYPE PcdDataType; +} PCD_ENTRY; + +PCD_ENTRY *PcdList; +UINT32 PcdListLength; + +/** + Record new token information + + @param FileBuffer File Buffer to be record + @param PcdIndex Index of PCD in database + @param TokenIndex Index of Token + @param TokenStart Start of Token + @param TokenEnd End of Token +**/ +VOID +STATIC +RecordToken ( + UINT8 *FileBuffer, + UINT32 PcdIndex, + UINT32 TokenIndex, + UINT32 TokenStart, + UINT32 TokenEnd + ) + +{ + CHAR8 *Token; + + Token = malloc (TokenEnd - TokenStart + 1); + if (Token == NULL) { + return; + } + memcpy (Token, &FileBuffer[TokenStart], TokenEnd - TokenStart); + Token[TokenEnd - TokenStart] = 0; + switch (TokenIndex) { + case 0: + PcdList[PcdIndex].SkuName = Token; + break; + case 1: + PcdList[PcdIndex].DefaultValueName = Token; + break; + case 2: + PcdList[PcdIndex].TokenSpaceGuidName = Token; + break; + case 3: + PcdList[PcdIndex].TokenName = Token; + break; + case 4: + PcdList[PcdIndex].DataType = Token; + if (strcmp (Token, "BOOLEAN") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeBoolean; + } else if (strcmp (Token, "UINT8") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint8; + } else if (strcmp (Token, "UINT16") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint16; + } else if (strcmp (Token, "UINT32") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint32; + } else if (strcmp (Token, "UINT64") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint64; + } else { + PcdList[PcdIndex].PcdDataType = PcdDataTypePointer; + } + break; + case 5: + PcdList[PcdIndex].Value = Token; + break; + default: + free (Token); + break; + } +} + +/** + Get PCD index in Pcd database + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + + @return Index of PCD in Pcd database +**/ +int +STATIC +LookupPcdIndex ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName + ) +{ + UINT32 Index; + + if (SkuName == NULL) { + SkuName = "DEFAULT"; + } + if (DefaultValueName == NULL) { + DefaultValueName = "DEFAULT"; + } + for (Index = 0; Index < PcdListLength; Index++) { + if (strcmp(PcdList[Index].TokenSpaceGuidName, TokenSpaceGuidName) != 0) { + continue; + } + if (strcmp(PcdList[Index].TokenName, TokenName) != 0) { + continue; + } + if (strcmp(PcdList[Index].SkuName, SkuName) != 0) { + continue; + } + if (strcmp(PcdList[Index].DefaultValueName, DefaultValueName) != 0) { + continue; + } + return Index; + } + return -1; +} + +/** + Get PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + + @return PCD value +**/ +UINT64 +__PcdGet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName + ) +{ + int Index; + CHAR8 *End; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + case PcdDataTypeUint8: + case PcdDataTypeUint16: + case PcdDataTypeUint32: + return (UINT64)strtoul(PcdList[Index].Value, &End, 16); + break; + case PcdDataTypeUint64: + return (UINT64)strtoul(PcdList[Index].Value, &End, 16); + break; + case PcdDataTypePointer: + fprintf (stderr, "PCD %s.%s.%s.%s is structure. Use PcdGetPtr()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + } + return 0; +} + +/** + Set PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Value PCD value to be set +**/ +VOID +__PcdSet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT64 Value + ) +{ + int Index; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + free(PcdList[Index].Value); + PcdList[Index].Value = malloc(20); + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + if (Value == 0) { + strcpy (PcdList[Index].Value, "0x00"); + } else { + strcpy (PcdList[Index].Value, "0x01"); + } + break; + case PcdDataTypeUint8: + sprintf(PcdList[Index].Value, "0x%02x", (UINT8)(Value & 0xff)); + break; + case PcdDataTypeUint16: + sprintf(PcdList[Index].Value, "0x%04x", (UINT16)(Value & 0xffff)); + break; + case PcdDataTypeUint32: + sprintf(PcdList[Index].Value, "0x%08x", (UINT32)(Value & 0xffffffff)); + break; + case PcdDataTypeUint64: + sprintf(PcdList[Index].Value, "0x%016llx", (unsigned long long)Value); + break; + case PcdDataTypePointer: + fprintf (stderr, "PCD %s.%s.%s.%s is structure. Use PcdSetPtr()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + } +} + +/** + Get PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value buffer + + @return PCD value buffer +**/ +VOID * +__PcdGetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 *Size + ) +{ + int Index; + CHAR8 *Value; + UINT8 *Buffer; + CHAR8 *End; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + case PcdDataTypeUint8: + case PcdDataTypeUint16: + case PcdDataTypeUint32: + case PcdDataTypeUint64: + fprintf (stderr, "PCD %s.%s.%s.%s is a value. Use PcdGet()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + case PcdDataTypePointer: + Value = &PcdList[Index].Value[1]; + for (*Size = 0, strtoul(Value, &End, 16); Value != End; strtoul(Value, &End, 16), *Size = *Size + 1) { + Value = End + 1; + } + Buffer = malloc(*Size + 1); + if (Buffer == NULL) { + *Size = 0; + return NULL; + } + Value = &PcdList[Index].Value[1]; + for (*Size = 0, Buffer[*Size] = (UINT8) strtoul(Value, &End, 16); Value != End; *Size = *Size + 1, Buffer[*Size] = (UINT8) strtoul(Value, &End, 16)) { + Value = End + 1; + } + return Buffer; + } + *Size = 0; + return 0; +} + +/** + Set PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value + @param Value Pointer to the updated PCD value buffer +**/ +VOID +__PcdSetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 Size, + UINT8 *Value + ) +{ + int Index; + UINT32 ValueIndex; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + case PcdDataTypeUint8: + case PcdDataTypeUint16: + case PcdDataTypeUint32: + case PcdDataTypeUint64: + fprintf (stderr, "PCD %s.%s.%s.%s is a value. Use PcdGet()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + case PcdDataTypePointer: + free(PcdList[Index].Value); + PcdList[Index].Value = malloc(Size * 5 + 3); + PcdList[Index].Value[0] = '{'; + for (ValueIndex = 0; ValueIndex < Size; ValueIndex++) { + sprintf(&PcdList[Index].Value[1 + ValueIndex * 5], "0x%02x,", Value[ValueIndex]); + } + PcdList[Index].Value[1 + Size * 5 - 1] = '}'; + PcdList[Index].Value[1 + Size * 5 ] = 0; + break; + } +} + +/** + Read the file buffer from the input file. + + @param InputFileName Point to the input file name. + @param FileBuffer Point to the input file buffer. + @param FileSize Size of the file buffer. +**/ +VOID +STATIC +ReadInputFile ( + CHAR8 *InputFileName, + UINT8 **FileBuffer, + UINT32 *FileSize + ) +{ + FILE *InputFile; + UINT32 BytesRead; + + // + // Open Input file and read file data. + // + InputFile = fopen (InputFileName, "rb"); + if (InputFile == NULL) { + fprintf (stderr, "Error opening file %s\n", InputFileName); + exit (EXIT_FAILURE); + } + + // + // Go to the end so that we can determine the file size + // + if (fseek (InputFile, 0, SEEK_END)) { + fprintf (stderr, "Error reading input file %s\n", InputFileName); + fclose (InputFile); + exit (EXIT_FAILURE); + } + + // + // Get the file size + // + *FileSize = ftell (InputFile); + if (*FileSize == -1) { + fprintf (stderr, "Error parsing the input file %s\n", InputFileName); + fclose (InputFile); + exit (EXIT_FAILURE); + } + + // + // Allocate a buffer + // + *FileBuffer = malloc (*FileSize); + if (*FileBuffer == NULL) { + fprintf (stderr, "Can not allocate buffer for input input file %s\n", InputFileName); + fclose (InputFile); + exit (EXIT_FAILURE); + } + + // + // Reset to the beginning of the file + // + if (fseek (InputFile, 0, SEEK_SET)) { + fprintf (stderr, "Error reading the input file %s\n", InputFileName); + fclose (InputFile); + free (*FileBuffer); + exit (EXIT_FAILURE); + } + + // + // Read all of the file contents. + // + BytesRead = (UINT32)fread (*FileBuffer, sizeof (UINT8), *FileSize, InputFile); + if (BytesRead != *FileSize * sizeof (UINT8)) { + fprintf (stderr, "Error reading the input file %s\n", InputFileName); + fclose (InputFile); + free (*FileBuffer); + exit (EXIT_FAILURE); + } + + // + // Close the file + // + fclose (InputFile); +} + +/** + Read the initial PCD value from the input file buffer. + + @param FileBuffer Point to the input file buffer. + @param FileSize Size of the file buffer. +**/ +VOID +STATIC +ParseFile ( + UINT8 *FileBuffer, + UINT32 FileSize + ) +{ + UINT32 Index; + UINT32 NumLines; + UINT32 TokenIndex; + UINT32 TokenStart; + + for (Index = 0, NumLines = 0; Index < FileSize; Index++) { + if (FileBuffer[Index] == '\n') { + NumLines++; + } + } + PcdList = malloc((NumLines + 1) * sizeof(PcdList[0])); + + for (Index = 0, TokenIndex = 0, PcdListLength = 0, TokenStart = 0; Index < FileSize; Index++) { + if (FileBuffer[Index] == ' ') { + continue; + } + if (FileBuffer[Index] == '|' || FileBuffer[Index] == '.' || FileBuffer[Index] == '\n' || FileBuffer[Index] == '\r') { + RecordToken (FileBuffer, PcdListLength, TokenIndex, TokenStart, Index); + if (FileBuffer[Index] == '\n' || FileBuffer[Index] == '\r') { + if (TokenIndex != 0) { + PcdListLength++; + TokenIndex = 0; + } + } else { + TokenIndex++; + } + TokenStart = Index + 1; + continue; + } + } + if (Index > TokenStart) { + RecordToken (FileBuffer, PcdListLength, TokenIndex, TokenStart, Index); + if (TokenIndex != 0) { + PcdListLength++; + } + } +} + +/** + Write the updated PCD value into the output file name. + + @param OutputFileName Point to the output file name. +**/ +VOID +STATIC +WriteOutputFile ( + CHAR8 *OutputFileName + ) +{ + FILE *OutputFile; + UINT32 Index; + + // + // Open output file + // + OutputFile = fopen (OutputFileName, "wb"); + if (OutputFile == NULL) { + fprintf (stderr, "Error opening file %s\n", OutputFileName); + exit (EXIT_FAILURE); + } + + for (Index = 0; Index < PcdListLength; Index++) { + fprintf ( + OutputFile, + "%s.%s.%s.%s|%s|%s\n", + PcdList[Index].SkuName, + PcdList[Index].DefaultValueName, + PcdList[Index].TokenSpaceGuidName, + PcdList[Index].TokenName, + PcdList[Index].DataType, + PcdList[Index].Value + ); + } + + // + // Done, write output file. + // + if (OutputFile != NULL) { + fclose (OutputFile); + } +} + +/** + Displays the utility usage syntax to STDOUT +**/ +VOID +STATIC +Usage ( + VOID + ) +{ + fprintf (stdout, "Usage: -i -o \n\n"); + fprintf (stdout, "optional arguments:\n"); + fprintf (stdout, " -h, --help Show this help message and exit\n"); + fprintf (stdout, " -i INPUT_FILENAME, --input INPUT_FILENAME\n\ + PCD Database Input file name\n"); + fprintf (stdout, " -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\ + PCD Database Output file name\n"); +} + +/** + Parse the input parameters to get the input/output file name. + + @param argc Number of command line parameters. + @param argv Array of pointers to parameter strings. + @param InputFileName Point to the input file name. + @param OutputFileName Point to the output file name. +**/ +VOID +STATIC +ParseArguments ( + int argc, + char *argv[], + CHAR8 **InputFileName, + CHAR8 **OutputFileName + ) +{ + if (argc == 1) { + fprintf (stderr, "Missing options\n"); + exit (EXIT_FAILURE); + } + + // + // Parse command line + // + argc--; + argv++; + + if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) { + Usage (); + exit (EXIT_SUCCESS); + } + + while (argc > 0) { + if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--input") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + fprintf (stderr, "Invalid option value. Input File name is missing for -i option\n"); + exit (EXIT_FAILURE); + } + *InputFileName = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + fprintf (stderr, "Invalid option value. Output File name is missing for -i option\n"); + exit (EXIT_FAILURE); + } + *OutputFileName = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if (argv[0][0] == '-') { + fprintf (stderr, "Unknown option %s\n", argv[0]); + exit (EXIT_FAILURE); + } + argc --; + argv ++; + } + + // + // Check Input parameters + // + if (*InputFileName == NULL) { + fprintf (stderr, "Missing option. Input files is not specified\n"); + exit (EXIT_FAILURE); + } + + if (*OutputFileName == NULL) { + fprintf (stderr, "Missing option. Output file is not specified\n"); + exit (EXIT_FAILURE); + } +} + +/** + Main function updates PCD values. + + @param argc Number of command line parameters. + @param argv Array of pointers to parameter strings. + + @retval EXIT_SUCCESS +**/ +int +PcdValueMain ( + int argc, + char *argv[] + ) +{ + CHAR8 *InputFileName; + CHAR8 *OutputFileName; + UINT8 *FileBuffer; + UINT32 FileSize; + + InputFileName = NULL; + OutputFileName = NULL; + + // + // Parse the input arguments + // + ParseArguments (argc, argv, &InputFileName, &OutputFileName); + + // + // Open Input file and read file data. + // + ReadInputFile (InputFileName, &FileBuffer, &FileSize); + + // + // Read the initial Pcd value + // + ParseFile (FileBuffer, FileSize); + + // + // Customize PCD values in the PCD Database + // + PcdEntryPoint (); + + // + // Save the updated PCD value + // + WriteOutputFile (OutputFileName); + + exit (EXIT_SUCCESS); +} diff --git a/tools/src/GenFw/Common/src/PcdValueCommon.h b/tools/src/GenFw/Common/src/PcdValueCommon.h new file mode 100644 index 0000000..2ec8a5a --- /dev/null +++ b/tools/src/GenFw/Common/src/PcdValueCommon.h @@ -0,0 +1,137 @@ +/** @file +Header file for PcdValue structure definition. + +Copyright (c) 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PCD_VALUE_COMMON_H +#define _PCD_VALUE_COMMON_H + +#include +#include + +#define __FIELD_SIZE(TYPE, Field) (sizeof((TYPE *)0)->Field) +#define __ARRAY_ELEMENT_SIZE(TYPE, Field) (sizeof((TYPE *)0)->Field[0]) +#define __OFFSET_OF(TYPE, Field) ((UINT32)(size_t) &(((TYPE *)0)->Field)) +#define __FLEXIBLE_SIZE(Size, TYPE, Field, MaxIndex) if (__FIELD_SIZE(TYPE, Field) == 0) Size = MAX((__OFFSET_OF(TYPE, Field) + __ARRAY_ELEMENT_SIZE(TYPE, Field) * (MaxIndex)), Size) +#define __ARRAY_SIZE(Array) (sizeof(Array)/sizeof(Array[0])) + +#if defined(_MSC_EXTENSIONS) +#define __STATIC_ASSERT static_assert +#else +#define __STATIC_ASSERT _Static_assert +#endif + +/** + Main function updates PCD values. It is auto generated by Build +**/ +VOID +PcdEntryPoint ( + VOID + ) + +; + +/** + Main function updates PCD values. + + @param argc Number of command line parameters. + @param argv Array of pointers to parameter strings. + + @retval EXIT_SUCCESS +**/ +int +PcdValueMain ( + int argc, + char *argv[] + ) +; + +/** + Set PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Value PCD value to be set +**/ +VOID +__PcdSet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT64 Value + ) +; + +/** + Get PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + + @return PCD value +**/ +UINT64 +__PcdGet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName + ) +; + +/** + Get PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value buffer + + @return PCD value buffer +**/ +VOID * +__PcdGetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 *Size + ) +; + +/** + Set PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value + @param Value Pointer to the updated PCD value buffer +**/ +VOID +__PcdSetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 Size, + UINT8 *Value + ) +; + +#define PcdGet(A, B, C, D) __PcdGet(#A, #B, #C, #D) +#define PcdSet(A, B, C, D, Value) __PcdSet(#A, #B, #C, #D, Value) +#define PcdGetPtr(A, B, C, D, Size) __PcdGetPtr(#A, #B, #C, #D, Size) +#define PcdSetPtr(A, B, C, D, Size, Value) __PcdSetPtr(#A, #B, #C, #D, Size, Value) + +#endif diff --git a/tools/src/GenFw/Common/src/PeCoffLib.h b/tools/src/GenFw/Common/src/PeCoffLib.h new file mode 100644 index 0000000..b625f6a --- /dev/null +++ b/tools/src/GenFw/Common/src/PeCoffLib.h @@ -0,0 +1,213 @@ +/** @file + Function prototypes and defines on Memory Only PE COFF loader + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Portion Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __BASE_PE_COFF_LIB_H__ +#define __BASE_PE_COFF_LIB_H__ + +// +// Return status codes from the PE/COFF Loader services +// BUGBUG: Find where used and see if can be replaced by RETURN_STATUS codes +// +#define IMAGE_ERROR_SUCCESS 0 +#define IMAGE_ERROR_IMAGE_READ 1 +#define IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE 2 +#define IMAGE_ERROR_INVALID_MACHINE_TYPE 3 +#define IMAGE_ERROR_INVALID_SUBSYSTEM 4 +#define IMAGE_ERROR_INVALID_IMAGE_ADDRESS 5 +#define IMAGE_ERROR_INVALID_IMAGE_SIZE 6 +#define IMAGE_ERROR_INVALID_SECTION_ALIGNMENT 7 +#define IMAGE_ERROR_SECTION_NOT_LOADED 8 +#define IMAGE_ERROR_FAILED_RELOCATION 9 +#define IMAGE_ERROR_FAILED_ICACHE_FLUSH 10 + +// +// Macro definitions for RISC-V architecture. +// +#define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1)) +#define RISCV_IMM_BITS 12 +#define RISCV_IMM_REACH (1LL<ImageRead() function + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderGetImageInfo ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +/** + Relocates a PE/COFF image in memory + + @param ImageContext Contains information on the loaded image to relocate + + @retval EFI_SUCCESS if the PE/COFF image was relocated + @retval EFI_LOAD_ERROR if the image is not a valid PE/COFF image + @retval EFI_UNSUPPORTED not support + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +/** + Loads a PE/COFF image into memory + + @param ImageContext Contains information on image to load into memory + + @retval EFI_SUCCESS if the PE/COFF image was loaded + @retval EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer + @retval EFI_LOAD_ERROR if the image is a runtime driver with no relocations + @retval EFI_INVALID_PARAMETER if the image address is invalid + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +VOID * +EFIAPI +PeCoffLoaderGetPdbPointer ( + IN VOID *Pe32Data + ) +; + +RETURN_STATUS +EFIAPI +PeCoffLoaderGetEntryPoint ( + IN VOID *Pe32Data, + OUT VOID **EntryPoint, + OUT VOID **BaseOfImage + ) +; + +// +// These functions are used by the ARM PE/COFF relocation code and by +// the ELF to PE/COFF converter so that is why they are public +// + +/** + Pass in a pointer to an ARM MOVT or MOVW immediate instruction and + return the immediate data encoded in the instruction + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + + @return Immediate address encoded in the instruction + +**/ +UINT16 +EFIAPI +ThumbMovtImmediateAddress ( + IN UINT16 *Instruction + ); + +/** + Update an ARM MOVT or MOVW immediate instruction immediate data. + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + @param Address New address to patch into the instruction + +**/ +VOID +EFIAPI +ThumbMovtImmediatePatch ( + IN OUT UINT16 *Instruction, + IN UINT16 Address + ); + + +/** + Pass in a pointer to an ARM MOVW/MOVT instruction pair and + return the immediate data encoded in the two` instruction + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + + @return Immediate address encoded in the instructions + +**/ +UINT32 +EFIAPI +ThumbMovwMovtImmediateAddress ( + IN UINT16 *Instructions + ); + +/** + Update an ARM MOVW/MOVT immediate instruction instruction pair. + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + @param Address New address to patch into the instructions +**/ +VOID +EFIAPI +ThumbMovwMovtImmediatePatch ( + IN OUT UINT16 *Instructions, + IN UINT32 Address + ); + + + +#endif diff --git a/tools/src/GenFw/Common/src/PeCoffLoaderEx.c b/tools/src/GenFw/Common/src/PeCoffLoaderEx.c new file mode 100644 index 0000000..c7fa7f4 --- /dev/null +++ b/tools/src/GenFw/Common/src/PeCoffLoaderEx.c @@ -0,0 +1,391 @@ +/** @file +IA32 and X64 Specific relocation fixups + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include +#include +#include "PeCoffLib.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" + + +#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \ + Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos) + +#define INS_IMM64(Value, Address, Size, InstPos, ValPos) \ + *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \ + ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos) + +#define IMM64_IMM7B_INST_WORD_X 3 +#define IMM64_IMM7B_SIZE_X 7 +#define IMM64_IMM7B_INST_WORD_POS_X 4 +#define IMM64_IMM7B_VAL_POS_X 0 + +#define IMM64_IMM9D_INST_WORD_X 3 +#define IMM64_IMM9D_SIZE_X 9 +#define IMM64_IMM9D_INST_WORD_POS_X 18 +#define IMM64_IMM9D_VAL_POS_X 7 + +#define IMM64_IMM5C_INST_WORD_X 3 +#define IMM64_IMM5C_SIZE_X 5 +#define IMM64_IMM5C_INST_WORD_POS_X 13 +#define IMM64_IMM5C_VAL_POS_X 16 + +#define IMM64_IC_INST_WORD_X 3 +#define IMM64_IC_SIZE_X 1 +#define IMM64_IC_INST_WORD_POS_X 12 +#define IMM64_IC_VAL_POS_X 21 + +#define IMM64_IMM41a_INST_WORD_X 1 +#define IMM64_IMM41a_SIZE_X 10 +#define IMM64_IMM41a_INST_WORD_POS_X 14 +#define IMM64_IMM41a_VAL_POS_X 22 + +#define IMM64_IMM41b_INST_WORD_X 1 +#define IMM64_IMM41b_SIZE_X 8 +#define IMM64_IMM41b_INST_WORD_POS_X 24 +#define IMM64_IMM41b_VAL_POS_X 32 + +#define IMM64_IMM41c_INST_WORD_X 2 +#define IMM64_IMM41c_SIZE_X 23 +#define IMM64_IMM41c_INST_WORD_POS_X 0 +#define IMM64_IMM41c_VAL_POS_X 40 + +#define IMM64_SIGN_INST_WORD_X 3 +#define IMM64_SIGN_SIZE_X 1 +#define IMM64_SIGN_INST_WORD_POS_X 27 +#define IMM64_SIGN_VAL_POS_X 63 + +UINT32 *RiscVHi20Fixup = NULL; + +/** + Performs an IA-32 specific relocation fixup + + @param Reloc Pointer to the relocation record + @param Fixup Pointer to the address to fix up + @param FixupData Pointer to a buffer to log the fixups + @param Adjust The offset to adjust the fixup + + @retval EFI_UNSUPPORTED - Unsupported now +**/ +RETURN_STATUS +PeCoffLoaderRelocateIa32Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + return RETURN_UNSUPPORTED; +} + +/** + Performs an RISC-V specific relocation fixup + + @param Reloc Pointer to the relocation record + @param Fixup Pointer to the address to fix up + @param FixupData Pointer to a buffer to log the fixups + @param Adjust The offset to adjust the fixup + + @return Status code +**/ +RETURN_STATUS +PeCoffLoaderRelocateRiscVImage ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT32 Value; + UINT32 Value2; + + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_RISCV_HI20: + RiscVHi20Fixup = (UINT32 *) Fixup; + break; + + case EFI_IMAGE_REL_BASED_RISCV_LOW12I: + if (RiscVHi20Fixup != NULL) { + Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12); + Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 20, 12)); + if (Value2 & (RISCV_IMM_REACH/2)) { + Value2 |= ~(RISCV_IMM_REACH-1); + } + Value += Value2; + Value += (UINT32)Adjust; + Value2 = RISCV_CONST_HIGH_PART (Value); + *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \ + (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12)); + *(UINT32 *)Fixup = (RV_X (Value, 0, 12) << 20) | \ + (RV_X (*(UINT32 *)Fixup, 0, 20)); + } + RiscVHi20Fixup = NULL; + break; + + case EFI_IMAGE_REL_BASED_RISCV_LOW12S: + if (RiscVHi20Fixup != NULL) { + Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12); + Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 7, 5) | (RV_X(*(UINT32 *)Fixup, 25, 7) << 5)); + if (Value2 & (RISCV_IMM_REACH/2)) { + Value2 |= ~(RISCV_IMM_REACH-1); + } + Value += Value2; + Value += (UINT32)Adjust; + Value2 = RISCV_CONST_HIGH_PART (Value); + *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \ + (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12)); + Value2 = *(UINT32 *)Fixup & 0x01fff07f; + Value &= RISCV_IMM_REACH - 1; + *(UINT32 *)Fixup = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25))); + } + RiscVHi20Fixup = NULL; + break; + + default: + return EFI_UNSUPPORTED; + + } + return RETURN_SUCCESS; +} + +/** + Pass in a pointer to an ARM MOVT or MOVW immediate instruction and + return the immediate data encoded in the instruction + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + + @return Immediate address encoded in the instruction + +**/ +UINT16 +ThumbMovtImmediateAddress ( + IN UINT16 *Instruction + ) +{ + UINT32 Movt; + UINT16 Address; + + // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction + // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000 + Movt = (*Instruction << 16) | (*(Instruction + 1)); + + // imm16 = imm4:i:imm3:imm8 + // imm4 -> Bit19:Bit16 + // i -> Bit26 + // imm3 -> Bit14:Bit12 + // imm8 -> Bit7:Bit0 + Address = (UINT16)(Movt & 0x000000ff); // imm8 + Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3 + Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i + return Address; +} + + +/** + Update an ARM MOVT or MOVW immediate instruction immediate data. + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + @param Address New address to patch into the instruction +**/ +VOID +ThumbMovtImmediatePatch ( + IN OUT UINT16 *Instruction, + IN UINT16 Address + ) +{ + UINT16 Patch; + + // First 16-bit chunk of instruction + Patch = ((Address >> 12) & 0x000f); // imm4 + Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i + *Instruction = (*Instruction & ~0x040f) | Patch; + + // Second 16-bit chunk of instruction + Patch = Address & 0x000000ff; // imm8 + Patch |= ((Address << 4) & 0x00007000); // imm3 + Instruction++; + *Instruction = (*Instruction & ~0x70ff) | Patch; +} + +/** + Pass in a pointer to an ARM MOVW/MOVT instruction pair and + return the immediate data encoded in the two` instruction + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + + @return Immediate address encoded in the instructions + +**/ +UINT32 +EFIAPI +ThumbMovwMovtImmediateAddress ( + IN UINT16 *Instructions + ) +{ + UINT16 *Word; + UINT16 *Top; + + Word = Instructions; // MOVW + Top = Word + 2; // MOVT + + return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word); +} + + +/** + Update an ARM MOVW/MOVT immediate instruction instruction pair. + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + @param Address New address to patch into the instructions +**/ +VOID +EFIAPI +ThumbMovwMovtImmediatePatch ( + IN OUT UINT16 *Instructions, + IN UINT32 Address + ) +{ + UINT16 *Word; + UINT16 *Top; + + Word = (UINT16 *)Instructions; // MOVW + Top = Word + 2; // MOVT + + ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff)); + ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16)); +} + + +/** + Performs an ARM-based specific relocation fixup and is a no-op on other + instruction sets. + + @param Reloc Pointer to the relocation record. + @param Fixup Pointer to the address to fix up. + @param FixupData Pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeCoffLoaderRelocateArmImage ( + IN UINT16 **Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT16 *Fixup16; + UINT32 FixupVal; + + Fixup16 = (UINT16 *) Fixup; + + switch ((**Reloc) >> 12) { + + case EFI_IMAGE_REL_BASED_ARM_MOV32T: + FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust; + ThumbMovwMovtImmediatePatch (Fixup16, FixupVal); + + + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); + CopyMem (*FixupData, Fixup16, sizeof (UINT64)); + *FixupData = *FixupData + sizeof(UINT64); + } + break; + + case EFI_IMAGE_REL_BASED_ARM_MOV32A: + // break omitted - ARM instruction encoding not implemented + default: + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +/** + Performs a LoongArch specific relocation fixup. + + @param[in] Reloc Pointer to the relocation record. + @param[in, out] Fixup Pointer to the address to fix up. + @param[in, out] FixupData Pointer to a buffer to log the fixups. + @param[in] Adjust The offset to adjust the fixup. + + @return Status code. +**/ +RETURN_STATUS +PeCoffLoaderRelocateLoongArch64Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT8 RelocType; + UINT64 Value; + UINT64 Tmp1; + UINT64 Tmp2; + + RelocType = ((*Reloc) >> 12); + Value = 0; + Tmp1 = 0; + Tmp2 = 0; + + switch (RelocType) { + case EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA: + // The next four instructions are used to load a 64 bit address, relocate all of them + Value = (*(UINT32 *)Fixup & 0x1ffffe0) << 7 | // lu12i.w 20bits from bit5 + (*((UINT32 *)Fixup + 1) & 0x3ffc00) >> 10; // ori 12bits from bit10 + Tmp1 = *((UINT32 *)Fixup + 2) & 0x1ffffe0; // lu32i.d 20bits from bit5 + Tmp2 = *((UINT32 *)Fixup + 3) & 0x3ffc00; // lu52i.d 12bits from bit10 + Value = Value | (Tmp1 << 27) | (Tmp2 << 42); + Value += Adjust; + + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 12) & 0xfffff) << 5); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + Fixup += sizeof (UINT32); + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | ((Value & 0xfff) << 10); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + Fixup += sizeof (UINT32); + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 32) & 0xfffff) << 5); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + Fixup += sizeof (UINT32); + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | (((Value >> 52) & 0xfff) << 10); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + break; + default: + Error (NULL, 0, 3000, "", "PeCoffLoaderRelocateLoongArch64Image: Fixup[0x%x] Adjust[0x%llx] *Reloc[0x%x], type[0x%x].", *(UINT32 *)Fixup, Adjust, *Reloc, RelocType); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} diff --git a/tools/src/GenFw/Common/src/SimpleFileParsing.c b/tools/src/GenFw/Common/src/SimpleFileParsing.c new file mode 100644 index 0000000..2dcc865 --- /dev/null +++ b/tools/src/GenFw/Common/src/SimpleFileParsing.c @@ -0,0 +1,1323 @@ +/** @file +Generic but simple file parsing routines. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include +#include +#include +#include + +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "SimpleFileParsing.h" + +#ifndef MAX_PATH +#define MAX_PATH 255 +#endif +// +// just in case we get in an endless loop. +// +#define MAX_NEST_DEPTH 20 +// +// number of wchars +// +#define MAX_STRING_IDENTIFIER_NAME 100 + +#define T_CHAR_SPACE ' ' +#define T_CHAR_NULL 0 +#define T_CHAR_CR '\r' +#define T_CHAR_TAB '\t' +#define T_CHAR_LF '\n' +#define T_CHAR_SLASH '/' +#define T_CHAR_BACKSLASH '\\' +#define T_CHAR_DOUBLE_QUOTE '"' +#define T_CHAR_LC_X 'x' +#define T_CHAR_0 '0' +#define T_CHAR_STAR '*' + +// +// We keep a linked list of these for the source files we process +// +typedef struct _SOURCE_FILE { + FILE *Fptr; + CHAR8 *FileBuffer; + CHAR8 *FileBufferPtr; + UINTN FileSize; + CHAR8 FileName[MAX_PATH]; + UINTN LineNum; + BOOLEAN EndOfFile; + BOOLEAN SkipToHash; + struct _SOURCE_FILE *Previous; + struct _SOURCE_FILE *Next; + CHAR8 ControlCharacter; +} SOURCE_FILE; + +typedef struct { + CHAR8 *FileBufferPtr; +} FILE_POSITION; + +// +// Keep all our module globals in this structure +// +STATIC struct { + SOURCE_FILE SourceFile; + BOOLEAN VerboseFile; + BOOLEAN VerboseToken; +} mGlobals; + +STATIC +UINTN +t_strcmp ( + CHAR8 *Buffer, + CHAR8 *Str + ); + +STATIC +UINTN +t_strncmp ( + CHAR8 *Str1, + CHAR8 *Str2, + INTN Len + ); + +STATIC +UINTN +t_strlen ( + CHAR8 *Str + ); + +STATIC +VOID +RewindFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +BOOLEAN +IsWhiteSpace ( + SOURCE_FILE *SourceFile + ); + +STATIC +UINTN +SkipWhiteSpace ( + SOURCE_FILE *SourceFile + ); + +STATIC +BOOLEAN +EndOfFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +VOID +PreprocessFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +CHAR8 * +t_strcpy ( + CHAR8 *Dest, + CHAR8 *Src + ); + +STATIC +STATUS +ProcessIncludeFile ( + SOURCE_FILE *SourceFile, + SOURCE_FILE *ParentSourceFile + ); + +STATIC +STATUS +ProcessFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +STATUS +GetFilePosition ( + FILE_POSITION *Fpos + ); + +STATIC +STATUS +SetFilePosition ( + FILE_POSITION *Fpos + ); + +/** + @retval STATUS_SUCCESS always +**/ +STATUS +SFPInit ( + VOID + ) +{ + memset ((VOID *) &mGlobals, 0, sizeof (mGlobals)); + return STATUS_SUCCESS; +} + +/** + Return the line number of the file we're parsing. Used + for error reporting purposes. + + @return The line number, or 0 if no file is being processed +**/ +UINTN +SFPGetLineNumber ( + VOID + ) +{ + return mGlobals.SourceFile.LineNum; +} + +/** + Return the name of the file we're parsing. Used + for error reporting purposes. + + @return A pointer to the file name. Null if no file is being + processed. +**/ +CHAR8 * +SFPGetFileName ( + VOID + ) +{ + if (mGlobals.SourceFile.FileName[0]) { + return mGlobals.SourceFile.FileName; + } + + return NULL; +} + +/** + Open a file for parsing. + + @param FileName name of the file to parse +**/ +STATUS +SFPOpenFile ( + CHAR8 *FileName + ) +{ + STATUS Status; + t_strcpy (mGlobals.SourceFile.FileName, FileName); + Status = ProcessIncludeFile (&mGlobals.SourceFile, NULL); + return Status; +} + +/** + Check to see if the specified token is found at + the current position in the input file. + + @note: + We do a simple string comparison on this function. It is + the responsibility of the caller to ensure that the token + is not a subset of some other token. + + The file pointer is advanced past the token in the input file. + + @param Str the token to look for + + @retval TRUE the token is next + @retval FALSE the token is not next +**/ +BOOLEAN +SFPIsToken ( + CHAR8 *Str + ) +{ + UINTN Len; + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { + mGlobals.SourceFile.FileBufferPtr += Len; + if (mGlobals.VerboseToken) { + printf ("Token: '%s'\n", Str); + } + + return TRUE; + } + + return FALSE; +} + +/** + Check to see if the specified keyword is found at + the current position in the input file. + + @note: + A keyword is defined as a "special" string that has a non-alphanumeric + character following it. + + @param Str keyword to look for + + @retval TRUE the keyword is next + @retval FALSE the keyword is not next +**/ +BOOLEAN +SFPIsKeyword ( + CHAR8 *Str + ) +{ + UINTN Len; + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { + if (isalnum ((int)mGlobals.SourceFile.FileBufferPtr[Len])) { + return FALSE; + } + + mGlobals.SourceFile.FileBufferPtr += Len; + if (mGlobals.VerboseToken) { + printf ("Token: '%s'\n", Str); + } + + return TRUE; + } + + return FALSE; +} + +/** + Get the next token from the input stream. + + @note: + Preceding white space is ignored. + The parser's buffer pointer is advanced past the end of the + token. + + @param Str pointer to a copy of the next token + @param Len size of buffer pointed to by Str + + @retval TRUE next token successfully returned + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetNextToken ( + CHAR8 *Str, + UINTN Len + ) +{ + UINTN Index; + CHAR8 TempChar; + + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + // + // Have to have enough string for at least one char and a null-terminator + // + if (Len < 2) { + return FALSE; + } + // + // Look at the first character. If it's an identifier, then treat it + // as such + // + TempChar = mGlobals.SourceFile.FileBufferPtr[0]; + if (((TempChar >= 'a') && (TempChar <= 'z')) || ((TempChar >= 'A') && (TempChar <= 'Z')) || (TempChar == '_')) { + Str[0] = TempChar; + mGlobals.SourceFile.FileBufferPtr++; + Index = 1; + while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { + TempChar = mGlobals.SourceFile.FileBufferPtr[0]; + if (((TempChar >= 'a') && (TempChar <= 'z')) || + ((TempChar >= 'A') && (TempChar <= 'Z')) || + ((TempChar >= '0') && (TempChar <= '9')) || + (TempChar == '_') + ) { + Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Index++; + } else { + // + // Invalid character for symbol name, so break out + // + break; + } + } + // + // Null terminate and return success + // + Str[Index] = 0; + return TRUE; + } else if ((TempChar == ')') || (TempChar == '(') || (TempChar == '*')) { + Str[0] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Str[1] = 0; + return TRUE; + } else { + // + // Everything else is white-space (or EOF) separated + // + Index = 0; + while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { + if (IsWhiteSpace (&mGlobals.SourceFile)) { + if (Index > 0) { + Str[Index] = 0; + return TRUE; + } + + return FALSE; + } else { + Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Index++; + } + } + // + // See if we just ran out of file contents, but did find a token + // + if ((Index > 0) && EndOfFile (&mGlobals.SourceFile)) { + Str[Index] = 0; + return TRUE; + } + } + + return FALSE; +} + +/** + Parse a GUID from the input stream. Stop when you discover white space. + + @param Str pointer to a copy of the next token + @param Len size of buffer pointed to by Str + + @retval TRUE GUID string returned successfully + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetGuidToken ( + CHAR8 *Str, + UINT32 Len + ) +{ + UINT32 Index; + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + Index = 0; + while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { + if (IsWhiteSpace (&mGlobals.SourceFile)) { + if (Index > 0) { + Str[Index] = 0; + return TRUE; + } + + return FALSE; + } else { + Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Index++; + } + } + + return FALSE; +} + +BOOLEAN +SFPSkipToToken ( + CHAR8 *Str + ) +{ + UINTN Len; + CHAR8 *SavePos; + Len = t_strlen (Str); + SavePos = mGlobals.SourceFile.FileBufferPtr; + SkipWhiteSpace (&mGlobals.SourceFile); + while (!EndOfFile (&mGlobals.SourceFile)) { + if (t_strncmp (Str, mGlobals.SourceFile.FileBufferPtr, Len) == 0) { + mGlobals.SourceFile.FileBufferPtr += Len; + return TRUE; + } + + mGlobals.SourceFile.FileBufferPtr++; + SkipWhiteSpace (&mGlobals.SourceFile); + } + + mGlobals.SourceFile.FileBufferPtr = SavePos; + return FALSE; +} + +/** + Check the token at the current file position for a numeric value. + May be either decimal or hex. + + @param Value pointer where to store the value + + @retval FALSE current token is not a number + @retval TRUE current token is a number +**/ +BOOLEAN +SFPGetNumber ( + UINTN *Value + ) +{ + int Val; + + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + // + // Check for hex value + // + if ((mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_0) && (mGlobals.SourceFile.FileBufferPtr[1] == T_CHAR_LC_X)) { + if (!isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[2])) { + return FALSE; + } + + mGlobals.SourceFile.FileBufferPtr += 2; + sscanf (mGlobals.SourceFile.FileBufferPtr, "%x", &Val); + *Value = (UINT32) Val; + while (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + mGlobals.SourceFile.FileBufferPtr++; + } + + return TRUE; + } else { + *Value = atoi (mGlobals.SourceFile.FileBufferPtr); + while (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + mGlobals.SourceFile.FileBufferPtr++; + } + + return TRUE; + } + } else { + return FALSE; + } +} + +/** + Close the file being parsed. + + @retval STATUS_SUCCESS the file was closed + @retval STATUS_ERROR no file is currently open +**/ +STATUS +SFPCloseFile ( + VOID + ) +{ + if (mGlobals.SourceFile.FileBuffer != NULL) { + free (mGlobals.SourceFile.FileBuffer); + memset (&mGlobals.SourceFile, 0, sizeof (mGlobals.SourceFile)); + return STATUS_SUCCESS; + } + + return STATUS_ERROR; +} + +/** + Given a source file, open the file and parse it + + @param SourceFile name of file to parse + @param ParentSourceFile for error reporting purposes, the file that #included SourceFile. + + @return Standard status. +**/ +STATIC +STATUS +ProcessIncludeFile ( + SOURCE_FILE *SourceFile, + SOURCE_FILE *ParentSourceFile + ) +{ + STATIC UINTN NestDepth = 0; + CHAR8 FoundFileName[MAX_PATH]; + STATUS Status; + + Status = STATUS_SUCCESS; + NestDepth++; + // + // Print the file being processed. Indent so you can tell the include nesting + // depth. + // + if (mGlobals.VerboseFile) { + fprintf (stdout, "%*cProcessing file '%s'\n", (int)NestDepth * 2, ' ', SourceFile->FileName); + fprintf (stdout, "Parent source file = '%s'\n", ParentSourceFile->FileName); + } + + // + // Make sure we didn't exceed our maximum nesting depth + // + if (NestDepth > MAX_NEST_DEPTH) { + Error (NULL, 0, 3001, "Not Supported", "%s exceeds max nesting depth (%u)", SourceFile->FileName, (unsigned) NestDepth); + Status = STATUS_ERROR; + goto Finish; + } + // + // Try to open the file locally, and if that fails try along our include paths. + // + strcpy (FoundFileName, SourceFile->FileName); + if ((SourceFile->Fptr = fopen (LongFilePath (FoundFileName), "rb")) == NULL) { + return STATUS_ERROR; + } + // + // Process the file found + // + ProcessFile (SourceFile); +Finish: + // + // Close open files and return status + // + if (SourceFile->Fptr != NULL) { + fclose (SourceFile->Fptr); + SourceFile->Fptr = NULL; + } + + return Status; +} + +/** + Given a source file that's been opened, read the contents into an internal + buffer and pre-process it to remove comments. + + @param SourceFile structure containing info on the file to process + + @return Standard status. +**/ +STATIC +STATUS +ProcessFile ( + SOURCE_FILE *SourceFile + ) +{ + // + // Get the file size, and then read the entire thing into memory. + // Allocate extra space for a terminator character. + // + fseek (SourceFile->Fptr, 0, SEEK_END); + SourceFile->FileSize = ftell (SourceFile->Fptr); + if (mGlobals.VerboseFile) { + printf ("FileSize = %u (0x%X)\n", (unsigned) SourceFile->FileSize, (unsigned) SourceFile->FileSize); + } + + fseek (SourceFile->Fptr, 0, SEEK_SET); + SourceFile->FileBuffer = (CHAR8 *) malloc (SourceFile->FileSize + sizeof (CHAR8 )); + if (SourceFile->FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL); + return STATUS_ERROR; + } + + fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr); + SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (CHAR8 ))] = T_CHAR_NULL; + // + // Pre-process the file to replace comments with spaces + // + PreprocessFile (SourceFile); + SourceFile->LineNum = 1; + return STATUS_SUCCESS; +} + +/** + Preprocess a file to replace all carriage returns with NULLs so + we can print lines (as part of error messages) from the file to the screen. + + @param SourceFile structure that we use to keep track of an input file. +**/ +STATIC +VOID +PreprocessFile ( + SOURCE_FILE *SourceFile + ) +{ + BOOLEAN InComment; + BOOLEAN SlashSlashComment; + int LineNum; + + RewindFile (SourceFile); + InComment = FALSE; + SlashSlashComment = FALSE; + while (!EndOfFile (SourceFile)) { + // + // If a line-feed, then no longer in a comment if we're in a // comment + // + if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { + SourceFile->FileBufferPtr++; + SourceFile->LineNum++; + if (InComment && SlashSlashComment) { + InComment = FALSE; + SlashSlashComment = FALSE; + } + } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) { + // + // Replace all carriage returns with a NULL so we can print stuff + // + SourceFile->FileBufferPtr[0] = 0; + SourceFile->FileBufferPtr++; + // + // Check for */ comment end + // + } else if (InComment && + !SlashSlashComment && + (SourceFile->FileBufferPtr[0] == T_CHAR_STAR) && + (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH) + ) { + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + InComment = FALSE; + } else if (InComment) { + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + // + // Check for // comments + // + } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)) { + InComment = TRUE; + SlashSlashComment = TRUE; + // + // Check for /* comment start + // + } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_STAR)) { + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + SlashSlashComment = FALSE; + InComment = TRUE; + } else { + SourceFile->FileBufferPtr++; + } + } + // + // Could check for end-of-file and still in a comment, but + // should not be necessary. So just restore the file pointers. + // + RewindFile (SourceFile); + // + // Dump the reformatted file if verbose mode + // + if (mGlobals.VerboseFile) { + LineNum = 1; + printf ("%04d: ", LineNum); + while (!EndOfFile (SourceFile)) { + if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { + printf ("'\n%04d: '", ++LineNum); + } else { + printf ("%c", SourceFile->FileBufferPtr[0]); + } + + SourceFile->FileBufferPtr++; + } + + printf ("'\n"); + printf ("FileSize = %u (0x%X)\n", (unsigned)SourceFile->FileSize, (unsigned)SourceFile->FileSize); + RewindFile (SourceFile); + } +} + +/** + Retrieve a quoted-string from the input file. + + @param Str pointer to a copy of the quoted string parsed + @param Length size of buffer pointed to by Str + + @retval TRUE next token in input stream was a quoted string, and + the string value was returned in Str + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetQuotedString ( + CHAR8 *Str, + INTN Length + ) +{ + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { + mGlobals.SourceFile.FileBufferPtr++; + while (Length > 0) { + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + // + // Check for closing quote + // + if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { + mGlobals.SourceFile.FileBufferPtr++; + *Str = 0; + return TRUE; + } + + *Str = mGlobals.SourceFile.FileBufferPtr[0]; + Str++; + Length--; + mGlobals.SourceFile.FileBufferPtr++; + } + } + // + // First character was not a quote, or the input string length was + // insufficient to contain the quoted string, so return failure code. + // + return FALSE; +} + +/** + Return TRUE of FALSE to indicate whether or not we've reached the end of the + file we're parsing. + + @retval TRUE EOF reached + @retval FALSE otherwise +**/ +BOOLEAN +SFPIsEOF ( + VOID + ) +{ + SkipWhiteSpace (&mGlobals.SourceFile); + return EndOfFile (&mGlobals.SourceFile); +} + +#if 0 +STATIC +CHAR8 * +GetQuotedString ( + SOURCE_FILE *SourceFile, + BOOLEAN Optional + ) +{ + CHAR8 *String; + CHAR8 *Start; + CHAR8 *Ptr; + UINTN Len; + BOOLEAN PreviousBackslash; + + if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { + if (Optional == FALSE) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr); + } + + return NULL; + } + + Len = 0; + SourceFile->FileBufferPtr++; + Start = Ptr = SourceFile->FileBufferPtr; + PreviousBackslash = FALSE; + while (!EndOfFile (SourceFile)) { + if ((SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) && (PreviousBackslash == FALSE)) { + break; + } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) { + Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start); + PreviousBackslash = FALSE; + } else if (SourceFile->FileBufferPtr[0] == T_CHAR_BACKSLASH) { + PreviousBackslash = TRUE; + } else { + PreviousBackslash = FALSE; + } + + SourceFile->FileBufferPtr++; + Len++; + } + + if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { + Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start); + } else { + SourceFile->FileBufferPtr++; + } + // + // Now allocate memory for the string and save it off + // + String = (CHAR8 *) malloc ((Len + 1) * sizeof (CHAR8 )); + if (String == NULL) { + Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL); + return NULL; + } + // + // Copy the string from the file buffer to the local copy. + // We do no reformatting of it whatsoever at this point. + // + Ptr = String; + while (Len > 0) { + *Ptr = *Start; + Start++; + Ptr++; + Len--; + } + + *Ptr = 0; + return String; +} +#endif +STATIC +BOOLEAN +EndOfFile ( + SOURCE_FILE *SourceFile + ) +{ + // + // The file buffer pointer will typically get updated before the End-of-file flag in the + // source file structure, so check it first. + // + if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (CHAR8 )) { + SourceFile->EndOfFile = TRUE; + return TRUE; + } + + if (SourceFile->EndOfFile) { + return TRUE; + } + + return FALSE; +} + +#if 0 +STATIC +VOID +ProcessTokenInclude ( + SOURCE_FILE *SourceFile + ) +{ + CHAR8 IncludeFileName[MAX_PATH]; + CHAR8 *To; + UINTN Len; + BOOLEAN ReportedError; + SOURCE_FILE IncludedSourceFile; + + ReportedError = FALSE; + if (SkipWhiteSpace (SourceFile) == 0) { + Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL); + } + // + // Should be quoted file name + // + if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL); + goto FailDone; + } + + SourceFile->FileBufferPtr++; + // + // Copy the filename as ascii to our local string + // + To = IncludeFileName; + Len = 0; + while (!EndOfFile (SourceFile)) { + if ((SourceFile->FileBufferPtr[0] == T_CHAR_CR) || (SourceFile->FileBufferPtr[0] == T_CHAR_LF)) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL); + goto FailDone; + } + + if (SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { + SourceFile->FileBufferPtr++; + break; + } + // + // If too long, then report the error once and process until the closing quote + // + Len++; + if (!ReportedError && (Len >= sizeof (IncludeFileName))) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL); + ReportedError = TRUE; + } + + if (!ReportedError) { + *To = (CHAR8 ) SourceFile->FileBufferPtr[0]; + To++; + } + + SourceFile->FileBufferPtr++; + } + + if (!ReportedError) { + *To = 0; + memset ((CHAR8 *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE)); + strcpy (IncludedSourceFile.FileName, IncludeFileName); + ProcessIncludeFile (&IncludedSourceFile, SourceFile); + } + + return ; +FailDone: + // + // Error recovery -- skip to next # + // + SourceFile->SkipToHash = TRUE; +} +#endif +STATIC +BOOLEAN +IsWhiteSpace ( + SOURCE_FILE *SourceFile + ) +{ + switch (*SourceFile->FileBufferPtr) { + case T_CHAR_NULL: + case T_CHAR_CR: + case T_CHAR_SPACE: + case T_CHAR_TAB: + case T_CHAR_LF: + return TRUE; + + default: + return FALSE; + } +} + +UINTN +SkipWhiteSpace ( + SOURCE_FILE *SourceFile + ) +{ + UINTN Count; + + Count = 0; + while (!EndOfFile (SourceFile)) { + Count++; + switch (*SourceFile->FileBufferPtr) { + case T_CHAR_NULL: + case T_CHAR_CR: + case T_CHAR_SPACE: + case T_CHAR_TAB: + SourceFile->FileBufferPtr++; + break; + + case T_CHAR_LF: + SourceFile->FileBufferPtr++; + SourceFile->LineNum++; + break; + + default: + return Count - 1; + } + } + // + // Some tokens require trailing whitespace. If we're at the end of the + // file, then we count that as well. + // + if ((Count == 0) && (EndOfFile (SourceFile))) { + Count++; + } + + return Count; +} + +/** + Compare two strings for equality. The string pointed to by 'Buffer' may or may not be null-terminated, + so only compare up to the length of Str. + + @param Buffer pointer to first (possibly not null-terminated) string + @param Str pointer to null-terminated string to compare to Buffer + + @retval Number of bytes matched if exact match + @retval 0 if Buffer does not start with Str +**/ +STATIC +UINTN +t_strcmp ( + CHAR8 *Buffer, + CHAR8 *Str + ) +{ + UINTN Len; + + Len = 0; + while (*Str && (*Str == *Buffer)) { + Buffer++; + Str++; + Len++; + } + + if (*Str) { + return 0; + } + + return Len; +} + +STATIC +UINTN +t_strlen ( + CHAR8 *Str + ) +{ + UINTN Len; + Len = 0; + while (*Str) { + Len++; + Str++; + } + + return Len; +} + +STATIC +UINTN +t_strncmp ( + CHAR8 *Str1, + CHAR8 *Str2, + INTN Len + ) +{ + while (Len > 0) { + if (*Str1 != *Str2) { + return Len; + } + + Len--; + Str1++; + Str2++; + } + + return 0; +} + +STATIC +CHAR8 * +t_strcpy ( + CHAR8 *Dest, + CHAR8 *Src + ) +{ + CHAR8 *SaveDest; + SaveDest = Dest; + while (*Src) { + *Dest = *Src; + Dest++; + Src++; + } + + *Dest = 0; + return SaveDest; +} + +STATIC +VOID +RewindFile ( + SOURCE_FILE *SourceFile + ) +{ + SourceFile->LineNum = 1; + SourceFile->FileBufferPtr = SourceFile->FileBuffer; + SourceFile->EndOfFile = 0; +} + +STATIC +UINT32 +GetHexChars ( + CHAR8 *Buffer, + UINT32 BufferLen + ) +{ + UINT32 Len; + Len = 0; + while (!EndOfFile (&mGlobals.SourceFile) && (Len < BufferLen)) { + if (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + Buffer[Len] = mGlobals.SourceFile.FileBufferPtr[0]; + Len++; + mGlobals.SourceFile.FileBufferPtr++; + } else { + break; + } + } + // + // Null terminate if we can + // + if ((Len > 0) && (Len < BufferLen)) { + Buffer[Len] = 0; + } + + return Len; +} + +/** + Parse a GUID from the input stream. Stop when you discover white space. + + GUID styles + Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD + + @param GuidStyle Style of the following GUID token + @param Value pointer to EFI_GUID struct for output + + @retval TRUE GUID string parsed successfully + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetGuid ( + INTN GuidStyle, + EFI_GUID *Value + ) +{ + INT32 Value32; + UINT32 Index; + FILE_POSITION FPos; + CHAR8 TempString[20]; + CHAR8 TempString2[3]; + CHAR8 *From; + CHAR8 *To; + UINT32 Len; + BOOLEAN Status; + + Status = FALSE; + // + // Skip white space, then start parsing + // + SkipWhiteSpace (&mGlobals.SourceFile); + GetFilePosition (&FPos); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if (GuidStyle == PARSE_GUID_STYLE_5_FIELDS) { + // + // Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD + // + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 8)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data1 = Value32; + // + // Next two UINT16 fields + // + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 4)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data2 = (UINT16) Value32; + + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 4)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data3 = (UINT16) Value32; + // + // Parse the "AAAA" as two bytes + // + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 4)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data4[0] = (UINT8) (Value32 >> 8); + Value->Data4[1] = (UINT8) Value32; + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + // + // Read the last 6 bytes of the GUID + // + // + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 12)) { + goto Done; + } + // + // Insert leading 0's to make life easier + // + if (Len != 12) { + From = TempString + Len - 1; + To = TempString + 11; + TempString[12] = 0; + while (From >= TempString) { + *To = *From; + To--; + From--; + } + + while (To >= TempString) { + *To = '0'; + To--; + } + } + // + // Now parse each byte + // + TempString2[2] = 0; + for (Index = 0; Index < 6; Index++) { + // + // Copy the two characters from the input string to something + // we can parse. + // + TempString2[0] = TempString[Index * 2]; + TempString2[1] = TempString[Index * 2 + 1]; + sscanf (TempString2, "%x", &Value32); + Value->Data4[Index + 2] = (UINT8) Value32; + } + + Status = TRUE; + } else { + // + // Unsupported GUID style + // + return FALSE; + } + +Done: + if (Status == FALSE) { + SetFilePosition (&FPos); + } + + return Status; +} + +STATIC +STATUS +GetFilePosition ( + FILE_POSITION *Fpos + ) +{ + Fpos->FileBufferPtr = mGlobals.SourceFile.FileBufferPtr; + return STATUS_SUCCESS; +} + +STATIC +STATUS +SetFilePosition ( + FILE_POSITION *Fpos + ) +{ + // + // Should check range of pointer + // + mGlobals.SourceFile.FileBufferPtr = Fpos->FileBufferPtr; + return STATUS_SUCCESS; +} diff --git a/tools/src/GenFw/Common/src/SimpleFileParsing.h b/tools/src/GenFw/Common/src/SimpleFileParsing.h new file mode 100644 index 0000000..e699f05 --- /dev/null +++ b/tools/src/GenFw/Common/src/SimpleFileParsing.h @@ -0,0 +1,104 @@ +/** @file +Function prototypes and defines for the simple file parsing routines. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SIMPLE_FILE_PARSING_H_ +#define _SIMPLE_FILE_PARSING_H_ + +#include + +STATUS +SFPInit ( + VOID + ) +; + +STATUS +SFPOpenFile ( + CHAR8 *FileName + ) +; + +BOOLEAN +SFPIsKeyword ( + CHAR8 *Str + ) +; + +BOOLEAN +SFPIsToken ( + CHAR8 *Str + ) +; + +BOOLEAN +SFPGetNextToken ( + CHAR8 *Str, + UINTN Len + ) +; + +BOOLEAN +SFPGetGuidToken ( + CHAR8 *Str, + UINT32 Len + ) +; + +#define PARSE_GUID_STYLE_5_FIELDS 0 + +BOOLEAN +SFPGetGuid ( + INTN GuidStyle, + EFI_GUID *Value + ) +; + +BOOLEAN +SFPSkipToToken ( + CHAR8 *Str + ) +; + +BOOLEAN +SFPGetNumber ( + UINTN *Value + ) +; + +BOOLEAN +SFPGetQuotedString ( + CHAR8 *Str, + INTN Length + ) +; + +BOOLEAN +SFPIsEOF ( + VOID + ) +; + +STATUS +SFPCloseFile ( + VOID + ) +; + +UINTN +SFPGetLineNumber ( + VOID + ) +; + +CHAR8 * +SFPGetFileName ( + VOID + ) +; + +#endif // #ifndef _SIMPLE_FILE_PARSING_H_ diff --git a/tools/src/GenFw/Common/src/StringFuncs.c b/tools/src/GenFw/Common/src/StringFuncs.c new file mode 100644 index 0000000..90c5354 --- /dev/null +++ b/tools/src/GenFw/Common/src/StringFuncs.c @@ -0,0 +1,327 @@ +/** @file +Function prototypes and defines for string routines. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include "StringFuncs.h" + +// +// Functions implementations +// + +/** + Allocates a new string and copies 'String' to clone it + + @param String The string to clone + + @return CHAR8* - NULL if there are not enough resources +**/ +CHAR8* +CloneString ( + IN CHAR8 *String + ) +{ + CHAR8* NewString; + + NewString = malloc (strlen (String) + 1); + if (NewString != NULL) { + strcpy (NewString, String); + } + + return NewString; +} + +/** + Remove all comments, leading and trailing whitespace from the string. + + @param String The string to 'strip' + + @return EFI_STATUS +**/ +EFI_STATUS +StripInfDscStringInPlace ( + IN CHAR8 *String + ) +{ + CHAR8 *Pos; + + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Remove leading whitespace + // + for (Pos = String; isspace ((int)*Pos); Pos++) { + } + if (Pos != String) { + memmove (String, Pos, strlen (Pos) + 1); + } + + // + // Comment BUGBUGs! + // + // What about strings? Comment characters are okay in strings. + // What about multiline comments? + // + + Pos = (CHAR8 *) strstr (String, "//"); + if (Pos != NULL) { + *Pos = '\0'; + } + + Pos = (CHAR8 *) strchr (String, '#'); + if (Pos != NULL) { + *Pos = '\0'; + } + + // + // Remove trailing whitespace + // + for (Pos = String + strlen (String); + ((Pos - 1) >= String) && (isspace ((int)*(Pos - 1))); + Pos-- + ) { + } + *Pos = '\0'; + + return EFI_SUCCESS; +} + +/** + Creates and returns a 'split' STRING_LIST by splitting the string + on whitespace boundaries. + + @param String The string to 'split' + + @return EFI_STATUS +**/ +STRING_LIST* +SplitStringByWhitespace ( + IN CHAR8 *String + ) +{ + CHAR8 *Pos; + CHAR8 *EndOfSubString; + CHAR8 *EndOfString; + STRING_LIST *Output; + UINTN Item; + + String = CloneString (String); + if (String == NULL) { + return NULL; + } + EndOfString = String + strlen (String); + + Output = NewStringList (); + + for (Pos = String, Item = 0; Pos < EndOfString; Item++) { + while (isspace ((int)*Pos)) { + Pos++; + } + + for (EndOfSubString=Pos; + (*EndOfSubString != '\0') && !isspace ((int)*EndOfSubString); + EndOfSubString++ + ) { + } + + if (EndOfSubString == Pos) { + break; + } + + *EndOfSubString = '\0'; + + AppendCopyOfStringToList (&Output, Pos); + + Pos = EndOfSubString + 1; + } + + free (String); + return Output; +} + +/** + Creates a new STRING_LIST with 0 strings. + + @return STRING_LIST* - Null if there is not enough resources to create the object. +**/ +STRING_LIST* +NewStringList ( + ) +{ + STRING_LIST *NewList; + NewList = AllocateStringListStruct (0); + if (NewList != NULL) { + NewList->Count = 0; + } + return NewList; +} + +/** + Adds String to StringList. A new copy of String is made before it is + added to StringList. + + @return EFI_STATUS +**/ +EFI_STATUS +AppendCopyOfStringToList ( + IN OUT STRING_LIST **StringList, + IN CHAR8 *String + ) +{ + STRING_LIST *OldList; + STRING_LIST *NewList; + CHAR8 *NewString; + + OldList = *StringList; + NewList = AllocateStringListStruct (OldList->Count + 1); + if (NewList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewString = CloneString (String); + if (NewString == NULL) { + free (NewList); + return EFI_OUT_OF_RESOURCES; + } + + memcpy ( + NewList->Strings, + OldList->Strings, + sizeof (OldList->Strings[0]) * OldList->Count + ); + NewList->Count = OldList->Count + 1; + NewList->Strings[OldList->Count] = NewString; + + *StringList = NewList; + free (OldList); + + return EFI_SUCCESS; +} + +/** + Removes the last string from StringList and frees the memory associated + with it. + + @param StringList The string list to remove the string from + + @return EFI_STATUS +**/ +EFI_STATUS +RemoveLastStringFromList ( + IN STRING_LIST *StringList + ) +{ + if (StringList->Count == 0) { + return EFI_INVALID_PARAMETER; + } + + free (StringList->Strings[StringList->Count - 1]); + StringList->Count--; + return EFI_SUCCESS; +} + +/** + Allocates a STRING_LIST structure that can store StringCount strings. + + @param StringCount The number of strings that need to be stored + + @return EFI_STATUS +**/ +STRING_LIST* +AllocateStringListStruct ( + IN UINTN StringCount + ) +{ + return malloc (OFFSET_OF(STRING_LIST, Strings[StringCount + 1])); +} + +/** + Frees all memory associated with StringList. + + @param StringList The string list to free +**/ +VOID +FreeStringList ( + IN STRING_LIST *StringList + ) +{ + while (StringList->Count > 0) { + RemoveLastStringFromList (StringList); + } + + free (StringList); +} + +/** + Generates a string that represents the STRING_LIST + + @param StringList The string list to convert to a string + + @return CHAR8* - The string list represented with a single string. The returned + string must be freed by the caller. +**/ +CHAR8* +StringListToString ( + IN STRING_LIST *StringList + ) +{ + UINTN Count; + UINTN Length; + CHAR8 *NewString; + + Length = 2; + for (Count = 0; Count < StringList->Count; Count++) { + if (Count > 0) { + Length += 2; + } + Length += strlen (StringList->Strings[Count]) + 2; + } + + NewString = malloc (Length + 1); + if (NewString == NULL) { + return NewString; + } + NewString[0] = '\0'; + + strcat (NewString, "["); + for (Count = 0; Count < StringList->Count; Count++) { + if (Count > 0) { + strcat (NewString, ", "); + } + strcat (NewString, "\""); + strcat (NewString, StringList->Strings[Count]); + strcat (NewString, "\""); + } + strcat (NewString, "]"); + + return NewString; +} + +/** + Prints out the string list + + @param StringList The string list to print + + @return EFI_STATUS +**/ +VOID +PrintStringList ( + IN STRING_LIST *StringList + ) +{ + CHAR8* String; + String = StringListToString (StringList); + if (String != NULL) { + printf ("%s", String); + free (String); + } +} + + diff --git a/tools/src/GenFw/Common/src/StringFuncs.h b/tools/src/GenFw/Common/src/StringFuncs.h new file mode 100644 index 0000000..e29d9be --- /dev/null +++ b/tools/src/GenFw/Common/src/StringFuncs.h @@ -0,0 +1,167 @@ +/** @file +String routines implementation + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_STRING_FUNCS_H +#define _EFI_STRING_FUNCS_H + +#include +#include +#include + +// +// Common data structures +// +typedef struct { + UINTN Count; + // + // Actually this array can be 0 or more items (based on Count) + // + CHAR8* Strings[1]; +} STRING_LIST; + + +// +// Functions declarations +// + +/** + Allocates a new string and copies 'String' to clone it + + @param String The string to clone + + @return CHAR8* - NULL if there are not enough resources +**/ +CHAR8* +CloneString ( + IN CHAR8 *String + ) +; + +/** + Remove all comments, leading and trailing whitespace from the string. + + @param String The string to 'strip' + + @return EFI_STATUS +**/ +EFI_STATUS +StripInfDscStringInPlace ( + IN CHAR8 *String + ) +; + +/** + Creates and returns a 'split' STRING_LIST by splitting the string + on whitespace boundaries. + + @param String The string to 'split' + + @return EFI_STATUS +**/ +STRING_LIST* +SplitStringByWhitespace ( + IN CHAR8 *String + ) +; + +/** + Creates a new STRING_LIST with 0 strings. + + @return STRING_LIST* - Null if there is not enough resources to create the object. +**/ +STRING_LIST* +NewStringList ( + ) +; + + +/** + Adds String to StringList. A new copy of String is made before it is + added to StringList. + + @return EFI_STATUS +**/ +EFI_STATUS +AppendCopyOfStringToList ( + IN OUT STRING_LIST **StringList, + IN CHAR8 *String + ) +; + +/** + Removes the last string from StringList and frees the memory associated + with it. + + @param StringList The string list to remove the string from + + @return EFI_STATUS +**/ +EFI_STATUS +RemoveLastStringFromList ( + IN STRING_LIST *StringList + ) +; + + +/** + Allocates a STRING_LIST structure that can store StringCount strings. + + @param StringCount The number of strings that need to be stored + + @return EFI_STATUS +**/ +STRING_LIST* +AllocateStringListStruct ( + IN UINTN StringCount + ) +; + + +/** + Frees all memory associated with StringList. + + @param StringList The string list to free + + @return EFI_STATUS +**/ +VOID +FreeStringList ( + IN STRING_LIST *StringList + ) +; + + +/** + Generates a string that represents the STRING_LIST + + @param StringList The string list to convert to a string + + @return CHAR8* The string list represented with a single string. The returned + string must be freed by the caller. +**/ +CHAR8* +StringListToString ( + IN STRING_LIST *StringList + ) +; + + +/** + Prints out the string list + + @param StringList The string list to print +**/ +VOID +PrintStringList ( + IN STRING_LIST *StringList + ) +; + + + +#endif diff --git a/tools/src/GenFw/Common/src/TianoCompress.c b/tools/src/GenFw/Common/src/TianoCompress.c new file mode 100644 index 0000000..d53ee59 --- /dev/null +++ b/tools/src/GenFw/Common/src/TianoCompress.c @@ -0,0 +1,1558 @@ +/** @file +Compression routine. The compression algorithm is a mixture of LZ77 and Huffman +coding. LZ77 transforms the source data into a sequence of Original Characters +and Pointers to repeated strings. This sequence is further divided into Blocks +and Huffman codings are applied to each Block. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Compress.h" + +// +// Macro Definitions +// +#undef UINT8_MAX +typedef INT32 NODE; +#define UINT8_MAX 0xff +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 19 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define BLKSIZ (1U << 14) // 16 * 1024U +#define PERC_FLAG 0x80000000U +#define CODE_BIT 16 +#define NIL 0 +#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) +#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2) +#define CRCPOLY 0xA001 +#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT) + +// +// C: the Char&Len Set; P: the Position Set; T: the exTra Set +// +#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define NP (WNDBIT + 1) +#define PBIT 5 +#define NT (CODE_BIT + 3) +#define TBIT 5 +#if NT > NP +#define NPT NT +#else +#define NPT NP +#endif +// +// Function Prototypes +// + +STATIC +VOID +PutDword( + IN UINT32 Data + ); + +STATIC +EFI_STATUS +AllocateMemory ( + VOID + ); + +STATIC +VOID +FreeMemory ( + VOID + ); + +STATIC +VOID +InitSlide ( + VOID + ); + +STATIC +NODE +Child ( + IN NODE NodeQ, + IN UINT8 CharC + ); + +STATIC +VOID +MakeChild ( + IN NODE NodeQ, + IN UINT8 CharC, + IN NODE NodeR + ); + +STATIC +VOID +Split ( + IN NODE Old + ); + +STATIC +VOID +InsertNode ( + VOID + ); + +STATIC +VOID +DeleteNode ( + VOID + ); + +STATIC +VOID +GetNextMatch ( + VOID + ); + +STATIC +EFI_STATUS +Encode ( + VOID + ); + +STATIC +VOID +CountTFreq ( + VOID + ); + +STATIC +VOID +WritePTLen ( + IN INT32 Number, + IN INT32 nbit, + IN INT32 Special + ); + +STATIC +VOID +WriteCLen ( + VOID + ); + +STATIC +VOID +EncodeC ( + IN INT32 Value + ); + +STATIC +VOID +EncodeP ( + IN UINT32 Value + ); + +STATIC +VOID +SendBlock ( + VOID + ); + +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ); + +STATIC +VOID +HufEncodeStart ( + VOID + ); + +STATIC +VOID +HufEncodeEnd ( + VOID + ); + +STATIC +VOID +MakeCrcTable ( + VOID + ); + +STATIC +VOID +PutBits ( + IN INT32 Number, + IN UINT32 Value + ); + +STATIC +INT32 +FreadCrc ( + OUT UINT8 *Pointer, + IN INT32 Number + ); + +STATIC +VOID +InitPutBits ( + VOID + ); + +STATIC +VOID +CountLen ( + IN INT32 Index + ); + +STATIC +VOID +MakeLen ( + IN INT32 Root + ); + +STATIC +VOID +DownHeap ( + IN INT32 Index + ); + +STATIC +VOID +MakeCode ( + IN INT32 Number, + IN UINT8 Len[ ], + OUT UINT16 Code[] + ); + +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[ ], + OUT UINT16 CodeParm[] + ); + +// +// Global Variables +// +STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; + +STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; +STATIC INT16 mHeap[NC + 1]; +STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN; +STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc; +STATIC UINT32 mCompSize, mOrigSize; + +STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], mCrcTable[UINT8_MAX + 1], + mCFreq[2 * NC - 1], mCCode[NC], mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1]; + +STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; + +// +// functions +// + +/** + The internal implementation of [Efi/Tiano]Compress(). + + @param SrcBuffer The buffer storing the source data + @param SrcSize The size of source data + @param DstBuffer The buffer to store the compressed data + @param DstSize On input, the size of DstBuffer; On output, + the size of the actual compressed data. + @param Version The version of de/compression algorithm. + Version 1 for UEFI 2.0 de/compression algorithm. + Version 2 for Tiano de/compression algorithm. + + @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case, + DstSize contains the size needed. + @retval EFI_SUCCESS Compression is successful. + @retval EFI_OUT_OF_RESOURCES No resource to complete function. + @retval EFI_INVALID_PARAMETER Parameter supplied is wrong. +**/ +EFI_STATUS +TianoCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +{ + EFI_STATUS Status; + + // + // Initializations + // + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + mSrc = SrcBuffer; + mSrcUpperLimit = mSrc + SrcSize; + mDst = DstBuffer; + mDstUpperLimit = mDst +*DstSize; + + PutDword (0L); + PutDword (0L); + + MakeCrcTable (); + + mOrigSize = mCompSize = 0; + mCrc = INIT_CRC; + + // + // Compress it + // + Status = Encode (); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + // + // Fill in compressed size and original size + // + mDst = DstBuffer; + PutDword (mCompSize + 1); + PutDword (mOrigSize); + + // + // Return + // + if (mCompSize + 1 + 8 > *DstSize) { + *DstSize = mCompSize + 1 + 8; + return EFI_BUFFER_TOO_SMALL; + } else { + *DstSize = mCompSize + 1 + 8; + return EFI_SUCCESS; + } + +} + +/** + Put a dword to output stream + + @param Data the dword to put +**/ +STATIC +VOID +PutDword ( + IN UINT32 Data + ) +{ + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x08)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x10)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x18)) & 0xff); + } +} + +/** + Allocate memory spaces for data structures used in compression process + + @retval EFI_SUCCESS Memory is allocated successfully + @retval EFI_OUT_OF_RESOURCES Allocation fails +**/ +STATIC +EFI_STATUS +AllocateMemory ( + VOID + ) +{ + UINT32 Index; + + mText = malloc (WNDSIZ * 2 + MAXMATCH); + if (mText == NULL) { + return EFI_OUT_OF_RESOURCES; + } + for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) { + mText[Index] = 0; + } + + mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel)); + mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount)); + mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition)); + mParent = malloc (WNDSIZ * 2 * sizeof (*mParent)); + mPrev = malloc (WNDSIZ * 2 * sizeof (*mPrev)); + mNext = malloc ((MAX_HASH_VAL + 1) * sizeof (*mNext)); + if (mLevel == NULL || mChildCount == NULL || mPosition == NULL || + mParent == NULL || mPrev == NULL || mNext == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mBufSiz = BLKSIZ; + mBuf = malloc (mBufSiz); + while (mBuf == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + + mBuf = malloc (mBufSiz); + } + + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +/** + Called when compression is completed to free memory previously allocated. +**/ +VOID +FreeMemory ( + VOID + ) +{ + if (mText != NULL) { + free (mText); + } + + if (mLevel != NULL) { + free (mLevel); + } + + if (mChildCount != NULL) { + free (mChildCount); + } + + if (mPosition != NULL) { + free (mPosition); + } + + if (mParent != NULL) { + free (mParent); + } + + if (mPrev != NULL) { + free (mPrev); + } + + if (mNext != NULL) { + free (mNext); + } + + if (mBuf != NULL) { + free (mBuf); + } + + return ; +} + +/** + Initialize String Info Log data structures +**/ +STATIC +VOID +InitSlide ( + VOID + ) +{ + NODE Index; + + for (Index = WNDSIZ; Index <= WNDSIZ + UINT8_MAX; Index++) { + mLevel[Index] = 1; + mPosition[Index] = NIL; /* sentinel */ + } + + for (Index = WNDSIZ; Index < WNDSIZ * 2; Index++) { + mParent[Index] = NIL; + } + + mAvail = 1; + for (Index = 1; Index < WNDSIZ - 1; Index++) { + mNext[Index] = (NODE) (Index + 1); + } + + mNext[WNDSIZ - 1] = NIL; + for (Index = WNDSIZ * 2; Index <= MAX_HASH_VAL; Index++) { + mNext[Index] = NIL; + } +} + +/** + Find child node given the parent node and the edge character + + @param NodeQ the parent node + @param CharC the edge character + + @return The child node (NIL if not found) +**/ +STATIC +NODE +Child ( + IN NODE NodeQ, + IN UINT8 CharC + ) +{ + NODE NodeR; + + NodeR = mNext[HASH (NodeQ, CharC)]; + // + // sentinel + // + mParent[NIL] = NodeQ; + while (mParent[NodeR] != NodeQ) { + NodeR = mNext[NodeR]; + } + + return NodeR; +} + +/** + Create a new child for a given parent node. + + @param Parent the parent node + @param CharC the edge character + @param Child the child node +**/ +STATIC +VOID +MakeChild ( + IN NODE Parent, + IN UINT8 CharC, + IN NODE Child + ) +{ + NODE Node1; + NODE Node2; + + Node1 = (NODE) HASH (Parent, CharC); + Node2 = mNext[Node1]; + mNext[Node1] = Child; + mNext[Child] = Node2; + mPrev[Node2] = Child; + mPrev[Child] = Node1; + mParent[Child] = Parent; + mChildCount[Parent]++; +} + +/** + Split a node. + + @param Old the node to split +**/ +STATIC +VOID +Split ( + NODE Old + ) +{ + NODE New; + NODE TempNode; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + TempNode = mPrev[Old]; + mPrev[New] = TempNode; + mNext[TempNode] = New; + TempNode = mNext[Old]; + mNext[New] = TempNode; + mPrev[TempNode] = New; + mParent[New] = mParent[Old]; + mLevel[New] = (UINT8) mMatchLen; + mPosition[New] = mPos; + MakeChild (New, mText[mMatchPos + mMatchLen], Old); + MakeChild (New, mText[mPos + mMatchLen], mPos); +} + +/** + Insert string info for current position into the String Info Log +**/ +STATIC +VOID +InsertNode ( + VOID + ) +{ + NODE NodeQ; + NODE NodeR; + NODE Index2; + NODE NodeT; + UINT8 CharC; + UINT8 *t1; + UINT8 *t2; + + if (mMatchLen >= 4) { + // + // We have just got a long match, the target tree + // can be located by MatchPos + 1. Traverse the tree + // from bottom up to get to a proper starting point. + // The usage of PERC_FLAG ensures proper node deletion + // in DeleteNode() later. + // + mMatchLen--; + NodeR = (NODE) ((mMatchPos + 1) | WNDSIZ); + NodeQ = mParent[NodeR]; + while (NodeQ == NIL) { + NodeR = mNext[NodeR]; + NodeQ = mParent[NodeR]; + } + + while (mLevel[NodeQ] >= mMatchLen) { + NodeR = NodeQ; + NodeQ = mParent[NodeQ]; + } + + NodeT = NodeQ; + while (mPosition[NodeT] < 0) { + mPosition[NodeT] = mPos; + NodeT = mParent[NodeT]; + } + + if (NodeT < WNDSIZ) { + mPosition[NodeT] = (NODE) (mPos | (UINT32) PERC_FLAG); + } + } else { + // + // Locate the target tree + // + NodeQ = (NODE) (mText[mPos] + WNDSIZ); + CharC = mText[mPos + 1]; + NodeR = Child (NodeQ, CharC); + if (NodeR == NIL) { + MakeChild (NodeQ, CharC, mPos); + mMatchLen = 1; + return ; + } + + mMatchLen = 2; + } + // + // Traverse down the tree to find a match. + // Update Position value along the route. + // Node split or creation is involved. + // + for (;;) { + if (NodeR >= WNDSIZ) { + Index2 = MAXMATCH; + mMatchPos = NodeR; + } else { + Index2 = mLevel[NodeR]; + mMatchPos = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); + } + + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + + t1 = &mText[mPos + mMatchLen]; + t2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < Index2) { + if (*t1 != *t2) { + Split (NodeR); + return ; + } + + mMatchLen++; + t1++; + t2++; + } + + if (mMatchLen >= MAXMATCH) { + break; + } + + mPosition[NodeR] = mPos; + NodeQ = NodeR; + NodeR = Child (NodeQ, *t1); + if (NodeR == NIL) { + MakeChild (NodeQ, *t1, mPos); + return ; + } + + mMatchLen++; + } + + NodeT = mPrev[NodeR]; + mPrev[mPos] = NodeT; + mNext[NodeT] = mPos; + NodeT = mNext[NodeR]; + mNext[mPos] = NodeT; + mPrev[NodeT] = mPos; + mParent[mPos] = NodeQ; + mParent[NodeR] = NIL; + + // + // Special usage of 'next' + // + mNext[NodeR] = mPos; + +} + +/** + Delete outdated string info. (The Usage of PERC_FLAG + ensures a clean deletion) +**/ +STATIC +VOID +DeleteNode ( + VOID + ) +{ + NODE NodeQ; + NODE NodeR; + NODE NodeS; + NODE NodeT; + NODE NodeU; + + if (mParent[mPos] == NIL) { + return ; + } + + NodeR = mPrev[mPos]; + NodeS = mNext[mPos]; + mNext[NodeR] = NodeS; + mPrev[NodeS] = NodeR; + NodeR = mParent[mPos]; + mParent[mPos] = NIL; + if (NodeR >= WNDSIZ) { + return ; + } + + mChildCount[NodeR]--; + if (mChildCount[NodeR] > 1) { + return ; + } + + NodeT = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); + if (NodeT >= mPos) { + NodeT -= WNDSIZ; + } + + NodeS = NodeT; + NodeQ = mParent[NodeR]; + NodeU = mPosition[NodeQ]; + while (NodeU & (UINT32) PERC_FLAG) { + NodeU &= (UINT32)~PERC_FLAG; + if (NodeU >= mPos) { + NodeU -= WNDSIZ; + } + + if (NodeU > NodeS) { + NodeS = NodeU; + } + + mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ); + NodeQ = mParent[NodeQ]; + NodeU = mPosition[NodeQ]; + } + + if (NodeQ < WNDSIZ) { + if (NodeU >= mPos) { + NodeU -= WNDSIZ; + } + + if (NodeU > NodeS) { + NodeS = NodeU; + } + + mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ | (UINT32) PERC_FLAG); + } + + NodeS = Child (NodeR, mText[NodeT + mLevel[NodeR]]); + NodeT = mPrev[NodeS]; + NodeU = mNext[NodeS]; + mNext[NodeT] = NodeU; + mPrev[NodeU] = NodeT; + NodeT = mPrev[NodeR]; + mNext[NodeT] = NodeS; + mPrev[NodeS] = NodeT; + NodeT = mNext[NodeR]; + mPrev[NodeT] = NodeS; + mNext[NodeS] = NodeT; + mParent[NodeS] = mParent[NodeR]; + mParent[NodeR] = NIL; + mNext[NodeR] = mAvail; + mAvail = NodeR; +} + +/** + Advance the current position (read in new data if needed). + Delete outdated string info. Find a match string for current position. +**/ +STATIC +VOID +GetNextMatch ( + VOID + ) +{ + INT32 Number; + + mRemainder--; + mPos++; + if (mPos == WNDSIZ * 2) { + memmove (&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); + Number = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += Number; + mPos = WNDSIZ; + } + + DeleteNode (); + InsertNode (); +} + +/** + The main controlling routine for compression process. + + @retval EFI_SUCCESS The compression is successful + @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process +**/ +STATIC +EFI_STATUS +Encode ( + VOID + ) +{ + EFI_STATUS Status; + INT32 LastMatchLen; + NODE LastMatchPos; + + Status = AllocateMemory (); + if (EFI_ERROR (Status)) { + FreeMemory (); + return Status; + } + + InitSlide (); + + HufEncodeStart (); + + mRemainder = FreadCrc (&mText[WNDSIZ], WNDSIZ + MAXMATCH); + + mMatchLen = 0; + mPos = WNDSIZ; + InsertNode (); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + while (mRemainder > 0) { + LastMatchLen = mMatchLen; + LastMatchPos = mMatchPos; + GetNextMatch (); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) { + // + // Not enough benefits are gained by outputting a pointer, + // so just output the original character + // + Output (mText[mPos - 1], 0); + + } else { + + if (LastMatchLen == THRESHOLD) { + if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) { + Output (mText[mPos - 1], 0); + continue; + } + } + // + // Outputting a pointer is beneficial enough, do it. + // + Output ( + LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1) + ); + LastMatchLen--; + while (LastMatchLen > 0) { + GetNextMatch (); + LastMatchLen--; + } + + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd (); + FreeMemory (); + return EFI_SUCCESS; +} + +/** + Count the frequencies for the Extra Set +**/ +STATIC +VOID +CountTFreq ( + VOID + ) +{ + INT32 Index; + INT32 Index3; + INT32 Number; + INT32 Count; + + for (Index = 0; Index < NT; Index++) { + mTFreq[Index] = 0; + } + + Number = NC; + while (Number > 0 && mCLen[Number - 1] == 0) { + Number--; + } + + Index = 0; + while (Index < Number) { + Index3 = mCLen[Index++]; + if (Index3 == 0) { + Count = 1; + while (Index < Number && mCLen[Index] == 0) { + Index++; + Count++; + } + + if (Count <= 2) { + mTFreq[0] = (UINT16) (mTFreq[0] + Count); + } else if (Count <= 18) { + mTFreq[1]++; + } else if (Count == 19) { + mTFreq[0]++; + mTFreq[1]++; + } else { + mTFreq[2]++; + } + } else { + mTFreq[Index3 + 2]++; + } + } +} + +/** + Outputs the code length array for the Extra Set or the Position Set. + + @param Number the number of symbols + @param nbit the number of bits needed to represent 'n' + @param Special the special symbol that needs to be take care of +**/ +STATIC +VOID +WritePTLen ( + IN INT32 Number, + IN INT32 nbit, + IN INT32 Special + ) +{ + INT32 Index; + INT32 Index3; + + while (Number > 0 && mPTLen[Number - 1] == 0) { + Number--; + } + + PutBits (nbit, Number); + Index = 0; + while (Index < Number) { + Index3 = mPTLen[Index++]; + if (Index3 <= 6) { + PutBits (3, Index3); + } else { + PutBits (Index3 - 3, (1U << (Index3 - 3)) - 2); + } + + if (Index == Special) { + while (Index < 6 && mPTLen[Index] == 0) { + Index++; + } + + PutBits (2, (Index - 3) & 3); + } + } +} + +/** + Outputs the code length array for Char&Length Set +**/ +STATIC +VOID +WriteCLen ( + VOID + ) +{ + INT32 Index; + INT32 Index3; + INT32 Number; + INT32 Count; + + Number = NC; + while (Number > 0 && mCLen[Number - 1] == 0) { + Number--; + } + + PutBits (CBIT, Number); + Index = 0; + while (Index < Number) { + Index3 = mCLen[Index++]; + if (Index3 == 0) { + Count = 1; + while (Index < Number && mCLen[Index] == 0) { + Index++; + Count++; + } + + if (Count <= 2) { + for (Index3 = 0; Index3 < Count; Index3++) { + PutBits (mPTLen[0], mPTCode[0]); + } + } else if (Count <= 18) { + PutBits (mPTLen[1], mPTCode[1]); + PutBits (4, Count - 3); + } else if (Count == 19) { + PutBits (mPTLen[0], mPTCode[0]); + PutBits (mPTLen[1], mPTCode[1]); + PutBits (4, 15); + } else { + PutBits (mPTLen[2], mPTCode[2]); + PutBits (CBIT, Count - 20); + } + } else { + PutBits (mPTLen[Index3 + 2], mPTCode[Index3 + 2]); + } + } +} + +STATIC +VOID +EncodeC ( + IN INT32 Value + ) +{ + PutBits (mCLen[Value], mCCode[Value]); +} + +STATIC +VOID +EncodeP ( + IN UINT32 Value + ) +{ + UINT32 Index; + UINT32 NodeQ; + + Index = 0; + NodeQ = Value; + while (NodeQ) { + NodeQ >>= 1; + Index++; + } + + PutBits (mPTLen[Index], mPTCode[Index]); + if (Index > 1) { + PutBits (Index - 1, Value & (0xFFFFFFFFU >> (32 - Index + 1))); + } +} + +/** + Huffman code the block and output it. +**/ +STATIC +VOID +SendBlock ( + VOID + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 Index3; + UINT32 Flags; + UINT32 Root; + UINT32 Pos; + UINT32 Size; + Flags = 0; + + Root = MakeTree (NC, mCFreq, mCLen, mCCode); + Size = mCFreq[Root]; + PutBits (16, Size); + if (Root >= NC) { + CountTFreq (); + Root = MakeTree (NT, mTFreq, mPTLen, mPTCode); + if (Root >= NT) { + WritePTLen (NT, TBIT, 3); + } else { + PutBits (TBIT, 0); + PutBits (TBIT, Root); + } + + WriteCLen (); + } else { + PutBits (TBIT, 0); + PutBits (TBIT, 0); + PutBits (CBIT, 0); + PutBits (CBIT, Root); + } + + Root = MakeTree (NP, mPFreq, mPTLen, mPTCode); + if (Root >= NP) { + WritePTLen (NP, PBIT, -1); + } else { + PutBits (PBIT, 0); + PutBits (PBIT, Root); + } + + Pos = 0; + for (Index = 0; Index < Size; Index++) { + if (Index % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } else { + Flags <<= 1; + } + + if (Flags & (1U << (UINT8_BIT - 1))) { + EncodeC (mBuf[Pos++] + (1U << UINT8_BIT)); + Index3 = mBuf[Pos++]; + for (Index2 = 0; Index2 < 3; Index2++) { + Index3 <<= UINT8_BIT; + Index3 += mBuf[Pos++]; + } + + EncodeP (Index3); + } else { + EncodeC (mBuf[Pos++]); + } + } + + for (Index = 0; Index < NC; Index++) { + mCFreq[Index] = 0; + } + + for (Index = 0; Index < NP; Index++) { + mPFreq[Index] = 0; + } +} + +/** + Outputs an Original Character or a Pointer + + @param CharC The original character or the 'String Length' element of a Pointer + @param Pos The 'Position' field of a Pointer +**/ +STATIC +VOID +Output ( + IN UINT32 CharC, + IN UINT32 Pos + ) +{ + STATIC UINT32 CPos; + + if ((mOutputMask >>= 1) == 0) { + mOutputMask = 1U << (UINT8_BIT - 1); + // + // Check the buffer overflow per outputing UINT8_BIT symbols + // which is an Original Character or a Pointer. The biggest + // symbol is a Pointer which occupies 5 bytes. + // + if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) { + SendBlock (); + mOutputPos = 0; + } + + CPos = mOutputPos++; + mBuf[CPos] = 0; + } + + mBuf[mOutputPos++] = (UINT8) CharC; + mCFreq[CharC]++; + if (CharC >= (1U << UINT8_BIT)) { + mBuf[CPos] |= mOutputMask; + mBuf[mOutputPos++] = (UINT8) (Pos >> 24); + mBuf[mOutputPos++] = (UINT8) (Pos >> 16); + mBuf[mOutputPos++] = (UINT8) (Pos >> (UINT8_BIT)); + mBuf[mOutputPos++] = (UINT8) Pos; + CharC = 0; + while (Pos) { + Pos >>= 1; + CharC++; + } + + mPFreq[CharC]++; + } +} + +STATIC +VOID +HufEncodeStart ( + VOID + ) +{ + INT32 Index; + + for (Index = 0; Index < NC; Index++) { + mCFreq[Index] = 0; + } + + for (Index = 0; Index < NP; Index++) { + mPFreq[Index] = 0; + } + + mOutputPos = mOutputMask = 0; + InitPutBits (); + return ; +} + +STATIC +VOID +HufEncodeEnd ( + VOID + ) +{ + SendBlock (); + + // + // Flush remaining bits + // + PutBits (UINT8_BIT - 1, 0); + + return ; +} + +STATIC +VOID +MakeCrcTable ( + VOID + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 Temp; + + for (Index = 0; Index <= UINT8_MAX; Index++) { + Temp = Index; + for (Index2 = 0; Index2 < UINT8_BIT; Index2++) { + if (Temp & 1) { + Temp = (Temp >> 1) ^ CRCPOLY; + } else { + Temp >>= 1; + } + } + + mCrcTable[Index] = (UINT16) Temp; + } +} + +/** + Outputs rightmost n bits of x + + @param Number the rightmost n bits of the data is used + @param x the data +**/ +STATIC +VOID +PutBits ( + IN INT32 Number, + IN UINT32 Value + ) +{ + UINT8 Temp; + + while (Number >= mBitCount) { + // + // Number -= mBitCount should never equal to 32 + // + Temp = (UINT8) (mSubBitBuf | (Value >> (Number -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + + mCompSize++; + mSubBitBuf = 0; + mBitCount = UINT8_BIT; + } + + mSubBitBuf |= Value << (mBitCount -= Number); +} + +/** + Read in source data + + @param Pointer - the buffer to hold the data + @param Number - number of bytes to read + + @return number of bytes actually read +**/ +STATIC +INT32 +FreadCrc ( + OUT UINT8 *Pointer, + IN INT32 Number + ) +{ + INT32 Index; + + for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) { + *Pointer++ = *mSrc++; + } + + Number = Index; + + Pointer -= Number; + mOrigSize += Number; + Index--; + while (Index >= 0) { + UPDATE_CRC (*Pointer++); + Index--; + } + + return Number; +} + +STATIC +VOID +InitPutBits ( + VOID + ) +{ + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +/** + Count the number of each code length for a Huffman tree. + + @param Index the top node +**/ +STATIC +VOID +CountLen ( + IN INT32 Index + ) +{ + STATIC INT32 Depth = 0; + + if (Index < mN) { + mLenCnt[(Depth < 16) ? Depth : 16]++; + } else { + Depth++; + CountLen (mLeft[Index]); + CountLen (mRight[Index]); + Depth--; + } +} + +/** + Create code length array for a Huffman tree + + @param Root the root of the tree +**/ +STATIC +VOID +MakeLen ( + IN INT32 Root + ) +{ + INT32 Index; + INT32 Index3; + UINT32 Cum; + + for (Index = 0; Index <= 16; Index++) { + mLenCnt[Index] = 0; + } + + CountLen (Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + Cum = 0; + for (Index = 16; Index > 0; Index--) { + Cum += mLenCnt[Index] << (16 - Index); + } + + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (Index = 15; Index > 0; Index--) { + if (mLenCnt[Index] != 0) { + mLenCnt[Index]--; + mLenCnt[Index + 1] += 2; + break; + } + } + + Cum--; + } + + for (Index = 16; Index > 0; Index--) { + Index3 = mLenCnt[Index]; + Index3--; + while (Index3 >= 0) { + mLen[*mSortPtr++] = (UINT8) Index; + Index3--; + } + } +} + +STATIC +VOID +DownHeap ( + IN INT32 Index + ) +{ + INT32 Index2; + INT32 Index3; + + // + // priority queue: send Index-th entry down heap + // + Index3 = mHeap[Index]; + Index2 = 2 * Index; + while (Index2 <= mHeapSize) { + if (Index2 < mHeapSize && mFreq[mHeap[Index2]] > mFreq[mHeap[Index2 + 1]]) { + Index2++; + } + + if (mFreq[Index3] <= mFreq[mHeap[Index2]]) { + break; + } + + mHeap[Index] = mHeap[Index2]; + Index = Index2; + Index2 = 2 * Index; + } + + mHeap[Index] = (INT16) Index3; +} + +/** + Assign code to each symbol based on the code length array + + @param Number number of symbols + @param Len the code length array + @param Code stores codes for each symbol +**/ +STATIC +VOID +MakeCode ( + IN INT32 Number, + IN UINT8 Len[ ], + OUT UINT16 Code[] + ) +{ + INT32 Index; + UINT16 Start[18]; + + Start[1] = 0; + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16) ((Start[Index] + mLenCnt[Index]) << 1); + } + + for (Index = 0; Index < Number; Index++) { + Code[Index] = Start[Len[Index]]++; + } +} + +/** + Generates Huffman codes given a frequency distribution of symbols + + @param NParm number of symbols + @param FreqParm frequency of each symbol + @param LenParm code length for each symbol + @param CodeParm code for each symbol + + @return Root of the Huffman tree. +**/ +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[ ], + OUT UINT16 CodeParm[] + ) +{ + INT32 Index; + INT32 Index2; + INT32 Index3; + INT32 Avail; + + // + // make tree, calculate len[], return root + // + mN = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mN; + mHeapSize = 0; + mHeap[1] = 0; + for (Index = 0; Index < mN; Index++) { + mLen[Index] = 0; + if (mFreq[Index]) { + mHeapSize++; + mHeap[mHeapSize] = (INT16) Index; + } + } + + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + + for (Index = mHeapSize / 2; Index >= 1; Index--) { + // + // make priority queue + // + DownHeap (Index); + } + + mSortPtr = CodeParm; + do { + Index = mHeap[1]; + if (Index < mN) { + *mSortPtr++ = (UINT16) Index; + } + + mHeap[1] = mHeap[mHeapSize--]; + DownHeap (1); + Index2 = mHeap[1]; + if (Index2 < mN) { + *mSortPtr++ = (UINT16) Index2; + } + + Index3 = Avail++; + mFreq[Index3] = (UINT16) (mFreq[Index] + mFreq[Index2]); + mHeap[1] = (INT16) Index3; + DownHeap (1); + mLeft[Index3] = (UINT16) Index; + mRight[Index3] = (UINT16) Index2; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen (Index3); + MakeCode (NParm, LenParm, CodeParm); + + // + // return root + // + return Index3; +} diff --git a/tools/src/GenFw/GenFw/build-win.sh b/tools/src/GenFw/GenFw/build-win.sh new file mode 100755 index 0000000..3b22bb6 --- /dev/null +++ b/tools/src/GenFw/GenFw/build-win.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +mkdir obj 2>/dev/null +CFLAGS="-c -I ../Include/ -I ../Common/src -I src -I ../MdePkg/Include/X64/ -I ../MdePkg/Include -fshort-wchar -fno-strict-aliasing -fwrapv -fno-delete-null-pointer-checks -Wall -nostdlib -O2" + +for srcfile in src/*.c; do + srcfilebase=$(basename "$srcfile") + printf "\033[1;34mCompiling\033[1;97m\t==> $srcfilebase...\033[0m" + x86_64-w64-mingw32-gcc $CFLAGS $srcfile -o obj/${srcfilebase%.c}.o || exit 1 + printf "\033[1;32mdone\033[0m\n" +done + +x86_64-w64-mingw32-gcc -s -o GenFw.exe obj/*.o ../Common/libCommon.a diff --git a/tools/src/GenFw/GenFw/build.sh b/tools/src/GenFw/GenFw/build.sh new file mode 100755 index 0000000..a635f19 --- /dev/null +++ b/tools/src/GenFw/GenFw/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +mkdir obj 2>/dev/null +CFLAGS="-c -I ../Include/ -I ../Common/src -I src -I ../MdePkg/Include/X64/ -I ../MdePkg/Include -fshort-wchar -fno-strict-aliasing -fwrapv -fno-delete-null-pointer-checks -Wall -nostdlib -O2" + +for srcfile in src/*.c; do + srcfilebase=$(basename "$srcfile") + printf "\033[1;34mCompiling\033[1;97m\t==> $srcfilebase...\033[0m" + gcc $CFLAGS $srcfile -o obj/${srcfilebase%.c}.o || exit 1 + printf "\033[1;32mdone\033[0m\n" +done + +gcc -s -o GenFw obj/*.o ../Common/libCommon.a diff --git a/tools/src/GenFw/GenFw/clean.sh b/tools/src/GenFw/GenFw/clean.sh new file mode 100755 index 0000000..b45fcd4 --- /dev/null +++ b/tools/src/GenFw/GenFw/clean.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +rm obj/*.o 2>/dev/null +rm GenFw 2>/dev/null +rm GenFw.exe 2>/dev/null diff --git a/tools/src/GenFw/GenFw/src/Elf32Convert.c b/tools/src/GenFw/GenFw/src/Elf32Convert.c new file mode 100644 index 0000000..ccd5988 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/Elf32Convert.c @@ -0,0 +1,1170 @@ +/** @file +Elf32 Convert solution + +Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.
+Portions copyright (c) 2013, ARM Ltd. All rights reserved.
+Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GNUC__ +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "PeCoffLib.h" +#include "EfiUtilityMsgs.h" + +#include "GenFw.h" +#include "ElfConvert.h" +#include "Elf32Convert.h" + +STATIC +VOID +ScanSections32 ( + VOID + ); + +STATIC +BOOLEAN +WriteSections32 ( + SECTION_FILTER_TYPES FilterType + ); + +STATIC +VOID +WriteRelocations32 ( + VOID + ); + +STATIC +VOID +WriteDebug32 ( + VOID + ); + +STATIC +VOID +SetImageSize32 ( + VOID + ); + +STATIC +VOID +CleanUp32 ( + VOID + ); + +// +// Rename ELF32 structures to common names to help when porting to ELF64. +// +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Sym Elf_Sym; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Dyn Elf_Dyn; +#define ELFCLASS ELFCLASS32 +#define ELF_R_TYPE(r) ELF32_R_TYPE(r) +#define ELF_R_SYM(r) ELF32_R_SYM(r) + +// +// Well known ELF structures. +// +STATIC Elf_Ehdr *mEhdr; +STATIC Elf_Shdr *mShdrBase; +STATIC Elf_Phdr *mPhdrBase; + +// +// Coff information +// +STATIC UINT32 mCoffAlignment = 0x20; + +// +// PE section alignment. +// +STATIC const UINT16 mCoffNbrSections = 4; + +// +// ELF sections to offset in Coff file. +// +STATIC UINT32 *mCoffSectionsOffset = NULL; + +// +// Offsets in COFF file +// +STATIC UINT32 mNtHdrOffset; +STATIC UINT32 mTextOffset; +STATIC UINT32 mDataOffset; +STATIC UINT32 mHiiRsrcOffset; +STATIC UINT32 mRelocOffset; +STATIC UINT32 mDebugOffset; + +// +// Initialization Function +// +BOOLEAN +InitializeElf32 ( + UINT8 *FileBuffer, + ELF_FUNCTION_TABLE *ElfFunctions + ) +{ + // + // Initialize data pointer and structures. + // + mEhdr = (Elf_Ehdr*) FileBuffer; + + // + // Check the ELF32 specific header information. + // + if (mEhdr->e_ident[EI_CLASS] != ELFCLASS32) { + Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS32"); + return FALSE; + } + if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) { + Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB"); + return FALSE; + } + if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) { + Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN"); + return FALSE; + } + if (!((mEhdr->e_machine == EM_386) || (mEhdr->e_machine == EM_ARM) || (mEhdr->e_machine == EM_RISCV))) { + Warning (NULL, 0, 3000, "Unsupported", "ELF e_machine is not Elf32 machine."); + } + if (mEhdr->e_version != EV_CURRENT) { + Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT); + return FALSE; + } + + // + // Update section header pointers + // + mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff); + mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff); + + // + // Create COFF Section offset buffer and zero. + // + mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32)); + if (mCoffSectionsOffset == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + return FALSE; + } + memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32)); + + // + // Fill in function pointers. + // + ElfFunctions->ScanSections = ScanSections32; + ElfFunctions->WriteSections = WriteSections32; + ElfFunctions->WriteRelocations = WriteRelocations32; + ElfFunctions->WriteDebug = WriteDebug32; + ElfFunctions->SetImageSize = SetImageSize32; + ElfFunctions->CleanUp = CleanUp32; + + return TRUE; +} + + +// +// Header by Index functions +// +STATIC +Elf_Shdr* +GetShdrByIndex ( + UINT32 Num + ) +{ + if (Num >= mEhdr->e_shnum) { + Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num); + exit(EXIT_FAILURE); + } + + return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize); +} + +STATIC +Elf_Phdr* +GetPhdrByIndex ( + UINT32 num + ) +{ + if (num >= mEhdr->e_phnum) { + Error (NULL, 0, 3000, "Invalid", "GetPhdrByIndex: Index %u is too high.", num); + exit(EXIT_FAILURE); + } + + return (Elf_Phdr *)((UINT8*)mPhdrBase + num * mEhdr->e_phentsize); +} + +STATIC +UINT32 +CoffAlign ( + UINT32 Offset + ) +{ + return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1); +} + +STATIC +UINT32 +DebugRvaAlign ( + UINT32 Offset + ) +{ + return (Offset + 3) & ~3; +} + +// +// filter functions +// +STATIC +BOOLEAN +IsTextShdr ( + Elf_Shdr *Shdr + ) +{ + return (BOOLEAN) (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) || + ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC)); +} + +STATIC +BOOLEAN +IsHiiRsrcShdr ( + Elf_Shdr *Shdr + ) +{ + Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx); + + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0); +} + +STATIC +BOOLEAN +IsDataShdr ( + Elf_Shdr *Shdr + ) +{ + if (IsHiiRsrcShdr(Shdr)) { + return FALSE; + } + return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE); +} + +STATIC +BOOLEAN +IsStrtabShdr ( + Elf_Shdr *Shdr + ) +{ + Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx); + + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0); +} + +STATIC +Elf_Shdr * +FindStrtabShdr ( + VOID + ) +{ + UINT32 i; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsStrtabShdr(shdr)) { + return shdr; + } + } + return NULL; +} + +STATIC +const UINT8 * +GetSymName ( + Elf_Sym *Sym + ) +{ + Elf_Shdr *StrtabShdr; + UINT8 *StrtabContents; + BOOLEAN foundEnd; + UINT32 i; + + if (Sym->st_name == 0) { + return NULL; + } + + StrtabShdr = FindStrtabShdr(); + if (StrtabShdr == NULL) { + return NULL; + } + + assert(Sym->st_name < StrtabShdr->sh_size); + + StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset; + + foundEnd = FALSE; + for (i = Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) { + foundEnd = (BOOLEAN)(StrtabContents[i] == 0); + } + assert(foundEnd); + + return StrtabContents + Sym->st_name; +} + +// +// Elf functions interface implementation +// + +STATIC +VOID +ScanSections32 ( + VOID + ) +{ + UINT32 i; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + UINT32 CoffEntry; + UINT32 SectionCount; + BOOLEAN FoundSection; + + CoffEntry = 0; + mCoffOffset = 0; + + // + // Coff file start with a DOS header. + // + mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40; + mNtHdrOffset = mCoffOffset; + switch (mEhdr->e_machine) { + case EM_386: + case EM_ARM: + mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32); + break; + default: + VerboseMsg ("%u unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine); + mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32); + break; + } + + mTableOffset = mCoffOffset; + mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER); + + // + // Set mCoffAlignment to the maximum alignment of the input sections + // we care about + // + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (shdr->sh_addralign <= mCoffAlignment) { + continue; + } + if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) { + mCoffAlignment = (UINT32)shdr->sh_addralign; + } + } + + // + // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT + // + if (mCoffAlignment > MAX_COFF_ALIGNMENT) { + Error (NULL, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT."); + assert (FALSE); + } + + // + // Move the PE/COFF header right before the first section. This will help us + // save space when converting to TE. + // + if (mCoffAlignment > mCoffOffset) { + mNtHdrOffset += mCoffAlignment - mCoffOffset; + mTableOffset += mCoffAlignment - mCoffOffset; + mCoffOffset = mCoffAlignment; + } + + // + // First text sections. + // + mCoffOffset = CoffAlign(mCoffOffset); + mTextOffset = mCoffOffset; + FoundSection = FALSE; + SectionCount = 0; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsTextShdr(shdr)) { + if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { + // the alignment field is valid + if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { + // if the section address is aligned we must align PE/COFF + mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); + } + } + + /* Relocate entry. */ + if ((mEhdr->e_entry >= shdr->sh_addr) && + (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) { + CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr; + } + + // + // Set mTextOffset with the offset of the first '.text' section + // + if (!FoundSection) { + mTextOffset = mCoffOffset; + FoundSection = TRUE; + } + + mCoffSectionsOffset[i] = mCoffOffset; + mCoffOffset += shdr->sh_size; + SectionCount ++; + } + } + + if (!FoundSection && mOutImageType != FW_ACPI_IMAGE) { + Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section."); + assert (FALSE); + } + + mDebugOffset = DebugRvaAlign(mCoffOffset); + mCoffOffset = CoffAlign(mCoffOffset); + + if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) { + Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName); + } + + // + // Then data sections. + // + mDataOffset = mCoffOffset; + FoundSection = FALSE; + SectionCount = 0; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsDataShdr(shdr)) { + if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { + // the alignment field is valid + if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { + // if the section address is aligned we must align PE/COFF + mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); + } + } + + // + // Set mDataOffset with the offset of the first '.data' section + // + if (!FoundSection) { + mDataOffset = mCoffOffset; + FoundSection = TRUE; + } + + mCoffSectionsOffset[i] = mCoffOffset; + mCoffOffset += shdr->sh_size; + SectionCount ++; + } + } + + if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) { + Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName); + } + + // + // Make room for .debug data in .data (or .text if .data is empty) instead of + // putting it in a section of its own. This is explicitly allowed by the + // PE/COFF spec, and prevents bloat in the binary when using large values for + // section alignment. + // + if (SectionCount > 0) { + mDebugOffset = DebugRvaAlign(mCoffOffset); + } + mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + + strlen(mInImageName) + 1; + + mCoffOffset = CoffAlign(mCoffOffset); + if (SectionCount == 0) { + mDataOffset = mCoffOffset; + } + + // + // The HII resource sections. + // + mHiiRsrcOffset = mCoffOffset; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsHiiRsrcShdr(shdr)) { + if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { + // the alignment field is valid + if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { + // if the section address is aligned we must align PE/COFF + mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); + } + } + if (shdr->sh_size != 0) { + mHiiRsrcOffset = mCoffOffset; + mCoffSectionsOffset[i] = mCoffOffset; + mCoffOffset += shdr->sh_size; + mCoffOffset = CoffAlign(mCoffOffset); + SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset); + } + break; + } + } + + mRelocOffset = mCoffOffset; + + // + // Allocate base Coff file. Will be expanded later for relocations. + // + mCoffFile = (UINT8 *)malloc(mCoffOffset); + if (mCoffFile == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + } + assert (mCoffFile != NULL); + memset(mCoffFile, 0, mCoffOffset); + + // + // Fill headers. + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile; + DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE; + DosHdr->e_lfanew = mNtHdrOffset; + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset); + + NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE; + + switch (mEhdr->e_machine) { + case EM_386: + NtHdr->Pe32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; + NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + break; + case EM_ARM: + NtHdr->Pe32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMTHUMB_MIXED; + NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + break; + default: + VerboseMsg ("%s unknown e_machine type %hu. Assume IA-32", mInImageName, mEhdr->e_machine); + NtHdr->Pe32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; + NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + } + + NtHdr->Pe32.FileHeader.NumberOfSections = mCoffNbrSections; + NtHdr->Pe32.FileHeader.TimeDateStamp = (UINT32) time(NULL); + mImageTimeStamp = NtHdr->Pe32.FileHeader.TimeDateStamp; + NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0; + NtHdr->Pe32.FileHeader.NumberOfSymbols = 0; + NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader); + NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE + | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED + | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED + | EFI_IMAGE_FILE_32BIT_MACHINE; + + NtHdr->Pe32.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset; + NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset; + NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0; + NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry; + + NtHdr->Pe32.OptionalHeader.BaseOfCode = mTextOffset; + + NtHdr->Pe32.OptionalHeader.BaseOfData = mDataOffset; + NtHdr->Pe32.OptionalHeader.ImageBase = 0; + NtHdr->Pe32.OptionalHeader.SectionAlignment = mCoffAlignment; + NtHdr->Pe32.OptionalHeader.FileAlignment = mCoffAlignment; + NtHdr->Pe32.OptionalHeader.SizeOfImage = 0; + + NtHdr->Pe32.OptionalHeader.SizeOfHeaders = mTextOffset; + NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES; + + // + // Section headers. + // + if ((mDataOffset - mTextOffset) > 0) { + CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset, + EFI_IMAGE_SCN_CNT_CODE + | EFI_IMAGE_SCN_MEM_EXECUTE + | EFI_IMAGE_SCN_MEM_READ); + } else { + // Don't make a section of size 0. + NtHdr->Pe32.FileHeader.NumberOfSections--; + } + + if ((mHiiRsrcOffset - mDataOffset) > 0) { + CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_WRITE + | EFI_IMAGE_SCN_MEM_READ); + } else { + // Don't make a section of size 0. + NtHdr->Pe32.FileHeader.NumberOfSections--; + } + + if ((mRelocOffset - mHiiRsrcOffset) > 0) { + CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_READ); + + NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset; + NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset; + } else { + // Don't make a section of size 0. + NtHdr->Pe32.FileHeader.NumberOfSections--; + } + +} + +STATIC +BOOLEAN +WriteSections32 ( + SECTION_FILTER_TYPES FilterType + ) +{ + UINT32 Idx; + Elf_Shdr *SecShdr; + UINT32 SecOffset; + BOOLEAN (*Filter)(Elf_Shdr *); + + // + // Initialize filter pointer + // + switch (FilterType) { + case SECTION_TEXT: + Filter = IsTextShdr; + break; + case SECTION_HII: + Filter = IsHiiRsrcShdr; + break; + case SECTION_DATA: + Filter = IsDataShdr; + break; + default: + return FALSE; + } + + // + // First: copy sections. + // + for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { + Elf_Shdr *Shdr = GetShdrByIndex(Idx); + if ((*Filter)(Shdr)) { + switch (Shdr->sh_type) { + case SHT_PROGBITS: + /* Copy. */ + if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) { + return FALSE; + } + memcpy(mCoffFile + mCoffSectionsOffset[Idx], + (UINT8*)mEhdr + Shdr->sh_offset, + Shdr->sh_size); + break; + + case SHT_NOBITS: + memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size); + break; + + default: + // + // Ignore for unknown section type. + // + VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName, (unsigned)Shdr->sh_type); + break; + } + } + } + + // + // Second: apply relocations. + // + for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { + // + // Determine if this is a relocation section. + // + Elf_Shdr *RelShdr = GetShdrByIndex(Idx); + if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) { + continue; + } + + // + // Relocation section found. Now extract section information that the relocations + // apply to in the ELF data and the new COFF data. + // + SecShdr = GetShdrByIndex(RelShdr->sh_info); + SecOffset = mCoffSectionsOffset[RelShdr->sh_info]; + + // + // Only process relocations for the current filter type. + // + if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) { + UINT32 RelOffset; + + // + // Determine the symbol table referenced by the relocation data. + // + Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link); + UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset; + + // + // Process all relocation entries for this section. + // + for (RelOffset = 0; RelOffset < RelShdr->sh_size; RelOffset += RelShdr->sh_entsize) { + // + // Set pointer to relocation entry + // + Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelOffset); + + // + // Set pointer to symbol table entry associated with the relocation entry. + // + Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize); + + Elf_Shdr *SymShdr; + UINT8 *Targ; + UINT16 Address; + + // + // Check section header index found in symbol table and get the section + // header location. + // + if (Sym->st_shndx == SHN_UNDEF + || Sym->st_shndx >= mEhdr->e_shnum) { + const UINT8 *SymName = GetSymName(Sym); + if (SymName == NULL) { + SymName = (const UINT8 *)""; + } + continue; + } + SymShdr = GetShdrByIndex(Sym->st_shndx); + + // + // Convert the relocation data to a pointer into the coff file. + // + // Note: + // r_offset is the virtual address of the storage unit to be relocated. + // sh_addr is the virtual address for the base of the section. + // + Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr); + + // + // Determine how to handle each relocation type based on the machine type. + // + if (mEhdr->e_machine == EM_386) { + switch (ELF_R_TYPE(Rel->r_info)) { + case R_386_NONE: + break; + case R_386_32: + // + // Absolute relocation. + // Converts Targ from a absolute virtual address to the absolute + // COFF address. + // + *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + + mCoffSectionsOffset[Sym->st_shndx]; + break; + case R_386_PC32: + // + // Relative relocation: Symbol - Ip + Addend + // + *(UINT32 *)Targ = *(UINT32 *)Targ + + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr) + - (SecOffset - SecShdr->sh_addr); + break; + default: + Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_ARM) { + switch (ELF32_R_TYPE(Rel->r_info)) { + case R_ARM_RBASE: + // No relocation - no action required + // break skipped + + case R_ARM_PC24: + case R_ARM_REL32: + case R_ARM_XPC25: + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP19: + case R_ARM_CALL: + case R_ARM_JMP24: + case R_ARM_THM_JUMP24: + case R_ARM_PREL31: + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: + case R_ARM_THM_JMP6: + case R_ARM_THM_ALU_PREL_11_0: + case R_ARM_THM_PC12: + case R_ARM_REL32_NOI: + case R_ARM_ALU_PC_G0_NC: + case R_ARM_ALU_PC_G0: + case R_ARM_ALU_PC_G1_NC: + case R_ARM_ALU_PC_G1: + case R_ARM_ALU_PC_G2: + case R_ARM_LDR_PC_G1: + case R_ARM_LDR_PC_G2: + case R_ARM_LDRS_PC_G0: + case R_ARM_LDRS_PC_G1: + case R_ARM_LDRS_PC_G2: + case R_ARM_LDC_PC_G0: + case R_ARM_LDC_PC_G1: + case R_ARM_LDC_PC_G2: + case R_ARM_THM_JUMP11: + case R_ARM_THM_JUMP8: + case R_ARM_TLS_GD32: + case R_ARM_TLS_LDM32: + case R_ARM_TLS_IE32: + // Thease are all PC-relative relocations and don't require modification + // GCC does not seem to have the concept of a application that just needs to get relocated. + break; + + case R_ARM_THM_MOVW_ABS_NC: + // MOVW is only lower 16-bits of the addres + Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]); + ThumbMovtImmediatePatch ((UINT16 *)Targ, Address); + break; + + case R_ARM_THM_MOVT_ABS: + // MOVT is only upper 16-bits of the addres + Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16); + ThumbMovtImmediatePatch ((UINT16 *)Targ, Address); + break; + + case R_ARM_ABS32: + case R_ARM_RABS32: + // + // Absolute relocation. + // + *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info)); + } + } + } + } + } + + return TRUE; +} + +UINTN gMovwOffset = 0; + +STATIC +VOID +WriteRelocations32 ( + VOID + ) +{ + UINT32 Index; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + EFI_IMAGE_DATA_DIRECTORY *Dir; + BOOLEAN FoundRelocations; + Elf_Dyn *Dyn; + Elf_Rel *Rel; + UINTN RelElementSize; + UINTN RelSize; + UINTN RelOffset; + UINTN K; + Elf32_Phdr *DynamicSegment; + + for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) { + Elf_Shdr *RelShdr = GetShdrByIndex(Index); + if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) { + Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info); + if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) { + UINT32 RelIdx; + + FoundRelocations = TRUE; + for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) { + Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx); + + if (mEhdr->e_machine == EM_386) { + switch (ELF_R_TYPE(Rel->r_info)) { + case R_386_NONE: + case R_386_PC32: + // + // No fixup entry required. + // + break; + case R_386_32: + // + // Creates a relative relocation entry from the absolute entry. + // + CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr), + EFI_IMAGE_REL_BASED_HIGHLOW); + break; + default: + Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_ARM) { + switch (ELF32_R_TYPE(Rel->r_info)) { + case R_ARM_RBASE: + // No relocation - no action required + // break skipped + + case R_ARM_PC24: + case R_ARM_REL32: + case R_ARM_XPC25: + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP19: + case R_ARM_CALL: + case R_ARM_JMP24: + case R_ARM_THM_JUMP24: + case R_ARM_PREL31: + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: + case R_ARM_THM_JMP6: + case R_ARM_THM_ALU_PREL_11_0: + case R_ARM_THM_PC12: + case R_ARM_REL32_NOI: + case R_ARM_ALU_PC_G0_NC: + case R_ARM_ALU_PC_G0: + case R_ARM_ALU_PC_G1_NC: + case R_ARM_ALU_PC_G1: + case R_ARM_ALU_PC_G2: + case R_ARM_LDR_PC_G1: + case R_ARM_LDR_PC_G2: + case R_ARM_LDRS_PC_G0: + case R_ARM_LDRS_PC_G1: + case R_ARM_LDRS_PC_G2: + case R_ARM_LDC_PC_G0: + case R_ARM_LDC_PC_G1: + case R_ARM_LDC_PC_G2: + case R_ARM_THM_JUMP11: + case R_ARM_THM_JUMP8: + case R_ARM_TLS_GD32: + case R_ARM_TLS_LDM32: + case R_ARM_TLS_IE32: + // Thease are all PC-relative relocations and don't require modification + break; + + case R_ARM_THM_MOVW_ABS_NC: + CoffAddFixup ( + mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr), + EFI_IMAGE_REL_BASED_ARM_MOV32T + ); + + // PE/COFF treats MOVW/MOVT relocation as single 64-bit instruction + // Track this address so we can log an error for unsupported sequence of MOVW/MOVT + gMovwOffset = mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr); + break; + + case R_ARM_THM_MOVT_ABS: + if ((gMovwOffset + 4) != (mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr))) { + Error (NULL, 0, 3000, "Not Supported", "PE/COFF requires MOVW+MOVT instruction sequence %x +4 != %x.", gMovwOffset, mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr)); + } + break; + + case R_ARM_ABS32: + case R_ARM_RABS32: + CoffAddFixup ( + mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr), + EFI_IMAGE_REL_BASED_HIGHLOW + ); + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info)); + } + } else { + Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine); + } + } + } + } + } + + if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) { + /* Try again, but look for PT_DYNAMIC instead of SHT_REL */ + + for (Index = 0; Index < mEhdr->e_phnum; Index++) { + RelElementSize = 0; + RelSize = 0; + RelOffset = 0; + + DynamicSegment = GetPhdrByIndex (Index); + + if (DynamicSegment->p_type == PT_DYNAMIC) { + Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset); + + while (Dyn->d_tag != DT_NULL) { + switch (Dyn->d_tag) { + case DT_REL: + RelOffset = Dyn->d_un.d_val; + break; + + case DT_RELSZ: + RelSize = Dyn->d_un.d_val; + break; + + case DT_RELENT: + RelElementSize = Dyn->d_un.d_val; + break; + + default: + break; + } + Dyn++; + } + if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) { + Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName); + } + + for (Index = 0; Index < mEhdr->e_shnum; Index++) { + Elf_Shdr *shdr = GetShdrByIndex(Index); + + // + // The PT_DYNAMIC section contains DT_REL relocations whose r_offset + // field is relative to the base of a segment (or the entire image), + // and not to the base of an ELF input section as is the case for + // SHT_REL sections. This means that we cannot fix up such relocations + // unless we cross-reference ELF sections and segments, considering + // that the output placement recorded in mCoffSectionsOffset[] is + // section based, not segment based. + // + // Fortunately, there is a simple way around this: we require that the + // in-memory layout of the ELF and PE/COFF versions of the binary is + // identical. That way, r_offset will retain its validity as a PE/COFF + // image offset, and we can record it in the COFF fixup table + // unmodified. + // + if (shdr->sh_addr != mCoffSectionsOffset[Index]) { + Error (NULL, 0, 3000, + "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.", + mInImageName); + } + } + + for (K = 0; K < RelSize; K += RelElementSize) { + + if (DynamicSegment->p_paddr == 0) { + // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL + // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools + Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K); + } else { + // This is how it reads in the generic ELF specification + Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K); + } + + switch (ELF32_R_TYPE (Rel->r_info)) { + case R_ARM_RBASE: + break; + + case R_ARM_RABS32: + CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW); + break; + + default: + Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unknown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info)); + break; + } + } + break; + } + } + } + + // + // Pad by adding empty entries. + // + while (mCoffOffset & (mCoffAlignment - 1)) { + CoffAddFixupEntry(0); + } + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + Dir->Size = mCoffOffset - mRelocOffset; + if (Dir->Size == 0) { + // If no relocations, null out the directory entry and don't add the .reloc section + Dir->VirtualAddress = 0; + NtHdr->Pe32.FileHeader.NumberOfSections--; + } else { + Dir->VirtualAddress = mRelocOffset; + CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_DISCARDABLE + | EFI_IMAGE_SCN_MEM_READ); + } + +} + +STATIC +VOID +WriteDebug32 ( + VOID + ) +{ + UINT32 Len; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + EFI_IMAGE_DATA_DIRECTORY *DataDir; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir; + EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10; + + Len = strlen(mInImageName) + 1; + + Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset); + Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW; + Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len; + Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + + Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1); + Nb10->Signature = CODEVIEW_SIGNATURE_NB10; + strcpy ((char *)(Nb10 + 1), mInImageName); + + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]; + DataDir->VirtualAddress = mDebugOffset; + DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); +} + +STATIC +VOID +SetImageSize32 ( + VOID + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + + // + // Set image size + // + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset; +} + +STATIC +VOID +CleanUp32 ( + VOID + ) +{ + if (mCoffSectionsOffset != NULL) { + free (mCoffSectionsOffset); + } +} + + diff --git a/tools/src/GenFw/GenFw/src/Elf32Convert.h b/tools/src/GenFw/GenFw/src/Elf32Convert.h new file mode 100644 index 0000000..d1b1512 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/Elf32Convert.h @@ -0,0 +1,19 @@ +/** @file +Header file for Elf32 Convert solution + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ELF_32_CONVERT_ +#define _ELF_32_CONVERT_ + +BOOLEAN +InitializeElf32 ( + UINT8 *FileBuffer, + ELF_FUNCTION_TABLE *ElfFunctions + ); + +#endif diff --git a/tools/src/GenFw/GenFw/src/Elf64Convert.c b/tools/src/GenFw/GenFw/src/Elf64Convert.c new file mode 100644 index 0000000..97ae3a7 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/Elf64Convert.c @@ -0,0 +1,2392 @@ +/** @file +Elf64 convert solution + +Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.
+Portions copyright (c) 2013-2022, ARM Ltd. All rights reserved.
+Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GNUC__ +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "PeCoffLib.h" +#include "EfiUtilityMsgs.h" + +#include "GenFw.h" +#include "ElfConvert.h" +#include "Elf64Convert.h" + +STATIC +VOID +ScanSections64 ( + VOID + ); + +STATIC +BOOLEAN +WriteSections64 ( + SECTION_FILTER_TYPES FilterType + ); + +STATIC +VOID +WriteRelocations64 ( + VOID + ); + +STATIC +VOID +WriteDebug64 ( + VOID + ); + +STATIC +VOID +WriteExport64 ( + VOID + ); + +STATIC +VOID +SetImageSize64 ( + VOID + ); + +STATIC +VOID +CleanUp64 ( + VOID + ); + +// +// Rename ELF32 structures to common names to help when porting to ELF64. +// +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; +typedef Elf64_Sym Elf_Sym; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Dyn Elf_Dyn; +#define ELFCLASS ELFCLASS64 +#define ELF_R_TYPE(r) ELF64_R_TYPE(r) +#define ELF_R_SYM(r) ELF64_R_SYM(r) + +// +// Well known ELF structures. +// +STATIC Elf_Ehdr *mEhdr; +STATIC Elf_Shdr *mShdrBase; +STATIC Elf_Phdr *mPhdrBase; + +// +// GOT information +// +STATIC Elf_Shdr *mGOTShdr = NULL; +STATIC UINT32 mGOTShindex = 0; +STATIC UINT32 *mGOTCoffEntries = NULL; +STATIC UINT32 mGOTMaxCoffEntries = 0; +STATIC UINT32 mGOTNumCoffEntries = 0; + +// +// Coff information +// +STATIC UINT32 mCoffAlignment = 0x20; + +// +// PE section alignment. +// +STATIC UINT16 mCoffNbrSections = 4; + +// +// ELF sections to offset in Coff file. +// +STATIC UINT32 *mCoffSectionsOffset = NULL; + +// +// Offsets in COFF file +// +STATIC UINT32 mNtHdrOffset; +STATIC UINT32 mTextOffset; +STATIC UINT32 mDataOffset; +STATIC UINT32 mHiiRsrcOffset; +STATIC UINT32 mRelocOffset; +STATIC UINT32 mDebugOffset; +STATIC UINT32 mExportOffset; +// +// Used for RISC-V relocations. +// +STATIC UINT8 *mRiscVPass1Targ = NULL; +STATIC Elf_Shdr *mRiscVPass1Sym = NULL; +STATIC Elf64_Half mRiscVPass1SymSecIndex = 0; +STATIC INT32 mRiscVPass1Offset; +STATIC INT32 mRiscVPass1GotFixup; + +// +// Used for Export section. +// +STATIC UINT32 mExportSize; +STATIC UINT32 mExportRVA[PRM_MODULE_EXPORT_SYMBOL_NUM]; +STATIC UINT32 mExportSymNum; +STATIC CHAR8 mExportSymName[PRM_MODULE_EXPORT_SYMBOL_NUM][PRM_HANDLER_NAME_MAXIMUM_LENGTH]; + +// +// Initialization Function +// +BOOLEAN +InitializeElf64 ( + UINT8 *FileBuffer, + ELF_FUNCTION_TABLE *ElfFunctions + ) +{ + // + // Initialize data pointer and structures. + // + VerboseMsg ("Set EHDR"); + mEhdr = (Elf_Ehdr*) FileBuffer; + + // + // Check the ELF64 specific header information. + // + VerboseMsg ("Check ELF64 Header Information"); + if (mEhdr->e_ident[EI_CLASS] != ELFCLASS64) { + Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64"); + return FALSE; + } + if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) { + Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB"); + return FALSE; + } + if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) { + Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN"); + return FALSE; + } + if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64) || (mEhdr->e_machine == EM_RISCV64) || (mEhdr->e_machine == EM_LOONGARCH))) { + Warning (NULL, 0, 3000, "Unsupported", "ELF e_machine is not Elf64 machine."); + } + if (mEhdr->e_version != EV_CURRENT) { + Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT); + return FALSE; + } + + if (mExportFlag) { + if ((mEhdr->e_machine != EM_X86_64) && (mEhdr->e_machine != EM_AARCH64)) { + Error (NULL, 0, 3000, "Unsupported", "--prm option currently only supports X64 and AArch64 archs."); + return FALSE; + } + } + + // + // Update section header pointers + // + VerboseMsg ("Update Header Pointers"); + mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff); + mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff); + + // + // Create COFF Section offset buffer and zero. + // + VerboseMsg ("Create COFF Section Offset Buffer"); + mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32)); + if (mCoffSectionsOffset == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + return FALSE; + } + memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32)); + + // + // Fill in function pointers. + // + VerboseMsg ("Fill in Function Pointers"); + ElfFunctions->ScanSections = ScanSections64; + ElfFunctions->WriteSections = WriteSections64; + ElfFunctions->WriteRelocations = WriteRelocations64; + ElfFunctions->WriteDebug = WriteDebug64; + ElfFunctions->SetImageSize = SetImageSize64; + ElfFunctions->CleanUp = CleanUp64; + + if (mExportFlag) { + mCoffNbrSections ++; + ElfFunctions->WriteExport = WriteExport64; + } + + return TRUE; +} + + +// +// Header by Index functions +// +STATIC +Elf_Shdr* +GetShdrByIndex ( + UINT32 Num + ) +{ + if (Num >= mEhdr->e_shnum) { + Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num); + exit(EXIT_FAILURE); + } + + return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize); +} + +STATIC +UINT32 +CoffAlign ( + UINT32 Offset + ) +{ + return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1); +} + +STATIC +UINT32 +DebugRvaAlign ( + UINT32 Offset + ) +{ + return (Offset + 3) & ~3; +} + +// +// filter functions +// +STATIC +BOOLEAN +IsTextShdr ( + Elf_Shdr *Shdr + ) +{ + return (BOOLEAN) (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) || + ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC)); +} + +STATIC +BOOLEAN +IsHiiRsrcShdr ( + Elf_Shdr *Shdr + ) +{ + Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx); + + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0); +} + +STATIC +BOOLEAN +IsSymbolShdr ( + Elf_Shdr *Shdr + ) +{ + Elf_Shdr *Namehdr = GetShdrByIndex(mEhdr->e_shstrndx); + + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0); +} + +STATIC +BOOLEAN +IsDataShdr ( + Elf_Shdr *Shdr + ) +{ + if (IsHiiRsrcShdr(Shdr)) { + return FALSE; + } + return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE); +} + +STATIC +BOOLEAN +IsStrtabShdr ( + Elf_Shdr *Shdr + ) +{ + Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx); + + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0); +} + +STATIC +Elf_Shdr * +FindStrtabShdr ( + VOID + ) +{ + UINT32 i; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsStrtabShdr(shdr)) { + return shdr; + } + } + return NULL; +} + +STATIC +const UINT8 * +GetSymName ( + Elf_Sym *Sym + ) +{ + Elf_Shdr *StrtabShdr; + UINT8 *StrtabContents; + BOOLEAN foundEnd; + UINT32 i; + + if (Sym->st_name == 0) { + return NULL; + } + + StrtabShdr = FindStrtabShdr(); + if (StrtabShdr == NULL) { + return NULL; + } + + assert(Sym->st_name < StrtabShdr->sh_size); + + StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset; + + foundEnd = FALSE; + for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) { + foundEnd = (BOOLEAN)(StrtabContents[i] == 0); + } + assert(foundEnd); + + return StrtabContents + Sym->st_name; +} + +// +// Get Prm Handler number and name +// +STATIC +VOID +FindPrmHandler ( + UINT64 Offset + ) +{ + PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER *PrmExport; + PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *PrmHandler; + UINT32 HandlerNum; + + PrmExport = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER*)((UINT8*)mEhdr + Offset); + PrmHandler = (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *)(PrmExport + 1); + + for (HandlerNum = 0; HandlerNum < PrmExport->NumberPrmHandlers; HandlerNum++) { + strcpy(mExportSymName[mExportSymNum], PrmHandler->PrmHandlerName); + mExportSymNum ++; + PrmHandler += 1; + + // + // Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1) + // + if (mExportSymNum >= (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)) { + Error (NULL, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum); + exit(EXIT_FAILURE); + } + } +} + +// +// Find the ELF section hosting the GOT from an ELF Rva +// of a single GOT entry. Normally, GOT is placed in +// ELF .text section, so assume once we find in which +// section the GOT is, all GOT entries are there, and +// just verify this. +// +STATIC +VOID +FindElfGOTSectionFromGOTEntryElfRva ( + Elf64_Addr GOTEntryElfRva + ) +{ + UINT32 i; + if (mGOTShdr != NULL) { + if (GOTEntryElfRva >= mGOTShdr->sh_addr && + GOTEntryElfRva < mGOTShdr->sh_addr + mGOTShdr->sh_size) { + return; + } + Error (NULL, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections."); + exit(EXIT_FAILURE); + } + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (GOTEntryElfRva >= shdr->sh_addr && + GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) { + mGOTShdr = shdr; + mGOTShindex = i; + return; + } + } + Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva); + exit(EXIT_FAILURE); +} + +// +// Stores locations of GOT entries in COFF image. +// Returns TRUE if GOT entry is new. +// Simple implementation as number of GOT +// entries is expected to be low. +// + +STATIC +BOOLEAN +AccumulateCoffGOTEntries ( + UINT32 GOTCoffEntry + ) +{ + UINT32 i; + if (mGOTCoffEntries != NULL) { + for (i = 0; i < mGOTNumCoffEntries; i++) { + if (mGOTCoffEntries[i] == GOTCoffEntry) { + return FALSE; + } + } + } + if (mGOTCoffEntries == NULL) { + mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries); + if (mGOTCoffEntries == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + } + assert (mGOTCoffEntries != NULL); + mGOTMaxCoffEntries = 5; + mGOTNumCoffEntries = 0; + } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) { + mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * mGOTMaxCoffEntries * sizeof *mGOTCoffEntries); + if (mGOTCoffEntries == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + } + assert (mGOTCoffEntries != NULL); + mGOTMaxCoffEntries += mGOTMaxCoffEntries; + } + mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry; + return TRUE; +} + +// +// 32-bit Unsigned integer comparator for qsort. +// +STATIC +int +UINT32Comparator ( + const void* lhs, + const void* rhs + ) +{ + if (*(const UINT32*)lhs < *(const UINT32*)rhs) { + return -1; + } + return *(const UINT32*)lhs > *(const UINT32*)rhs; +} + +// +// Emit accumulated Coff GOT entry relocations into +// Coff image. This function performs its job +// once and then releases the entry list, so +// it can safely be called multiple times. +// +STATIC +VOID +EmitGOTRelocations ( + VOID + ) +{ + UINT32 i; + if (mGOTCoffEntries == NULL) { + return; + } + // + // Emit Coff relocations with Rvas ordered. + // + qsort( + mGOTCoffEntries, + mGOTNumCoffEntries, + sizeof *mGOTCoffEntries, + UINT32Comparator); + for (i = 0; i < mGOTNumCoffEntries; i++) { + VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries[i]); + CoffAddFixup( + mGOTCoffEntries[i], + EFI_IMAGE_REL_BASED_DIR64); + } + free(mGOTCoffEntries); + mGOTCoffEntries = NULL; + mGOTMaxCoffEntries = 0; + mGOTNumCoffEntries = 0; +} +// +// RISC-V 64 specific Elf WriteSection function. +// +STATIC +VOID +WriteSectionRiscV64 ( + Elf_Rela *Rel, + UINT8 *Targ, + Elf_Shdr *SymShdr, + Elf_Sym *Sym + ) +{ + UINT32 Value; + UINT32 Value2; + Elf64_Addr GOTEntryRva; + + switch (ELF_R_TYPE(Rel->r_info)) { + case R_RISCV_NONE: + break; + + case R_RISCV_32: + *(UINT64 *)Targ = Sym->st_value + Rel->r_addend; + break; + + case R_RISCV_64: + *(UINT64 *)Targ = Sym->st_value + Rel->r_addend; + break; + + case R_RISCV_HI20: + mRiscVPass1Targ = Targ; + mRiscVPass1Sym = SymShdr; + mRiscVPass1SymSecIndex = Sym->st_shndx; + break; + + case R_RISCV_LO12_I: + if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) { + Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12); + Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12)); + if (Value2 & (RISCV_IMM_REACH/2)) { + Value2 |= ~(RISCV_IMM_REACH-1); + } + Value += Value2; + Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + Value2 = RISCV_CONST_HIGH_PART (Value); + *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \ + (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12)); + *(UINT32 *)Targ = (RV_X (Value, 0, 12) << 20) | \ + (RV_X (*(UINT32 *)Targ, 0, 20)); + } + mRiscVPass1Sym = NULL; + mRiscVPass1Targ = NULL; + mRiscVPass1SymSecIndex = 0; + break; + + case R_RISCV_LO12_S: + if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) { + Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12); + Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5) | (RV_X(*(UINT32 *)Targ, 25, 7) << 5)); + if (Value2 & (RISCV_IMM_REACH/2)) { + Value2 |= ~(RISCV_IMM_REACH-1); + } + Value += Value2; + Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + Value2 = RISCV_CONST_HIGH_PART (Value); + *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \ + (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12)); + Value2 = *(UINT32 *)Targ & 0x01fff07f; + Value &= RISCV_IMM_REACH - 1; + *(UINT32 *)Targ = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25))); + } + mRiscVPass1Sym = NULL; + mRiscVPass1Targ = NULL; + mRiscVPass1SymSecIndex = 0; + break; + + case R_RISCV_GOT_HI20: + GOTEntryRva = (Sym->st_value - Rel->r_offset); + mRiscVPass1Offset = RV_X(GOTEntryRva, 0, 12); + Value = (UINT32)RV_X(GOTEntryRva, 12, 20); + *(UINT32 *)Targ = (Value << 12) | (RV_X(*(UINT32*)Targ, 0, 12)); + + mRiscVPass1Targ = Targ; + mRiscVPass1Sym = SymShdr; + mRiscVPass1SymSecIndex = Sym->st_shndx; + mRiscVPass1GotFixup = 1; + break; + + case R_RISCV_PCREL_HI20: + mRiscVPass1Targ = Targ; + mRiscVPass1Sym = SymShdr; + mRiscVPass1SymSecIndex = Sym->st_shndx; + + Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20)); + break; + + case R_RISCV_PCREL_LO12_S: + if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) { + int i; + Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20)); + + Value = ((UINT32)(RV_X(*(UINT32 *)Targ, 25, 7)) << 5); + Value = (Value | (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5))); + + if(Value & (RISCV_IMM_REACH/2)) { + Value |= ~(RISCV_IMM_REACH-1); + } + Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex]; + + if(-2048 > (INT32)Value) { + i = (((INT32)Value * -1) / 4096); + Value2 -= i; + Value += 4096 * i; + if(-2048 > (INT32)Value) { + Value2 -= 1; + Value += 4096; + } + } + else if( 2047 < (INT32)Value) { + i = (Value / 4096); + Value2 += i; + Value -= 4096 * i; + if(2047 < (INT32)Value) { + Value2 += 1; + Value -= 4096; + } + } + + // Update the IMM of SD instruction + // + // |31 25|24 20|19 15|14 12 |11 7|6 0| + // |-------------------------------------------|-------| + // |imm[11:5] | rs2 | rs1 | funct3 |imm[4:0] | opcode| + // --------------------------------------------------- + + // First Zero out current IMM + *(UINT32 *)Targ &= ~0xfe000f80; + + // Update with new IMM + *(UINT32 *)Targ |= (RV_X(Value, 5, 7) << 25); + *(UINT32 *)Targ |= (RV_X(Value, 0, 5) << 7); + + // Update previous instruction + *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12)); + } + mRiscVPass1Sym = NULL; + mRiscVPass1Targ = NULL; + mRiscVPass1SymSecIndex = 0; + break; + + case R_RISCV_PCREL_LO12_I: + if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) { + int i; + Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20)); + + if(mRiscVPass1GotFixup) { + Value = (UINT32)(mRiscVPass1Offset); + } else { + Value = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12)); + if(Value & (RISCV_IMM_REACH/2)) { + Value |= ~(RISCV_IMM_REACH-1); + } + } + Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex]; + + if(-2048 > (INT32)Value) { + i = (((INT32)Value * -1) / 4096); + Value2 -= i; + Value += 4096 * i; + if(-2048 > (INT32)Value) { + Value2 -= 1; + Value += 4096; + } + } + else if( 2047 < (INT32)Value) { + i = (Value / 4096); + Value2 += i; + Value -= 4096 * i; + if(2047 < (INT32)Value) { + Value2 += 1; + Value -= 4096; + } + } + + if(mRiscVPass1GotFixup) { + *(UINT32 *)Targ = (RV_X((UINT32)Value, 0, 12) << 20) + | (RV_X(*(UINT32*)Targ, 0, 20)); + // Convert LD instruction to ADDI + // + // |31 20|19 15|14 12|11 7|6 0| + // |-----------------------------------------| + // |imm[11:0] | rs1 | 011 | rd | 0000011 | LD + // ----------------------------------------- + + // |-----------------------------------------| + // |imm[11:0] | rs1 | 000 | rd | 0010011 | ADDI + // ----------------------------------------- + + // To convert, let's first reset bits 12-14 and 0-6 using ~0x707f + // Then modify the opcode to ADDI (0010011) + // All other fields will remain same. + + *(UINT32 *)Targ = ((*(UINT32 *)Targ & ~0x707f) | 0x13); + } else { + *(UINT32 *)Targ = (RV_X(Value, 0, 12) << 20) | (RV_X(*(UINT32*)Targ, 0, 20)); + } + *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12)); + } + mRiscVPass1Sym = NULL; + mRiscVPass1Targ = NULL; + mRiscVPass1SymSecIndex = 0; + mRiscVPass1Offset = 0; + mRiscVPass1GotFixup = 0; + break; + + case R_RISCV_ADD64: + case R_RISCV_SUB64: + case R_RISCV_ADD32: + case R_RISCV_SUB32: + case R_RISCV_BRANCH: + case R_RISCV_JAL: + case R_RISCV_GPREL_I: + case R_RISCV_GPREL_S: + case R_RISCV_CALL: + case R_RISCV_CALL_PLT: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + case R_RISCV_RELAX: + case R_RISCV_SUB6: + case R_RISCV_SET6: + case R_RISCV_SET8: + case R_RISCV_SET16: + case R_RISCV_SET32: + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } +} + +STATIC UINT16 mDllCharacteristicsEx; + +STATIC +VOID +ParseNoteSection ( + CONST Elf_Shdr *Shdr + ) +{ + CONST Elf_Note *Note; + CONST UINT32 *Prop; + UINT32 Prop0; + UINT32 Prop2; + + Note = (Elf_Note *)((UINT8 *)mEhdr + Shdr->sh_offset); + + if ((Note->n_type == NT_GNU_PROPERTY_TYPE_0) && + (Note->n_namesz == sizeof ("GNU")) && + (strcmp ((CHAR8 *)(Note + 1), "GNU") == 0) && + (Note->n_descsz > sizeof (UINT32[2]))) { + Prop = (UINT32 *)((UINT8 *)(Note + 1) + sizeof("GNU")); + + switch (mEhdr->e_machine) { + case EM_AARCH64: + Prop0 = GNU_PROPERTY_AARCH64_FEATURE_1_AND; + Prop2 = GNU_PROPERTY_AARCH64_FEATURE_1_BTI; + break; + + case EM_X86_64: + Prop0 = GNU_PROPERTY_X86_FEATURE_1_AND; + Prop2 = GNU_PROPERTY_X86_FEATURE_1_IBT; + break; + + default: + return; + } + if ((Prop[0] == Prop0) && + (Prop[1] >= sizeof (UINT32)) && + ((Prop[2] & Prop2) != 0)) { + mDllCharacteristicsEx |= EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT; + } + } +} + +// +// Elf functions interface implementation +// + +STATIC +VOID +ScanSections64 ( + VOID + ) +{ + UINT32 i; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + UINT32 CoffEntry; + UINT32 SectionCount; + BOOLEAN FoundSection; + UINT32 Offset; + + CoffEntry = 0; + mCoffOffset = 0; + + // + // Coff file start with a DOS header. + // + mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40; + mNtHdrOffset = mCoffOffset; + switch (mEhdr->e_machine) { + case EM_X86_64: + case EM_AARCH64: + case EM_RISCV64: + case EM_LOONGARCH: + mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64); + break; + default: + VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName, mEhdr->e_machine); + mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64); + break; + } + + mTableOffset = mCoffOffset; + mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER); + + // + // Set mCoffAlignment to the maximum alignment of the input sections + // we care about + // + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (shdr->sh_addralign <= mCoffAlignment) { + continue; + } + if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) { + mCoffAlignment = (UINT32)shdr->sh_addralign; + } + } + + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (shdr->sh_type == SHT_NOTE) { + ParseNoteSection (shdr); + } + } + + // + // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT + // + if (mCoffAlignment > MAX_COFF_ALIGNMENT) { + Error (NULL, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT."); + assert (FALSE); + } + + + // + // Move the PE/COFF header right before the first section. This will help us + // save space when converting to TE. + // + if (mCoffAlignment > mCoffOffset) { + mNtHdrOffset += mCoffAlignment - mCoffOffset; + mTableOffset += mCoffAlignment - mCoffOffset; + mCoffOffset = mCoffAlignment; + } + + // + // First text sections. + // + mCoffOffset = CoffAlign(mCoffOffset); + mTextOffset = mCoffOffset; + FoundSection = FALSE; + SectionCount = 0; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsTextShdr(shdr)) { + if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { + // the alignment field is valid + if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { + // if the section address is aligned we must align PE/COFF + mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1)); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); + } + } + + /* Relocate entry. */ + if ((mEhdr->e_entry >= shdr->sh_addr) && + (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) { + CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr); + } + + // + // Set mTextOffset with the offset of the first '.text' section + // + if (!FoundSection) { + mTextOffset = mCoffOffset; + FoundSection = TRUE; + } + + mCoffSectionsOffset[i] = mCoffOffset; + mCoffOffset += (UINT32) shdr->sh_size; + SectionCount ++; + } + } + + if (!FoundSection && mOutImageType != FW_ACPI_IMAGE) { + Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section."); + assert (FALSE); + } + + mDebugOffset = DebugRvaAlign(mCoffOffset); + mCoffOffset = CoffAlign(mCoffOffset); + + if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) { + Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName); + } + + // + // Then data sections. + // + mDataOffset = mCoffOffset; + FoundSection = FALSE; + SectionCount = 0; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsDataShdr(shdr)) { + if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { + // the alignment field is valid + if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { + // if the section address is aligned we must align PE/COFF + mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1)); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); + } + } + + // + // Set mDataOffset with the offset of the first '.data' section + // + if (!FoundSection) { + mDataOffset = mCoffOffset; + FoundSection = TRUE; + } + mCoffSectionsOffset[i] = mCoffOffset; + mCoffOffset += (UINT32) shdr->sh_size; + SectionCount ++; + } + } + + // + // Make room for .debug data in .data (or .text if .data is empty) instead of + // putting it in a section of its own. This is explicitly allowed by the + // PE/COFF spec, and prevents bloat in the binary when using large values for + // section alignment. + // + if (SectionCount > 0) { + mDebugOffset = DebugRvaAlign(mCoffOffset); + } + mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + + strlen(mInImageName) + 1; + + // + // Add more space in the .debug data region for the DllCharacteristicsEx + // field. + // + if (mDllCharacteristicsEx != 0) { + mCoffOffset = DebugRvaAlign(mCoffOffset) + + sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + + sizeof (EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY); + } + + mCoffOffset = CoffAlign(mCoffOffset); + if (SectionCount == 0) { + mDataOffset = mCoffOffset; + } + + if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) { + Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName); + } + + // + // The Symbol sections. + // + if (mExportFlag) { + UINT32 SymIndex; + Elf_Sym *Sym; + UINT64 SymNum; + const UINT8 *SymName; + + mExportOffset = mCoffOffset; + mExportSize = sizeof(EFI_IMAGE_EXPORT_DIRECTORY) + strlen(mInImageName) + 1; + + for (i = 0; i < mEhdr->e_shnum; i++) { + + // + // Determine if this is a symbol section. + // + Elf_Shdr *shdr = GetShdrByIndex(i); + if (!IsSymbolShdr(shdr)) { + continue; + } + + UINT8 *Symtab = (UINT8*)mEhdr + shdr->sh_offset; + SymNum = (shdr->sh_size) / (shdr->sh_entsize); + + // + // First Get PrmModuleExportDescriptor + // + for (SymIndex = 0; SymIndex < SymNum; SymIndex++) { + Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize); + SymName = GetSymName(Sym); + if (SymName == NULL) { + continue; + } + + if (strcmp((CHAR8*)SymName, PRM_MODULE_EXPORT_DESCRIPTOR_NAME) == 0) { + // + // Find PrmHandler Number and Name + // + FindPrmHandler(Sym->st_value); + + strcpy(mExportSymName[mExportSymNum], (CHAR8*)SymName); + mExportRVA[mExportSymNum] = (UINT32)(Sym->st_value); + mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1; + mExportSymNum ++; + break; + } + } + + // + // Second Get PrmHandler + // + for (SymIndex = 0; SymIndex < SymNum; SymIndex++) { + UINT32 ExpIndex; + Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize); + SymName = GetSymName(Sym); + if (SymName == NULL) { + continue; + } + + for (ExpIndex = 0; ExpIndex < (mExportSymNum -1); ExpIndex++) { + if (strcmp((CHAR8*)SymName, mExportSymName[ExpIndex]) != 0) { + continue; + } + mExportRVA[ExpIndex] = (UINT32)(Sym->st_value); + mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1; + } + } + + break; + } + + mCoffOffset += mExportSize; + mCoffOffset = CoffAlign(mCoffOffset); + } + + // + // The HII resource sections. + // + mHiiRsrcOffset = mCoffOffset; + for (i = 0; i < mEhdr->e_shnum; i++) { + Elf_Shdr *shdr = GetShdrByIndex(i); + if (IsHiiRsrcShdr(shdr)) { + if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) { + // the alignment field is valid + if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) { + // if the section address is aligned we must align PE/COFF + mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1)); + } else { + Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment."); + } + } + if (shdr->sh_size != 0) { + mHiiRsrcOffset = mCoffOffset; + mCoffSectionsOffset[i] = mCoffOffset; + mCoffOffset += (UINT32) shdr->sh_size; + mCoffOffset = CoffAlign(mCoffOffset); + SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset); + } + break; + } + } + + mRelocOffset = mCoffOffset; + + // + // Allocate base Coff file. Will be expanded later for relocations. + // + mCoffFile = (UINT8 *)malloc(mCoffOffset); + if (mCoffFile == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + } + assert (mCoffFile != NULL); + memset(mCoffFile, 0, mCoffOffset); + + // + // Fill headers. + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile; + DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE; + DosHdr->e_lfanew = mNtHdrOffset; + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset); + + NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE; + + switch (mEhdr->e_machine) { + case EM_X86_64: + NtHdr->Pe32Plus.FileHeader.Machine = IMAGE_FILE_MACHINE_X64; + NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + case EM_AARCH64: + NtHdr->Pe32Plus.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; + NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + case EM_RISCV64: + NtHdr->Pe32Plus.FileHeader.Machine = IMAGE_FILE_MACHINE_RISCV64; + NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + case EM_LOONGARCH: + NtHdr->Pe32Plus.FileHeader.Machine = IMAGE_FILE_MACHINE_LOONGARCH64; + NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + + default: + VerboseMsg ("%u unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine); + NtHdr->Pe32Plus.FileHeader.Machine = IMAGE_FILE_MACHINE_X64; + NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } + + NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections; + NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL); + mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp; + NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0; + NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0; + NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader); + NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE + | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED + | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED + | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE; + + NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset; + NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset; + NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0; + NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry; + + NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset; + + NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0; + NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment; + NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment; + NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0; + + NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset; + NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES; + + // + // Section headers. + // + if ((mDataOffset - mTextOffset) > 0) { + CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset, + EFI_IMAGE_SCN_CNT_CODE + | EFI_IMAGE_SCN_MEM_EXECUTE + | EFI_IMAGE_SCN_MEM_READ); + } else { + // Don't make a section of size 0. + NtHdr->Pe32Plus.FileHeader.NumberOfSections--; + } + + // + // If found symbol, add edata section between data and rsrc section + // + if(mExportFlag) { + Offset = mExportOffset; + } else { + Offset = mHiiRsrcOffset; + } + + if ((mHiiRsrcOffset - mDataOffset) > 0) { + CreateSectionHeader (".data", mDataOffset, Offset - mDataOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_WRITE + | EFI_IMAGE_SCN_MEM_READ); + } else { + // Don't make a section of size 0. + NtHdr->Pe32Plus.FileHeader.NumberOfSections--; + } + + if(mExportFlag) { + if ((mHiiRsrcOffset - mExportOffset) > 0) { + CreateSectionHeader (".edata", mExportOffset, mHiiRsrcOffset - mExportOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_READ); + NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = mHiiRsrcOffset - mExportOffset; + NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = mExportOffset; + + } else { + // Don't make a section of size 0. + NtHdr->Pe32Plus.FileHeader.NumberOfSections--; + } + } + + if ((mRelocOffset - mHiiRsrcOffset) > 0) { + CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_READ); + + NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset; + NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset; + } else { + // Don't make a section of size 0. + NtHdr->Pe32Plus.FileHeader.NumberOfSections--; + } + +} + +STATIC +BOOLEAN +WriteSections64 ( + SECTION_FILTER_TYPES FilterType + ) +{ + UINT32 Idx; + Elf_Shdr *SecShdr; + UINT32 SecOffset; + BOOLEAN (*Filter)(Elf_Shdr *); + Elf64_Addr GOTEntryRva; + + // + // Initialize filter pointer + // + switch (FilterType) { + case SECTION_TEXT: + Filter = IsTextShdr; + break; + case SECTION_HII: + Filter = IsHiiRsrcShdr; + break; + case SECTION_DATA: + Filter = IsDataShdr; + break; + default: + return FALSE; + } + + // + // First: copy sections. + // + for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { + Elf_Shdr *Shdr = GetShdrByIndex(Idx); + if ((*Filter)(Shdr)) { + switch (Shdr->sh_type) { + case SHT_PROGBITS: + /* Copy. */ + if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) { + return FALSE; + } + memcpy(mCoffFile + mCoffSectionsOffset[Idx], + (UINT8*)mEhdr + Shdr->sh_offset, + (size_t) Shdr->sh_size); + break; + + case SHT_NOBITS: + memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size); + break; + + default: + // + // Ignore for unknown section type. + // + VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName, (unsigned)Shdr->sh_type); + break; + } + } + } + + // + // Second: apply relocations. + // + VerboseMsg ("Applying Relocations..."); + for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { + // + // Determine if this is a relocation section. + // + Elf_Shdr *RelShdr = GetShdrByIndex(Idx); + if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) { + continue; + } + + // + // If this is a ET_DYN (PIE) executable, we will encounter a dynamic SHT_RELA + // section that applies to the entire binary, and which will have its section + // index set to #0 (which is a NULL section with the SHF_ALLOC bit cleared). + // + // In the absence of GOT based relocations, + // this RELA section will contain redundant R_xxx_RELATIVE relocations, one + // for every R_xxx_xx64 relocation appearing in the per-section RELA sections. + // (i.e., .rela.text and .rela.data) + // + if (RelShdr->sh_info == 0) { + continue; + } + + // + // Relocation section found. Now extract section information that the relocations + // apply to in the ELF data and the new COFF data. + // + SecShdr = GetShdrByIndex(RelShdr->sh_info); + SecOffset = mCoffSectionsOffset[RelShdr->sh_info]; + + // + // Only process relocations for the current filter type. + // + if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) { + UINT64 RelIdx; + + // + // Determine the symbol table referenced by the relocation data. + // + Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link); + UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset; + + // + // Process all relocation entries for this section. + // + for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) { + + // + // Set pointer to relocation entry + // + Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx); + + // + // Set pointer to symbol table entry associated with the relocation entry. + // + Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize); + + Elf_Shdr *SymShdr; + UINT8 *Targ; + + // + // The _GLOBAL_OFFSET_TABLE_ symbol is not actually an absolute symbol, + // but carries the SHN_ABS section index for historical reasons. + // It must be accompanied by a R_*_GOT_* type relocation on a + // subsequent instruction, which we handle below, specifically to avoid + // the GOT indirection, and to refer to the symbol directly. This means + // we can simply disregard direct references to the GOT symbol itself, + // as the resulting value will never be used. + // + if (Sym->st_shndx == SHN_ABS) { + const UINT8 *SymName = GetSymName (Sym); + if (strcmp ((CHAR8 *)SymName, "_GLOBAL_OFFSET_TABLE_") == 0) { + continue; + } + } + + // + // Check section header index found in symbol table and get the section + // header location. + // + if (Sym->st_shndx == SHN_UNDEF + || Sym->st_shndx >= mEhdr->e_shnum) { + const UINT8 *SymName = GetSymName(Sym); + if (SymName == NULL) { + SymName = (const UINT8 *)""; + } + + // + // Skip error on EM_RISCV64 and EM_LOONGARCH because no symbol name is built + // from RISC-V and LoongArch toolchain. + // + if ((mEhdr->e_machine != EM_RISCV64) && (mEhdr->e_machine != EM_LOONGARCH)) { + Error (NULL, 0, 3000, "Invalid", + "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. " + "For example, absolute and undefined symbols are not supported.", + mInImageName, SymName, Sym->st_value); + + exit(EXIT_FAILURE); + } + continue; + } + SymShdr = GetShdrByIndex(Sym->st_shndx); + + // + // Convert the relocation data to a pointer into the coff file. + // + // Note: + // r_offset is the virtual address of the storage unit to be relocated. + // sh_addr is the virtual address for the base of the section. + // + // r_offset in a memory address. + // Convert it to a pointer in the coff file. + // + Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr); + + // + // Determine how to handle each relocation type based on the machine type. + // + if (mEhdr->e_machine == EM_X86_64) { + switch (ELF_R_TYPE(Rel->r_info)) { + case R_X86_64_NONE: + break; + case R_X86_64_64: + // + // Absolute relocation. + // + VerboseMsg ("R_X86_64_64"); + VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", + (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), + *(UINT64 *)Targ); + *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ); + break; + case R_X86_64_32: + VerboseMsg ("R_X86_64_32"); + VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", + (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), + *(UINT32 *)Targ); + *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]); + VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ); + break; + case R_X86_64_32S: + VerboseMsg ("R_X86_64_32S"); + VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", + (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), + *(UINT32 *)Targ); + *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]); + VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ); + break; + + case R_X86_64_PLT32: + // + // Treat R_X86_64_PLT32 relocations as R_X86_64_PC32: this is + // possible since we know all code symbol references resolve to + // definitions in the same module (UEFI has no shared libraries), + // and so there is never a reason to jump via a PLT entry, + // allowing us to resolve the reference using the symbol directly. + // + VerboseMsg ("Treating R_X86_64_PLT32 as R_X86_64_PC32 ..."); + /* fall through */ + case R_X86_64_PC32: + // + // Relative relocation: Symbol - Ip + Addend + // + VerboseMsg ("R_X86_64_PC32"); + VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", + (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), + *(UINT32 *)Targ); + *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ + + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr) + - (SecOffset - SecShdr->sh_addr)); + VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ); + break; + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + VerboseMsg ("R_X86_64_GOTPCREL family"); + VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", + (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), + *(UINT32 *)Targ); + GOTEntryRva = Rel->r_offset - Rel->r_addend + *(INT32 *)Targ; + FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva); + *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ + + (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr) + - (SecOffset - SecShdr->sh_addr)); + VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ); + GOTEntryRva += (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr); // ELF Rva -> COFF Rva + if (AccumulateCoffGOTEntries((UINT32)GOTEntryRva)) { + // + // Relocate GOT entry if it's the first time we run into it + // + Targ = mCoffFile + GOTEntryRva; + // + // Limitation: The following three statements assume memory + // at *Targ is valid because the section containing the GOT + // has already been copied from the ELF image to the Coff image. + // This pre-condition presently holds because the GOT is placed + // in section .text, and the ELF text sections are all copied + // prior to reaching this point. + // If the pre-condition is violated in the future, this fixup + // either needs to be deferred after the GOT section is copied + // to the Coff image, or the fixup should be performed on the + // source Elf image instead of the destination Coff image. + // + VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", + (UINT32)GOTEntryRva, + *(UINT64 *)Targ); + *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ); + } + break; + default: + Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_AARCH64) { + + switch (ELF_R_TYPE(Rel->r_info)) { + INT64 Offset; + + case R_AARCH64_LD64_GOTOFF_LO15: + case R_AARCH64_LD64_GOTPAGE_LO15: + // + // Convert into an ADR instruction that refers to the symbol directly. + // + Offset = Sym->st_value - Rel->r_offset; + + *(UINT32 *)Targ &= 0x1000001f; + *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29); + + if (Offset < -0x100000 || Offset > 0xfffff) { + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s failed to relax GOT based symbol reference - image is too big (>1 MiB).", + mInImageName); + break; + } + break; + + case R_AARCH64_LD64_GOT_LO12_NC: + // + // Convert into an ADD instruction - see R_AARCH64_ADR_GOT_PAGE below. + // + *(UINT32 *)Targ &= 0x3ff; + *(UINT32 *)Targ |= 0x91000000 | ((Sym->st_value & 0xfff) << 10); + break; + + case R_AARCH64_ADR_GOT_PAGE: + // + // This relocation points to the GOT entry that contains the absolute + // address of the symbol we are referring to. Since EDK2 only uses + // fully linked binaries, we can avoid the indirection, and simply + // refer to the symbol directly. This implies having to patch the + // subsequent LDR instruction (covered by a R_AARCH64_LD64_GOT_LO12_NC + // relocation) into an ADD instruction - this is handled above. + // + Offset = (Sym->st_value - (Rel->r_offset & ~0xfff)) >> 12; + + *(UINT32 *)Targ &= 0x9000001f; + *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29); + + /* fall through */ + + case R_AARCH64_ADR_PREL_PG_HI21: + // + // In order to handle Cortex-A53 erratum #843419, the LD linker may + // convert ADRP instructions into ADR instructions, but without + // updating the static relocation type, and so we may end up here + // while the instruction in question is actually ADR. So let's + // just disregard it: the section offset check we apply below to + // ADR instructions will trigger for its R_AARCH64_xxx_ABS_LO12_NC + // companion instruction as well, so it is safe to omit it here. + // + if ((*(UINT32 *)Targ & BIT31) == 0) { + break; + } + + // + // AArch64 PG_H21 relocations are typically paired with ABS_LO12 + // relocations, where a PC-relative reference with +/- 4 GB range is + // split into a relative high part and an absolute low part. Since + // the absolute low part represents the offset into a 4 KB page, we + // either have to convert the ADRP into an ADR instruction, or we + // need to use a section alignment of at least 4 KB, so that the + // binary appears at a correct offset at runtime. In any case, we + // have to make sure that the 4 KB relative offsets of both the + // section containing the reference as well as the section to which + // it refers have not been changed during PE/COFF conversion (i.e., + // in ScanSections64() above). + // + if (mCoffAlignment < 0x1000) { + // + // Attempt to convert the ADRP into an ADR instruction. + // This is only possible if the symbol is within +/- 1 MB. + // + + // Decode the ADRP instruction + Offset = (INT32)((*(UINT32 *)Targ & 0xffffe0) << 8); + Offset = (Offset << (6 - 5)) | ((*(UINT32 *)Targ & 0x60000000) >> (29 - 12)); + + // + // ADRP offset is relative to the previous page boundary, + // whereas ADR offset is relative to the instruction itself. + // So fix up the offset so it points to the page containing + // the symbol. + // + Offset -= (UINTN)(Targ - mCoffFile) & 0xfff; + + if (Offset < -0x100000 || Offset > 0xfffff) { + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s due to its size (> 1 MB), this module requires 4 KB section alignment.", + mInImageName); + break; + } + + // Re-encode the offset as an ADR instruction + *(UINT32 *)Targ &= 0x1000001f; + *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29); + } + /* fall through */ + + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 || + ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0) { + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires identical ELF and PE/COFF section offsets modulo 4 KB.", + mInImageName); + break; + } + /* fall through */ + + case R_AARCH64_ADR_PREL_LO21: + case R_AARCH64_CONDBR19: + case R_AARCH64_LD_PREL_LO19: + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + case R_AARCH64_PREL64: + case R_AARCH64_PREL32: + case R_AARCH64_PREL16: + // + // The GCC toolchains (i.e., binutils) may corrupt section relative + // relocations when emitting relocation sections into fully linked + // binaries. More specifically, they tend to fail to take into + // account the fact that a '.rodata + XXX' relocation needs to have + // its addend recalculated once .rodata is merged into the .text + // section, and the relocation emitted into the .rela.text section. + // + // We cannot really recover from this loss of information, so the + // only workaround is to prevent having to recalculate any relative + // relocations at all, by using a linker script that ensures that + // the offset between the Place and the Symbol is the same in both + // the ELF and the PE/COFF versions of the binary. + // + if ((SymShdr->sh_addr - SecShdr->sh_addr) != + (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) { + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets", + mInImageName); + } + break; + + // Absolute relocations. + case R_AARCH64_ABS64: + *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_RISCV64) { + // + // Write section for RISC-V 64 architecture. + // + WriteSectionRiscV64 (Rel, Targ, SymShdr, Sym); + } else if (mEhdr->e_machine == EM_LOONGARCH) { + switch (ELF_R_TYPE(Rel->r_info)) { + INT64 Offset; + INT32 Lo, Hi; + + case R_LARCH_SOP_PUSH_ABSOLUTE: + // + // Absolute relocation. + // + *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; + break; + + case R_LARCH_MARK_LA: + case R_LARCH_64: + case R_LARCH_NONE: + case R_LARCH_32: + case R_LARCH_RELATIVE: + case R_LARCH_COPY: + case R_LARCH_JUMP_SLOT: + case R_LARCH_TLS_DTPMOD32: + case R_LARCH_TLS_DTPMOD64: + case R_LARCH_TLS_DTPREL32: + case R_LARCH_TLS_DTPREL64: + case R_LARCH_TLS_TPREL32: + case R_LARCH_TLS_TPREL64: + case R_LARCH_IRELATIVE: + case R_LARCH_MARK_PCREL: + case R_LARCH_SOP_PUSH_PCREL: + case R_LARCH_SOP_PUSH_DUP: + case R_LARCH_SOP_PUSH_GPREL: + case R_LARCH_SOP_PUSH_TLS_TPREL: + case R_LARCH_SOP_PUSH_TLS_GOT: + case R_LARCH_SOP_PUSH_TLS_GD: + case R_LARCH_SOP_PUSH_PLT_PCREL: + case R_LARCH_SOP_ASSERT: + case R_LARCH_SOP_NOT: + case R_LARCH_SOP_SUB: + case R_LARCH_SOP_SL: + case R_LARCH_SOP_SR: + case R_LARCH_SOP_ADD: + case R_LARCH_SOP_AND: + case R_LARCH_SOP_IF_ELSE: + case R_LARCH_SOP_POP_32_S_10_5: + case R_LARCH_SOP_POP_32_U_10_12: + case R_LARCH_SOP_POP_32_S_10_12: + case R_LARCH_SOP_POP_32_S_10_16: + case R_LARCH_SOP_POP_32_S_10_16_S2: + case R_LARCH_SOP_POP_32_S_5_20: + case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: + case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: + case R_LARCH_SOP_POP_32_U: + case R_LARCH_ADD8: + case R_LARCH_ADD16: + case R_LARCH_ADD24: + case R_LARCH_ADD32: + case R_LARCH_ADD64: + case R_LARCH_SUB8: + case R_LARCH_SUB16: + case R_LARCH_SUB24: + case R_LARCH_SUB32: + case R_LARCH_SUB64: + case R_LARCH_GNU_VTINHERIT: + case R_LARCH_GNU_VTENTRY: + case R_LARCH_B16: + case R_LARCH_B21: + case R_LARCH_B26: + case R_LARCH_ABS_HI20: + case R_LARCH_ABS_LO12: + case R_LARCH_ABS64_LO20: + case R_LARCH_ABS64_HI12: + case R_LARCH_PCALA_LO12: + case R_LARCH_PCALA64_LO20: + case R_LARCH_PCALA64_HI12: + case R_LARCH_GOT_PC_LO12: + case R_LARCH_GOT64_PC_LO20: + case R_LARCH_GOT64_PC_HI12: + case R_LARCH_GOT64_HI20: + case R_LARCH_GOT64_LO12: + case R_LARCH_GOT64_LO20: + case R_LARCH_GOT64_HI12: + case R_LARCH_TLS_LE_HI20: + case R_LARCH_TLS_LE_LO12: + case R_LARCH_TLS_LE64_LO20: + case R_LARCH_TLS_LE64_HI12: + case R_LARCH_TLS_IE_PC_HI20: + case R_LARCH_TLS_IE_PC_LO12: + case R_LARCH_TLS_IE64_PC_LO20: + case R_LARCH_TLS_IE64_PC_HI12: + case R_LARCH_TLS_IE64_HI20: + case R_LARCH_TLS_IE64_LO12: + case R_LARCH_TLS_IE64_LO20: + case R_LARCH_TLS_IE64_HI12: + case R_LARCH_TLS_LD_PC_HI20: + case R_LARCH_TLS_LD64_HI20: + case R_LARCH_TLS_GD_PC_HI20: + case R_LARCH_TLS_GD64_HI20: + case R_LARCH_RELAX: + // + // These types are not used or do not require fixup. + // + break; + + case R_LARCH_GOT_PC_HI20: + Offset = Sym->st_value - (UINTN)(Targ - mCoffFile); + if (Offset < 0) { + Offset = (UINTN)(Targ - mCoffFile) - Sym->st_value; + Hi = Offset & ~0xfff; + Lo = (INT32)((Offset & 0xfff) << 20) >> 20; + if ((Lo < 0) && (Lo > -2048)) { + Hi += 0x1000; + Lo = ~(0x1000 - Lo) + 1; + } + Hi = ~Hi + 1; + Lo = ~Lo + 1; + } else { + Hi = Offset & ~0xfff; + Lo = (INT32)((Offset & 0xfff) << 20) >> 20; + if (Lo < 0) { + Hi += 0x1000; + Lo = ~(0x1000 - Lo) + 1; + } + } + // Re-encode the offset as PCADDU12I + ADDI.D(Convert LD.D) instruction + *(UINT32 *)Targ &= 0x1f; + *(UINT32 *)Targ |= 0x1c000000; + *(UINT32 *)Targ |= (((Hi >> 12) & 0xfffff) << 5); + *(UINT32 *)(Targ + 4) &= 0x3ff; + *(UINT32 *)(Targ + 4) |= 0x2c00000 | ((Lo & 0xfff) << 10); + break; + + // + // Attempt to convert instruction. + // + case R_LARCH_PCALA_HI20: + // Decode the PCALAU12I instruction and the instruction that following it. + Offset = ((INT32)((*(UINT32 *)Targ & 0x1ffffe0) << 7)); + Offset += ((INT32)((*(UINT32 *)(Targ + 4) & 0x3ffc00) << 10) >> 20); + // + // PCALA offset is relative to the previous page boundary, + // whereas PCADD offset is relative to the instruction itself. + // So fix up the offset so it points to the page containing + // the symbol. + // + Offset -= (UINTN)(Targ - mCoffFile) & 0xfff; + if (Offset < 0) { + Offset = -Offset; + Hi = Offset & ~0xfff; + Lo = (INT32)((Offset & 0xfff) << 20) >> 20; + if ((Lo < 0) && (Lo > -2048)) { + Hi += 0x1000; + Lo = ~(0x1000 - Lo) + 1; + } + Hi = ~Hi + 1; + Lo = ~Lo + 1; + } else { + Hi = Offset & ~0xfff; + Lo = (INT32)((Offset & 0xfff) << 20) >> 20; + if (Lo < 0) { + Hi += 0x1000; + Lo = ~(0x1000 - Lo) + 1; + } + } + // Convert the first instruction from PCALAU12I to PCADDU12I and re-encode the offset into them. + *(UINT32 *)Targ &= 0x1f; + *(UINT32 *)Targ |= 0x1c000000; + *(UINT32 *)Targ |= (((Hi >> 12) & 0xfffff) << 5); + *(UINT32 *)(Targ + 4) &= 0xffc003ff; + *(UINT32 *)(Targ + 4) |= (Lo & 0xfff) << 10; + break; + default: + Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_LOONGARCH relocation 0x%x.", mInImageName, (unsigned) ELF64_R_TYPE(Rel->r_info)); + } + } else { + Error (NULL, 0, 3000, "Invalid", "Not a supported machine type"); + } + } + } + } + + return TRUE; +} + +STATIC +VOID +WriteRelocations64 ( + VOID + ) +{ + UINT32 Index; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + EFI_IMAGE_DATA_DIRECTORY *Dir; + UINT32 RiscVRelType; + + for (Index = 0; Index < mEhdr->e_shnum; Index++) { + Elf_Shdr *RelShdr = GetShdrByIndex(Index); + if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) { + Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info); + if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) { + UINT64 RelIdx; + + for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) { + Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx); + + if (mEhdr->e_machine == EM_X86_64) { + switch (ELF_R_TYPE(Rel->r_info)) { + case R_X86_64_NONE: + case R_X86_64_PC32: + case R_X86_64_PLT32: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + break; + case R_X86_64_64: + VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08llX", + mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr)); + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_DIR64); + break; + // + // R_X86_64_32 and R_X86_64_32S are ELF64 relocations emitted when using + // the SYSV X64 ABI small non-position-independent code model. + // R_X86_64_32 is used for unsigned 32-bit immediates with a 32-bit operand + // size. The value is either not extended, or zero-extended to 64 bits. + // R_X86_64_32S is used for either signed 32-bit non-rip-relative displacements + // or signed 32-bit immediates with a 64-bit operand size. The value is + // sign-extended to 64 bits. + // EFI_IMAGE_REL_BASED_HIGHLOW is a PE relocation that uses 32-bit arithmetic + // for rebasing an image. + // EFI PE binaries declare themselves EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE and + // may load above 2GB. If an EFI PE binary with a converted R_X86_64_32S + // relocation is loaded above 2GB, the value will get sign-extended to the + // negative part of the 64-bit address space. The negative part of the 64-bit + // address space is unmapped, so accessing such an address page-faults. + // In order to support R_X86_64_32S, it is necessary to unset + // EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE, and the EFI PE loader must implement + // this flag and abstain from loading such a PE binary above 2GB. + // Since this feature is not supported, support for R_X86_64_32S (and hence + // the small non-position-independent code model) is disabled. + // + // case R_X86_64_32S: + case R_X86_64_32: + VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08llX", + mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr)); + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_HIGHLOW); + break; + default: + Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_AARCH64) { + + switch (ELF_R_TYPE(Rel->r_info)) { + case R_AARCH64_ADR_PREL_LO21: + case R_AARCH64_CONDBR19: + case R_AARCH64_LD_PREL_LO19: + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + case R_AARCH64_PREL64: + case R_AARCH64_PREL32: + case R_AARCH64_PREL16: + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_LD64_GOTOFF_LO15: + case R_AARCH64_LD64_GOTPAGE_LO15: + // + // No fixups are required for relative relocations, provided that + // the relative offsets between sections have been preserved in + // the ELF to PE/COFF conversion. We have already asserted that + // this is the case in WriteSections64 (). + // + break; + + case R_AARCH64_ABS64: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_DIR64); + break; + + case R_AARCH64_ABS32: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_HIGHLOW); + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_RISCV64) { + RiscVRelType = ELF_R_TYPE(Rel->r_info); + switch (RiscVRelType) { + case R_RISCV_NONE: + break; + + case R_RISCV_32: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_HIGHLOW); + break; + + case R_RISCV_64: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_DIR64); + break; + + case R_RISCV_HI20: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_RISCV_HI20); + break; + + case R_RISCV_LO12_I: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_RISCV_LOW12I); + break; + + case R_RISCV_LO12_S: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_RISCV_LOW12S); + break; + + case R_RISCV_ADD64: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_ABSOLUTE); + break; + + case R_RISCV_SUB64: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_ABSOLUTE); + break; + + case R_RISCV_ADD32: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_ABSOLUTE); + break; + + case R_RISCV_SUB32: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_ABSOLUTE); + break; + + case R_RISCV_BRANCH: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_ABSOLUTE); + break; + + case R_RISCV_JAL: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_ABSOLUTE); + break; + + case R_RISCV_GPREL_I: + case R_RISCV_GPREL_S: + case R_RISCV_CALL: + case R_RISCV_CALL_PLT: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + case R_RISCV_RELAX: + case R_RISCV_SUB6: + case R_RISCV_SET6: + case R_RISCV_SET8: + case R_RISCV_SET16: + case R_RISCV_SET32: + case R_RISCV_PCREL_HI20: + case R_RISCV_GOT_HI20: + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + break; + + default: + Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); + } + } else if (mEhdr->e_machine == EM_LOONGARCH) { + switch (ELF_R_TYPE(Rel->r_info)) { + case R_LARCH_MARK_LA: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA); + break; + case R_LARCH_64: + CoffAddFixup( + (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info] + + (Rel->r_offset - SecShdr->sh_addr)), + EFI_IMAGE_REL_BASED_DIR64); + break; + case R_LARCH_NONE: + case R_LARCH_32: + case R_LARCH_RELATIVE: + case R_LARCH_COPY: + case R_LARCH_JUMP_SLOT: + case R_LARCH_TLS_DTPMOD32: + case R_LARCH_TLS_DTPMOD64: + case R_LARCH_TLS_DTPREL32: + case R_LARCH_TLS_DTPREL64: + case R_LARCH_TLS_TPREL32: + case R_LARCH_TLS_TPREL64: + case R_LARCH_IRELATIVE: + case R_LARCH_MARK_PCREL: + case R_LARCH_SOP_PUSH_PCREL: + case R_LARCH_SOP_PUSH_ABSOLUTE: + case R_LARCH_SOP_PUSH_DUP: + case R_LARCH_SOP_PUSH_GPREL: + case R_LARCH_SOP_PUSH_TLS_TPREL: + case R_LARCH_SOP_PUSH_TLS_GOT: + case R_LARCH_SOP_PUSH_TLS_GD: + case R_LARCH_SOP_PUSH_PLT_PCREL: + case R_LARCH_SOP_ASSERT: + case R_LARCH_SOP_NOT: + case R_LARCH_SOP_SUB: + case R_LARCH_SOP_SL: + case R_LARCH_SOP_SR: + case R_LARCH_SOP_ADD: + case R_LARCH_SOP_AND: + case R_LARCH_SOP_IF_ELSE: + case R_LARCH_SOP_POP_32_S_10_5: + case R_LARCH_SOP_POP_32_U_10_12: + case R_LARCH_SOP_POP_32_S_10_12: + case R_LARCH_SOP_POP_32_S_10_16: + case R_LARCH_SOP_POP_32_S_10_16_S2: + case R_LARCH_SOP_POP_32_S_5_20: + case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: + case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: + case R_LARCH_SOP_POP_32_U: + case R_LARCH_ADD8: + case R_LARCH_ADD16: + case R_LARCH_ADD24: + case R_LARCH_ADD32: + case R_LARCH_ADD64: + case R_LARCH_SUB8: + case R_LARCH_SUB16: + case R_LARCH_SUB24: + case R_LARCH_SUB32: + case R_LARCH_SUB64: + case R_LARCH_GNU_VTINHERIT: + case R_LARCH_GNU_VTENTRY: + case R_LARCH_B16: + case R_LARCH_B21: + case R_LARCH_B26: + case R_LARCH_ABS_HI20: + case R_LARCH_ABS_LO12: + case R_LARCH_ABS64_LO20: + case R_LARCH_ABS64_HI12: + case R_LARCH_PCALA_HI20: + case R_LARCH_PCALA_LO12: + case R_LARCH_PCALA64_LO20: + case R_LARCH_PCALA64_HI12: + case R_LARCH_GOT_PC_HI20: + case R_LARCH_GOT_PC_LO12: + case R_LARCH_GOT64_PC_LO20: + case R_LARCH_GOT64_PC_HI12: + case R_LARCH_GOT64_HI20: + case R_LARCH_GOT64_LO12: + case R_LARCH_GOT64_LO20: + case R_LARCH_GOT64_HI12: + case R_LARCH_TLS_LE_HI20: + case R_LARCH_TLS_LE_LO12: + case R_LARCH_TLS_LE64_LO20: + case R_LARCH_TLS_LE64_HI12: + case R_LARCH_TLS_IE_PC_HI20: + case R_LARCH_TLS_IE_PC_LO12: + case R_LARCH_TLS_IE64_PC_LO20: + case R_LARCH_TLS_IE64_PC_HI12: + case R_LARCH_TLS_IE64_HI20: + case R_LARCH_TLS_IE64_LO12: + case R_LARCH_TLS_IE64_LO20: + case R_LARCH_TLS_IE64_HI12: + case R_LARCH_TLS_LD_PC_HI20: + case R_LARCH_TLS_LD64_HI20: + case R_LARCH_TLS_GD_PC_HI20: + case R_LARCH_TLS_GD64_HI20: + case R_LARCH_RELAX: + // + // These types are not used or do not require fixup in PE format files. + // + break; + default: + Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_LOONGARCH relocation 0x%x.", mInImageName, (unsigned) ELF64_R_TYPE(Rel->r_info)); + } + } else { + Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine); + } + } + if (mEhdr->e_machine == EM_X86_64 && RelShdr->sh_info == mGOTShindex) { + // + // Tack relocations for GOT entries after other relocations for + // the section the GOT is in, as it's usually found at the end + // of the section. This is done in order to maintain Rva order + // of Coff relocations. + // + EmitGOTRelocations(); + } + } + } + } + + if (mEhdr->e_machine == EM_X86_64) { + // + // This is a safety net just in case the GOT is in a section + // with no other relocations and the first invocation of + // EmitGOTRelocations() above was skipped. This invocation + // does not maintain Rva order of Coff relocations. + // At present, with a single text section, all references to + // the GOT and the GOT itself reside in section .text, so + // if there's a GOT at all, the first invocation above + // is executed. + // + EmitGOTRelocations(); + } + // + // Pad by adding empty entries. + // + while (mCoffOffset & (mCoffAlignment - 1)) { + CoffAddFixupEntry(0); + } + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + Dir->Size = mCoffOffset - mRelocOffset; + if (Dir->Size == 0) { + // If no relocations, null out the directory entry and don't add the .reloc section + Dir->VirtualAddress = 0; + NtHdr->Pe32Plus.FileHeader.NumberOfSections--; + } else { + Dir->VirtualAddress = mRelocOffset; + CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset, + EFI_IMAGE_SCN_CNT_INITIALIZED_DATA + | EFI_IMAGE_SCN_MEM_DISCARDABLE + | EFI_IMAGE_SCN_MEM_READ); + } +} + +STATIC +VOID +WriteDebug64 ( + VOID + ) +{ + UINT32 Len; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + EFI_IMAGE_DATA_DIRECTORY *DataDir; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir; + EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10; + EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY *DllEntry; + + Len = strlen(mInImageName) + 1; + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]; + DataDir->VirtualAddress = mDebugOffset; + DataDir->Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + + Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset); + + if (mDllCharacteristicsEx != 0) { + DataDir->Size += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + + Dir->Type = EFI_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS; + Dir->SizeOfData = sizeof (EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY); + Dir->FileOffset = mDebugOffset + DataDir->Size + + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + + DebugRvaAlign(Len); + Dir->RVA = Dir->FileOffset; + + DllEntry = (VOID *)(mCoffFile + Dir->FileOffset); + + DllEntry->DllCharacteristicsEx = mDllCharacteristicsEx; + + Dir++; + } + + Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW; + Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len; + Dir->RVA = mDebugOffset + DataDir->Size; + Dir->FileOffset = mDebugOffset + DataDir->Size; + + Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1); + Nb10->Signature = CODEVIEW_SIGNATURE_NB10; + strcpy ((char *)(Nb10 + 1), mInImageName); +} + +STATIC +VOID +SetImageSize64 ( + VOID + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + + // + // Set image size + // + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset; +} + +STATIC +VOID +CleanUp64 ( + VOID + ) +{ + if (mCoffSectionsOffset != NULL) { + free (mCoffSectionsOffset); + } +} + +STATIC +VOID +WriteExport64 ( + VOID + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; + EFI_IMAGE_EXPORT_DIRECTORY *ExportDir; + EFI_IMAGE_DATA_DIRECTORY *DataDir; + UINT32 FileNameOffset; + UINT32 NameOffset; + UINT16 Index; + UINT8 *Tdata = NULL; + + ExportDir = (EFI_IMAGE_EXPORT_DIRECTORY*)(mCoffFile + mExportOffset); + ExportDir->Characteristics = 0; + ExportDir->TimeDateStamp = 0; + ExportDir->MajorVersion = 0; + ExportDir->MinorVersion =0; + ExportDir->Name = 0; + ExportDir->NumberOfFunctions = mExportSymNum; + ExportDir->NumberOfNames = mExportSymNum; + ExportDir->Base = EFI_IMAGE_EXPORT_ORDINAL_BASE; + ExportDir->AddressOfFunctions = mExportOffset + sizeof(EFI_IMAGE_EXPORT_DIRECTORY); + ExportDir->AddressOfNames = ExportDir->AddressOfFunctions + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum; + ExportDir->AddressOfNameOrdinals = ExportDir->AddressOfNames + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum; + + FileNameOffset = ExportDir->AddressOfNameOrdinals + EFI_IMAGE_EXPORT_ORDINAL_SIZE * mExportSymNum; + NameOffset = FileNameOffset + strlen(mInImageName) + 1; + + // Write Input image Name RVA + ExportDir->Name = FileNameOffset; + + // Write Input image Name + strcpy((char *)(mCoffFile + FileNameOffset), mInImageName); + + for (Index = 0; Index < mExportSymNum; Index++) { + // + // Write Export Address Table + // + Tdata = mCoffFile + ExportDir->AddressOfFunctions + Index * EFI_IMAGE_EXPORT_ADDR_SIZE; + *(UINT32 *)Tdata = mExportRVA[Index]; + + // + // Write Export Name Pointer Table + // + Tdata = mCoffFile + ExportDir->AddressOfNames + Index * EFI_IMAGE_EXPORT_ADDR_SIZE; + *(UINT32 *)Tdata = NameOffset; + + // + // Write Export Ordinal table + // + Tdata = mCoffFile + ExportDir->AddressOfNameOrdinals + Index * EFI_IMAGE_EXPORT_ORDINAL_SIZE; + *(UINT16 *)Tdata = Index; + + // + // Write Export Name Table + // + strcpy((char *)(mCoffFile + NameOffset), mExportSymName[Index]); + NameOffset += strlen(mExportSymName[Index]) + 1; + } + + NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset); + DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]; + DataDir->VirtualAddress = mExportOffset; + DataDir->Size = mExportSize; + +} + diff --git a/tools/src/GenFw/GenFw/src/Elf64Convert.h b/tools/src/GenFw/GenFw/src/Elf64Convert.h new file mode 100644 index 0000000..69746f4 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/Elf64Convert.h @@ -0,0 +1,19 @@ +/** @file +Header file for Elf64 convert solution + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ELF_64_CONVERT_ +#define _ELF_64_CONVERT_ + +BOOLEAN +InitializeElf64 ( + UINT8 *FileBuffer, + ELF_FUNCTION_TABLE *ElfFunctions + ); + +#endif diff --git a/tools/src/GenFw/GenFw/src/ElfConvert.c b/tools/src/GenFw/GenFw/src/ElfConvert.c new file mode 100644 index 0000000..3a8dfe0 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/ElfConvert.c @@ -0,0 +1,251 @@ +/** @file +Elf convert solution + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GNUC__ +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "EfiUtilityMsgs.h" + +#include "GenFw.h" +#include "ElfConvert.h" +#include "Elf32Convert.h" +#include "Elf64Convert.h" + +// +// Result Coff file in memory. +// +UINT8 *mCoffFile = NULL; + +// +// COFF relocation data +// +EFI_IMAGE_BASE_RELOCATION *mCoffBaseRel; +UINT16 *mCoffEntryRel; + +// +// Current offset in coff file. +// +UINT32 mCoffOffset; + +// +// Offset in Coff file of headers and sections. +// +UINT32 mTableOffset; + +// +//mFileBufferSize +// +UINT32 mFileBufferSize; + +// +//***************************************************************************** +// Common ELF Functions +//***************************************************************************** +// + +VOID +CoffAddFixupEntry( + UINT16 Val + ) +{ + *mCoffEntryRel = Val; + mCoffEntryRel++; + mCoffBaseRel->SizeOfBlock += 2; + mCoffOffset += 2; +} + +VOID +CoffAddFixup( + UINT32 Offset, + UINT8 Type + ) +{ + if (mCoffBaseRel == NULL + || mCoffBaseRel->VirtualAddress != (Offset & ~0xfff)) { + if (mCoffBaseRel != NULL) { + // + // Add a null entry (is it required ?) + // + CoffAddFixupEntry (0); + + // + // Pad for alignment. + // + if (mCoffOffset % 4 != 0) + CoffAddFixupEntry (0); + } + + mCoffFile = realloc ( + mCoffFile, + mCoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2 * MAX_COFF_ALIGNMENT + ); + if (mCoffFile == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + } + assert (mCoffFile != NULL); + memset ( + mCoffFile + mCoffOffset, 0, + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2 * MAX_COFF_ALIGNMENT + ); + + mCoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(mCoffFile + mCoffOffset); + mCoffBaseRel->VirtualAddress = Offset & ~0xfff; + mCoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION); + + mCoffEntryRel = (UINT16 *)(mCoffBaseRel + 1); + mCoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION); + } + + // + // Fill the entry. + // + CoffAddFixupEntry((UINT16) ((Type << 12) | (Offset & 0xfff))); +} + +VOID +CreateSectionHeader ( + const CHAR8 *Name, + UINT32 Offset, + UINT32 Size, + UINT32 Flags + ) +{ + EFI_IMAGE_SECTION_HEADER *Hdr; + Hdr = (EFI_IMAGE_SECTION_HEADER*)(mCoffFile + mTableOffset); + + strcpy((char *)Hdr->Name, Name); + Hdr->Misc.VirtualSize = Size; + Hdr->VirtualAddress = Offset; + Hdr->SizeOfRawData = Size; + Hdr->PointerToRawData = Offset; + Hdr->PointerToRelocations = 0; + Hdr->PointerToLinenumbers = 0; + Hdr->NumberOfRelocations = 0; + Hdr->NumberOfLinenumbers = 0; + Hdr->Characteristics = Flags; + + mTableOffset += sizeof (EFI_IMAGE_SECTION_HEADER); +} + +// +//***************************************************************************** +// Functions called from GenFw main code. +//***************************************************************************** +// + +INTN +IsElfHeader ( + UINT8 *FileBuffer +) +{ + return (FileBuffer[EI_MAG0] == ELFMAG0 && + FileBuffer[EI_MAG1] == ELFMAG1 && + FileBuffer[EI_MAG2] == ELFMAG2 && + FileBuffer[EI_MAG3] == ELFMAG3); +} + +BOOLEAN +ConvertElf ( + UINT8 **FileBuffer, + UINT32 *FileLength + ) +{ + ELF_FUNCTION_TABLE ElfFunctions; + UINT8 EiClass; + + mFileBufferSize = *FileLength; + // + // Determine ELF type and set function table pointer correctly. + // + VerboseMsg ("Check Elf Image Header"); + EiClass = (*FileBuffer)[EI_CLASS]; + if (EiClass == ELFCLASS32) { + if (!InitializeElf32 (*FileBuffer, &ElfFunctions)) { + return FALSE; + } + } else if (EiClass == ELFCLASS64) { + if (!InitializeElf64 (*FileBuffer, &ElfFunctions)) { + return FALSE; + } + } else { + Error (NULL, 0, 3000, "Unsupported", "ELF EI_CLASS not supported."); + return FALSE; + } + + // + // Compute sections new address. + // + VerboseMsg ("Compute sections new address."); + ElfFunctions.ScanSections (); + + // + // Write and relocate sections. + // + VerboseMsg ("Write and relocate sections."); + if (!ElfFunctions.WriteSections (SECTION_TEXT)) { + return FALSE; + } + if (!ElfFunctions.WriteSections (SECTION_DATA)) { + return FALSE; + } + if (!ElfFunctions.WriteSections (SECTION_HII)) { + return FALSE; + } + + // + // Translate and write relocations. + // + VerboseMsg ("Translate and write relocations."); + ElfFunctions.WriteRelocations (); + + // + // Write debug info. + // + VerboseMsg ("Write debug info."); + ElfFunctions.WriteDebug (); + + // + // For PRM Driver to Write export info. + // + if (mExportFlag) { + VerboseMsg ("Write export info."); + ElfFunctions.WriteExport (); + } + + // + // Make sure image size is correct before returning the new image. + // + VerboseMsg ("Set image size."); + ElfFunctions.SetImageSize (); + + // + // Replace. + // + free (*FileBuffer); + *FileBuffer = mCoffFile; + *FileLength = mCoffOffset; + + // + // Free resources used by ELF functions. + // + ElfFunctions.CleanUp (); + + return TRUE; +} diff --git a/tools/src/GenFw/GenFw/src/ElfConvert.h b/tools/src/GenFw/GenFw/src/ElfConvert.h new file mode 100644 index 0000000..f5e4fd9 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/ElfConvert.h @@ -0,0 +1,122 @@ +/** @file +Header file for Elf convert solution + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ELF_CONVERT_H_ +#define _ELF_CONVERT_H_ + +#include "elf_common.h" +#include "elf32.h" +#include "elf64.h" + +// +// Externally defined variables +// +extern UINT32 mCoffOffset; +extern CHAR8 *mInImageName; +extern UINT32 mImageTimeStamp; +extern UINT8 *mCoffFile; +extern UINT32 mTableOffset; +extern UINT32 mOutImageType; +extern UINT32 mFileBufferSize; +extern BOOLEAN mExportFlag; + +// +// Common EFI specific data. +// +#define ELF_HII_SECTION_NAME ".hii" +#define ELF_STRTAB_SECTION_NAME ".strtab" +#define MAX_COFF_ALIGNMENT 0x10000 +#define ELF_SYMBOL_SECTION_NAME ".symtab" + +// +// Platform Runtime Mechanism (PRM) specific data. +// +#define PRM_MODULE_EXPORT_SYMBOL_NUM 256 + +// to include PRM header directly once PrmPkg is in main repo +#define PRM_HANDLER_NAME_MAXIMUM_LENGTH 128 + +#define PRM_MODULE_EXPORT_DESCRIPTOR_NAME "PrmModuleExportDescriptor" +#define PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE SIGNATURE_64 ('P', 'R', 'M', '_', 'M', 'E', 'D', 'T') +#define PRM_MODULE_EXPORT_REVISION 0x0 + +// +// Platform Runtime Mechanism (PRM) Export Descriptor Structures +// +#pragma pack(push, 1) + +typedef struct { + EFI_GUID PrmHandlerGuid; + CHAR8 PrmHandlerName[PRM_HANDLER_NAME_MAXIMUM_LENGTH]; +} PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT; + +typedef struct { + UINT64 Signature; + UINT16 Revision; + UINT16 NumberPrmHandlers; + EFI_GUID PlatformGuid; + EFI_GUID ModuleGuid; +} PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER; + +typedef struct { + PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER Header; + PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT PrmHandlerExportDescriptors[1]; +} PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT; + +#pragma pack(pop) + +// +// Filter Types +// +typedef enum { + SECTION_TEXT, + SECTION_HII, + SECTION_DATA, + SECTION_SYMBOL + +} SECTION_FILTER_TYPES; + +// +// FunctionTable +// +typedef struct { + VOID (*ScanSections) (); + BOOLEAN (*WriteSections) (SECTION_FILTER_TYPES FilterType); + VOID (*WriteRelocations) (); + VOID (*WriteDebug) (); + VOID (*WriteExport) (); + VOID (*SetImageSize) (); + VOID (*CleanUp) (); + +} ELF_FUNCTION_TABLE; + +// +// Common functions +// +VOID +CoffAddFixup ( + UINT32 Offset, + UINT8 Type + ); + +VOID +CoffAddFixupEntry ( + UINT16 Val + ); + + +VOID +CreateSectionHeader ( + const CHAR8 *Name, + UINT32 Offset, + UINT32 Size, + UINT32 Flags + ); + +#endif diff --git a/tools/src/GenFw/GenFw/src/GenFw.c b/tools/src/GenFw/GenFw/src/GenFw.c new file mode 100644 index 0000000..327fb7a --- /dev/null +++ b/tools/src/GenFw/GenFw/src/GenFw.c @@ -0,0 +1,3262 @@ +/** @file +Converts a pe32+ image to an FW, Te image type, or other specific image. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GNUC__ +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include + +// +// Acpi Table definition +// +#include +#include +#include +#include +#include + +#include "CommonLib.h" +#include "PeCoffLib.h" +#include "ParseInf.h" +#include "EfiUtilityMsgs.h" + +#include "GenFw.h" + +// +// Version of this utility +// +#define UTILITY_NAME "GenFw" +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 2 + +#define HII_RESOURCE_SECTION_INDEX 1 +#define HII_RESOURCE_SECTION_NAME "HII" + +#define DEFAULT_MC_PAD_BYTE_VALUE 0xFF +#define DEFAULT_MC_ALIGNMENT 16 + +#define STATUS_IGNORE 0xA +// +// Structure definition for a microcode header +// +typedef struct { + UINT32 HeaderVersion; + UINT32 PatchId; + UINT32 Date; + UINT32 CpuId; + UINT32 Checksum; + UINT32 LoaderVersion; + UINT32 PlatformId; + UINT32 DataSize; // if 0, then TotalSize = 2048, and TotalSize field is invalid + UINT32 TotalSize; // number of bytes + UINT32 Reserved[3]; +} MICROCODE_IMAGE_HEADER; + +static EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + +static const char *gHiiPackageRCFileHeader[] = { + "//", + "// DO NOT EDIT -- auto-generated file", + "//", + NULL +}; + +// +// Module image information +// +CHAR8 *mInImageName; +UINT32 mImageTimeStamp = 0; +UINT32 mImageSize = 0; +UINT32 mOutImageType = FW_DUMMY_IMAGE; +BOOLEAN mIsConvertXip = FALSE; +BOOLEAN mExportFlag = FALSE; + +STATIC +EFI_STATUS +ZeroDebugData ( + IN OUT UINT8 *FileBuffer, + BOOLEAN ZeroDebug + ); + +STATIC +EFI_STATUS +SetStamp ( + IN OUT UINT8 *FileBuffer, + IN CHAR8 *TimeStamp + ); + +STATIC +STATUS +MicrocodeReadData ( + FILE *InFptr, + UINT32 *Data + ); + +STATIC +VOID +Version ( + VOID + ) +/*++ + +Routine Description: + + Print out version information for this utility. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); +} + +STATIC +VOID +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print Help message. + +Arguments: + + VOID + +Returns: + + None + +--*/ +{ + // + // Summary usage + // + fprintf (stdout, "\nUsage: %s [options] \n\n", UTILITY_NAME); + + // + // Copyright declaration + // + fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n"); + + // + // Details Option + // + fprintf (stdout, "Options:\n"); + fprintf (stdout, " -o FileName, --outputfile FileName\n\ + File will be created to store the output content.\n"); + fprintf (stdout, " -e EFI_FILETYPE, --efiImage EFI_FILETYPE\n\ + Create Efi Image. EFI_FILETYPE is one of BASE,SMM_CORE,\n\ + PEI_CORE, PEIM, DXE_CORE, DXE_DRIVER, UEFI_APPLICATION,\n\ + SEC, DXE_SAL_DRIVER, UEFI_DRIVER, DXE_RUNTIME_DRIVER,\n\ + DXE_SMM_DRIVER, SECURITY_CORE, COMBINED_PEIM_DRIVER,\n\ + MM_STANDALONE, MM_CORE_STANDALONE,\n\ + PIC_PEIM, RELOCATABLE_PEIM, BS_DRIVER, RT_DRIVER,\n\ + APPLICATION, SAL_RT_DRIVER to support all module types\n\ + It can only be used together with --keepexceptiontable,\n\ + --keepzeropending, --keepoptionalheader, -r, -o option.\n\ + It is a action option. If it is combined with other action options,\n\ + the later input action option will override the previous one.\n"); + fprintf (stdout, " -c, --acpi Create Acpi table.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -t, --terse Create Te Image.\n\ + It can only be used together with --keepexceptiontable,\n\ + --keepzeropending, --keepoptionalheader, -r, -o option.\n\ + It is a action option. If it is combined with other action options,\n\ + the later input action option will override the previous one.\n"); + fprintf (stdout, " -u, --dump Dump TeImage Header.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -z, --zero Zero the Debug Data Fields in the PE input image file.\n\ + It also zeros the time stamp fields.\n\ + This option can be used to compare the binary efi image.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -b, --exe2bin Convert the input EXE to the output BIN file.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n");; + fprintf (stdout, " -l, --stripped Strip off the relocation info from PE or TE image.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -s timedate, --stamp timedate\n\ + timedate format is \"yyyy-mm-dd 00:00:00\". if timedata \n\ + is set to NOW, current system time is used. The support\n\ + date scope is 1970-01-01 00+timezone:00:00\n\ + ~ 2038-01-19 03+timezone:14:07\n\ + The scope is adjusted according to the different zones.\n\ + It can't be combined with other action options\n\ + except for -o, -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -m, --mcifile Convert input microcode txt file to microcode bin file.\n\ + It can't be combined with other action options\n\ + except for -o option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -j, --join Combine multi microcode bin files to one file.\n\ + It can be specified with -a, -p, -o option.\n\ + No other options can be combined with it.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " -a NUM, --align NUM NUM is one HEX or DEC format alignment value.\n\ + This option is only used together with -j option.\n"); + fprintf (stdout, " -p NUM, --pad NUM NUM is one HEX or DEC format padding value.\n\ + This option is only used together with -j option.\n"); + fprintf (stdout, " --keepexceptiontable Don't clear exception table.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " --keepoptionalheader Don't zero PE/COFF optional header fields.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " --keepzeropending Don't strip zero pending of .reloc.\n\ + This option can be used together with -e or -t.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " -r, --replace Overwrite the input file with the output content.\n\ + If more input files are specified,\n\ + the last input file will be as the output file.\n"); + fprintf (stdout, " -g HiiPackageListGuid, --hiiguid HiiPackageListGuid\n\ + Guid is used to specify hii package list guid.\n\ + Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n\ + If not specified, the first Form FormSet guid is used.\n"); + fprintf (stdout, " --hiipackage Combine all input binary hii packages into \n\ + a single package list as the text resource data(RC).\n\ + It can't be combined with other action options\n\ + except for -o option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --hiibinpackage Combine all input binary hii packages into \n\ + a single package list as the binary resource section.\n\ + It can't be combined with other action options\n\ + except for -o option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --rebase NewAddress Rebase image to new base address. New address \n\ + is also set to the first none code section header.\n\ + It can't be combined with other action options\n\ + except for -o or -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --address NewAddress Set new address into the first none code \n\ + section header of the input image.\n\ + It can't be combined with other action options\n\ + except for -o or -r option. It is a action option.\n\ + If it is combined with other action options, the later\n\ + input action option will override the previous one.\n"); + fprintf (stdout, " --prm Scan symbol section from ELF image and \n\ + write export table into PE-COFF.\n\ + This option can be used together with -e.\n\ + It doesn't work for other options.\n"); + fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n"); + fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n"); + fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n"); + fprintf (stdout, " --version Show program's version number and exit\n"); + fprintf (stdout, " -h, --help Show this help message and exit\n"); +} + +STATIC +STATUS +CheckAcpiTable ( + VOID *AcpiTable, + UINT32 Length + ) +/*++ + +Routine Description: + + Check Acpi Table + +Arguments: + + AcpiTable Buffer for AcpiSection + Length AcpiSection Length + +Returns: + + 0 success + non-zero otherwise + +--*/ +{ + EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader; + EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; + UINT32 ExpectedLength; + + AcpiHeader = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable; + + // + // Generic check for AcpiTable length. + // + if (AcpiHeader->Length > Length) { + Error (NULL, 0, 3000, "Invalid", "AcpiTable length check failed.", NULL); + return STATUS_ERROR; + } + + // + // Currently, we only check must-have tables: FADT, FACS, DSDT, + // and some important tables: MADT, MCFG. + // + switch (AcpiHeader->Signature) { + + // + // "FACP" Fixed ACPI Description Table + // + case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE: + switch (AcpiHeader->Revision) { + case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION: + ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE); + break; + case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION: + ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE); + break; + case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION: + ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE); + break; + default: + if (AcpiHeader->Revision > EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) { + ExpectedLength = AcpiHeader->Length; + break; + } + Error (NULL, 0, 3000, "Invalid", "FACP revision check failed."); + return STATUS_ERROR; + } + if (ExpectedLength != AcpiHeader->Length) { + Error (NULL, 0, 3000, "Invalid", "FACP length check failed."); + return STATUS_ERROR; + } + break; + + // + // "FACS" Firmware ACPI Control Structure + // + case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE: + Facs = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable; + if (Facs->Version > EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) { + break; + } + if ((Facs->Version != 0 /* field is reserved in ACPI 1.0 */) && + (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && + (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)){ + Error (NULL, 0, 3000, "Invalid", "FACS version check failed."); + return STATUS_ERROR; + } + if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) && + (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) && + (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) { + Error (NULL, 0, 3000, "Invalid", "FACS length check failed."); + return STATUS_ERROR; + } + break; + + // + // "DSDT" Differentiated System Description Table + // + case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: + if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) { + break; + } + if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) { + Error (NULL, 0, 3000, "Invalid", "DSDT length check failed."); + return STATUS_ERROR; + } + break; + + // + // "APIC" Multiple APIC Description Table + // + case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE: + if (AcpiHeader->Revision > EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) { + break; + } + if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) && + (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) && + (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) { + Error (NULL, 0, 3000, "Invalid", "APIC revision check failed."); + return STATUS_ERROR; + } + if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32)) { + Error (NULL, 0, 3000, "Invalid", "APIC length check failed."); + return STATUS_ERROR; + } + break; + + // + // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table + // + case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE: + if (AcpiHeader->Revision > EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) { + break; + } + if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) { + Error (NULL, 0, 3000, "Invalid", "MCFG revision check failed."); + return STATUS_ERROR; + } + if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64)) { + Error (NULL, 0, 3000, "Invalid", "MCFG length check failed."); + return STATUS_ERROR; + } + break; + + // + // Other table pass check + // + default: + break; + } + + return STATUS_SUCCESS; +} + +VOID +SetHiiResourceHeader ( + UINT8 *HiiBinData, + UINT32 OffsetToFile + ) +{ + UINT32 Index; + EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString; + EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry; + + // + // Fill Resource section entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiBinData); + ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1); + for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index ++) { + if (ResourceDirectoryEntry->u1.s.NameIsString) { + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiBinData + ResourceDirectoryEntry->u1.s.NameOffset); + + if (ResourceDirectoryString->Length == 3 && + ResourceDirectoryString->String[0] == L'H' && + ResourceDirectoryString->String[1] == L'I' && + ResourceDirectoryString->String[2] == L'I') { + // + // Resource Type "HII" found + // + if (ResourceDirectoryEntry->u2.s.DataIsDirectory) { + // + // Move to next level - resource Name + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiBinData + ResourceDirectoryEntry->u2.s.OffsetToDirectory); + ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1); + + if (ResourceDirectoryEntry->u2.s.DataIsDirectory) { + // + // Move to next level - resource Language + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiBinData + ResourceDirectoryEntry->u2.s.OffsetToDirectory); + ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1); + } + } + + // + // Now it ought to be resource Data and update its OffsetToData value + // + if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) { + ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (HiiBinData + ResourceDirectoryEntry->u2.OffsetToData); + ResourceDataEntry->OffsetToData = ResourceDataEntry->OffsetToData + OffsetToFile; + break; + } + } + } + ResourceDirectoryEntry++; + } + + return; +} + +EFI_IMAGE_OPTIONAL_HEADER_UNION * +GetPeCoffHeader ( + void *Data + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + + // + // Read the dos & pe hdrs of the image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)Data; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, check for PE/COFF header + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(Data); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + return NULL; + } + } else { + + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(((UINT8 *)Data) + DosHdr->e_lfanew); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + return NULL; + } + } + + return PeHdr; +} + +void +PeCoffConvertImageToXip ( + UINT8 **FileBuffer, + UINT32 *FileLength + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *NewPeHdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN TotalNecessaryFileSize; + UINTN SectionSize; + UINT8 *XipFile; + UINT32 XipLength; + UINTN Index; + UINTN FirstSectionOffset; + BOOLEAN ConversionNeeded; + + PeHdr = GetPeCoffHeader ((void *) *FileBuffer); + if (PeHdr == NULL) { + return; + } + + if (PeHdr->Pe32.OptionalHeader.SectionAlignment != PeHdr->Pe32.OptionalHeader.FileAlignment) { + // + // The only reason to expand zero fill sections is to make them compatible with XIP images. + // If SectionAlignment is not equal to FileAlignment then it is not an XIP type image. + // + return; + } + + // + // Calculate size of XIP file, and determine if the conversion is needed. + // + ConversionNeeded = FALSE; + XipLength = 0; + FirstSectionOffset = *FileLength; + TotalNecessaryFileSize = 0; + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + SectionSize = MAX (SectionHeader->Misc.VirtualSize, SectionHeader->SizeOfRawData); + TotalNecessaryFileSize += SectionSize; + if (SectionSize > 0) { + FirstSectionOffset = MIN (FirstSectionOffset, SectionHeader->VirtualAddress); + XipLength = MAX (XipLength, SectionHeader->VirtualAddress + SectionSize); + if (SectionHeader->VirtualAddress != SectionHeader->PointerToRawData) { + ConversionNeeded = TRUE; + } + } + if (SectionHeader->Misc.VirtualSize > SectionHeader->SizeOfRawData) { + ConversionNeeded = TRUE; + } + } + + if (FirstSectionOffset < PeHdr->Pe32.OptionalHeader.SizeOfHeaders) { + // + // If one of the sections should be loaded to an offset overlapping with + // the executable header, then it cannot be made into an XIP image. + // + VerboseMsg ("PE/COFF conversion to XIP is impossible due to overlap"); + VerboseMsg ("of section data with the executable header."); + return; + } + + if (FirstSectionOffset == *FileLength) { + // + // If we never found a section with a non-zero size, then we + // skip the conversion. + // + return; + } + + TotalNecessaryFileSize += FirstSectionOffset; + + if (!ConversionNeeded) { + return; + } + + if (XipLength > (2 * TotalNecessaryFileSize)) { + VerboseMsg ("PE/COFF conversion to XIP appears to be larger than necessary."); + VerboseMsg ("The image linking process may have left unused memory ranges."); + } + + if (PeHdr->Pe32.FileHeader.PointerToSymbolTable != 0) { + // + // This field is obsolete and should be zero + // + PeHdr->Pe32.FileHeader.PointerToSymbolTable = 0; + } + + // + // Allocate the extra space that we need to grow the image + // + XipFile = malloc (XipLength); + if (XipFile == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + return; + } + memset (XipFile, 0, XipLength); + + // + // Copy the file headers + // + memcpy (XipFile, *FileBuffer, PeHdr->Pe32.OptionalHeader.SizeOfHeaders); + + NewPeHdr = GetPeCoffHeader ((void *)XipFile); + if (NewPeHdr == NULL) { + free (XipFile); + return; + } + + // + // Copy the section data over to the appropriate XIP offsets + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(NewPeHdr->Pe32.OptionalHeader) + NewPeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if (SectionHeader->SizeOfRawData > 0) { + memcpy ( + XipFile + SectionHeader->VirtualAddress, + *FileBuffer + SectionHeader->PointerToRawData, + SectionHeader->SizeOfRawData + ); + } + // + // Make the size of raw data in section header alignment. + // + SectionSize = (SectionHeader->Misc.VirtualSize + PeHdr->Pe32.OptionalHeader.FileAlignment - 1) & (~(PeHdr->Pe32.OptionalHeader.FileAlignment - 1)); + if (SectionSize < SectionHeader->SizeOfRawData) { + SectionHeader->SizeOfRawData = SectionSize; + } + + SectionHeader->PointerToRawData = SectionHeader->VirtualAddress; + } + + free (*FileBuffer); + *FileLength = XipLength; + *FileBuffer = XipFile; + + mIsConvertXip = TRUE; +} + +UINT8 * +CreateHiiResouceSectionHeader ( + UINT32 *pSectionHeaderSize, + UINT32 HiiDataSize + ) +/*++ + +Routine Description: + + Create COFF resource section header + +Arguments: + + pSectionHeaderSize - Pointer to section header size. + HiiDataSize - Size of the total HII data in section. + +Returns: + The created section header buffer. + +--*/ +{ + UINT32 HiiSectionHeaderSize; + UINT32 HiiSectionOffset; + UINT8 *HiiSectionHeader; + EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *TypeResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *NameResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *LanguageResourceDirectoryEntry; + EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString; + EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry; + + // + // Calculate the total size for the resource header (include Type, Name and Language) + // then allocate memory for the resource header. + // + HiiSectionHeaderSize = 3 * (sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY)) + + 3 * (sizeof (UINT16) + 3 * sizeof (CHAR16)) + + sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY); + HiiSectionHeader = malloc (HiiSectionHeaderSize); + if (HiiSectionHeader == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + return NULL; + } + memset (HiiSectionHeader, 0, HiiSectionHeaderSize); + + HiiSectionOffset = 0; + // + // Create Type entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY); + ResourceDirectory->NumberOfNamedEntries = 1; + TypeResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY); + TypeResourceDirectoryEntry->u1.s.NameIsString = 1; + TypeResourceDirectoryEntry->u2.s.DataIsDirectory = 1; + TypeResourceDirectoryEntry->u2.s.OffsetToDirectory = HiiSectionOffset; + // + // Create Name entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY); + ResourceDirectory->NumberOfNamedEntries = 1; + NameResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY); + NameResourceDirectoryEntry->u1.s.NameIsString = 1; + NameResourceDirectoryEntry->u2.s.DataIsDirectory = 1; + NameResourceDirectoryEntry->u2.s.OffsetToDirectory = HiiSectionOffset; + // + // Create Language entry + // + ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY); + ResourceDirectory->NumberOfNamedEntries = 1; + LanguageResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY); + LanguageResourceDirectoryEntry->u1.s.NameIsString = 1; + // + // Create string entry for Type + // + TypeResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset; + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset); + ResourceDirectoryString->Length = 3; + ResourceDirectoryString->String[0] = L'H'; + ResourceDirectoryString->String[1] = L'I'; + ResourceDirectoryString->String[2] = L'I'; + HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]); + // + // Create string entry for Name + // + NameResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset; + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset); + ResourceDirectoryString->Length = 3; + ResourceDirectoryString->String[0] = L'E'; + ResourceDirectoryString->String[1] = L'F'; + ResourceDirectoryString->String[2] = L'I'; + HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]); + // + // Create string entry for Language + // + LanguageResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset; + ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset); + ResourceDirectoryString->Length = 3; + ResourceDirectoryString->String[0] = L'B'; + ResourceDirectoryString->String[1] = L'I'; + ResourceDirectoryString->String[2] = L'N'; + HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]); + // + // Create Leaf data + // + LanguageResourceDirectoryEntry->u2.OffsetToData = HiiSectionOffset; + ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (HiiSectionHeader + HiiSectionOffset); + HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY); + ResourceDataEntry->OffsetToData = HiiSectionOffset; + ResourceDataEntry->Size = HiiDataSize; + + *pSectionHeaderSize = HiiSectionHeaderSize; + return HiiSectionHeader; +} + +EFI_STATUS +RebaseImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINT32 *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file + +Arguments: + + FileHandle - The handle to the PE/COFF file + + FileOffset - The offset, in bytes, into the file to read + + ReadSize - The number of bytes to read from the file starting at FileOffset + + Buffer - A pointer to the buffer to read the data into. + +Returns: + + EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + UINT32 Length; + + Destination8 = Buffer; + Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); + Length = *ReadSize; + while (Length--) { + *(Destination8++) = *(Source8++); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SetAddressToSectionHeader ( + IN CHAR8 *FileName, + IN OUT UINT8 *FileBuffer, + IN UINT64 NewPe32BaseAddress + ) +/*++ + +Routine Description: + + Set new base address into the section header of PeImage + +Arguments: + + FileName - Name of file + FileBuffer - Pointer to PeImage. + NewPe32BaseAddress - New Base Address for PE image. + +Returns: + + EFI_SUCCESS Set new base address into this image successfully. + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINTN Index; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + + // + // Initialize context + // + memset (&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead; + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName); + return Status; + } + + if (ImageContext.RelocationsStripped) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName); + return Status; + } + + // + // Get PeHeader pointer + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset); + + // + // Get section header list + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN) ImgHdr + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + // + // Set base address into the first section header that doesn't point to code section. + // + for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { + *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress; + break; + } + } + + // + // BaseAddress is set to section header. + // + return EFI_SUCCESS; +} + +EFI_STATUS +RebaseImage ( + IN CHAR8 *FileName, + IN OUT UINT8 *FileBuffer, + IN UINT64 NewPe32BaseAddress + ) +/*++ + +Routine Description: + + Set new base address into PeImage, and fix up PeImage based on new address. + +Arguments: + + FileName - Name of file + FileBuffer - Pointer to PeImage. + NewPe32BaseAddress - New Base Address for PE image. + +Returns: + + EFI_INVALID_PARAMETER - BaseAddress is not valid. + EFI_SUCCESS - Update PeImage is correctly. + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINTN Index; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + UINT8 *MemoryImagePointer; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + + // + // Initialize context + // + memset (&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead; + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName); + return Status; + } + + if (ImageContext.RelocationsStripped) { + Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName); + return Status; + } + + // + // Get PeHeader pointer + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset); + + // + // Load and Relocate Image Data + // + MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); + if (MemoryImagePointer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); + return EFI_OUT_OF_RESOURCES; + } + memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); + ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1)); + + Status = PeCoffLoaderLoadImage (&ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName); + free ((VOID *) MemoryImagePointer); + return Status; + } + + ImageContext.DestinationAddress = NewPe32BaseAddress; + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName); + free ((VOID *) MemoryImagePointer); + return Status; + } + + // + // Copy Relocated data to raw image file. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN) ImgHdr + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + CopyMem ( + FileBuffer + SectionHeader->PointerToRawData, + (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), + SectionHeader->SizeOfRawData < SectionHeader->Misc.VirtualSize ? SectionHeader->SizeOfRawData : SectionHeader->Misc.VirtualSize + ); + } + + free ((VOID *) MemoryImagePointer); + + // + // Update Image Base Address + // + if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress; + } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress; + } else { + Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s", + ImgHdr->Pe32.OptionalHeader.Magic, + FileName + ); + return EFI_ABORTED; + } + + // + // Set new base address into section header + // + Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress); + + return Status; +} + +int +main ( + int argc, + char *argv[] + ) +/*++ + +Routine Description: + + Main function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to command line parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + UINT32 Type; + UINT32 InputFileNum; + CHAR8 **InputFileName; + char *OutImageName; + char *ModuleType; + CHAR8 *TimeStamp; + FILE *fpIn; + FILE *fpOut; + FILE *fpInOut; + UINT32 Data; + UINT32 *DataPointer; + UINT32 *OldDataPointer; + UINT32 CheckSum; + UINT32 Index; + UINT32 Index1; + UINT32 Index2; + UINT64 Temp64; + UINT32 MciAlignment; + UINT8 MciPadValue; + UINT32 AllignedRelocSize; + UINT8 *FileBuffer; + UINT32 FileLength; + UINT8 *OutputFileBuffer; + UINT32 OutputFileLength; + UINT8 *InputFileBuffer; + UINT32 InputFileLength; + RUNTIME_FUNCTION *RuntimeFunction; + UNWIND_INFO *UnwindInfo; + STATUS Status; + BOOLEAN ReplaceFlag; + BOOLEAN KeepExceptionTableFlag; + BOOLEAN KeepOptionalHeaderFlag; + BOOLEAN KeepZeroPendingFlag; + UINT64 LogLevel; + EFI_TE_IMAGE_HEADER TEImageHeader; + EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64; + EFI_IMAGE_DOS_HEADER BackupDosHdr; + MICROCODE_IMAGE_HEADER *MciHeader; + UINT8 *HiiPackageListBuffer; + UINT8 *HiiPackageDataPointer; + EFI_GUID HiiPackageListGuid; + EFI_HII_PACKAGE_LIST_HEADER HiiPackageListHeader; + EFI_HII_PACKAGE_HEADER HiiPackageHeader; + EFI_IFR_FORM_SET IfrFormSet; + UINT8 NumberOfFormPackage; + EFI_HII_PACKAGE_HEADER EndPackage; + UINT32 HiiSectionHeaderSize; + UINT8 *HiiSectionHeader; + UINT64 NewBaseAddress; + BOOLEAN NegativeAddr; + FILE *ReportFile; + CHAR8 *ReportFileName; + UINTN FileLen; + time_t InputFileTime; + time_t OutputFileTime; + struct stat Stat_Buf; + BOOLEAN ZeroDebugFlag; + + SetUtilityName (UTILITY_NAME); + + // + // Assign to fix compile warning + // + FileLen = 0; + InputFileNum = 0; + InputFileName = NULL; + mInImageName = NULL; + OutImageName = NULL; + ModuleType = NULL; + Type = 0; + Status = STATUS_SUCCESS; + FileBuffer = NULL; + fpIn = NULL; + fpOut = NULL; + fpInOut = NULL; + TimeStamp = NULL; + MciAlignment = DEFAULT_MC_ALIGNMENT; + MciPadValue = DEFAULT_MC_PAD_BYTE_VALUE; + FileLength = 0; + MciHeader = NULL; + CheckSum = 0; + ReplaceFlag = FALSE; + LogLevel = 0; + OutputFileBuffer = NULL; + OutputFileLength = 0; + InputFileBuffer = NULL; + InputFileLength = 0; + Optional32 = NULL; + Optional64 = NULL; + KeepExceptionTableFlag = FALSE; + KeepOptionalHeaderFlag = FALSE; + KeepZeroPendingFlag = FALSE; + NumberOfFormPackage = 0; + HiiPackageListBuffer = NULL; + HiiPackageDataPointer = NULL; + EndPackage.Length = sizeof (EFI_HII_PACKAGE_HEADER); + EndPackage.Type = EFI_HII_PACKAGE_END; + memset (&HiiPackageListGuid, 0, sizeof (HiiPackageListGuid)); + HiiSectionHeaderSize = 0; + HiiSectionHeader = NULL; + NewBaseAddress = 0; + NegativeAddr = FALSE; + InputFileTime = 0; + OutputFileTime = 0; + ZeroDebugFlag = FALSE; + + if (argc == 1) { + Error (NULL, 0, 1001, "Missing options", "No input options."); + Usage (); + return STATUS_ERROR; + } + + argc --; + argv ++; + + if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) { + Version (); + Usage (); + return STATUS_SUCCESS; + } + + if (stricmp (argv[0], "--version") == 0) { + Version (); + return STATUS_SUCCESS; + } + + while (argc > 0) { + if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + Error (NULL, 0, 1003, "Invalid option value", "Output file name is missing for -o option"); + goto Finish; + } + OutImageName = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-e") == 0) || (stricmp (argv[0], "--efiImage") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + Error (NULL, 0, 1003, "Invalid option value", "Module Type is missing for -o option"); + goto Finish; + } + ModuleType = argv[1]; + if (mOutImageType == FW_ZERO_DEBUG_IMAGE) { + ZeroDebugFlag = TRUE; + } + if (mOutImageType != FW_TE_IMAGE) { + mOutImageType = FW_EFI_IMAGE; + } + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--stripped") == 0)) { + mOutImageType = FW_RELOC_STRIPEED_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--acpi") == 0)) { + mOutImageType = FW_ACPI_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--terse") == 0)) { + if (mOutImageType == FW_ZERO_DEBUG_IMAGE) { + ZeroDebugFlag = TRUE; + } + mOutImageType = FW_TE_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-u") == 0) || (stricmp (argv[0], "--dump") == 0)) { + mOutImageType = DUMP_TE_HEADER; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--exe2bin") == 0)) { + mOutImageType = FW_BIN_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-z") == 0) || (stricmp (argv[0], "--zero") == 0)) { + if (mOutImageType == FW_DUMMY_IMAGE) { + mOutImageType = FW_ZERO_DEBUG_IMAGE; + } + if (mOutImageType == FW_TE_IMAGE || mOutImageType == FW_EFI_IMAGE) { + ZeroDebugFlag = TRUE; + } + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--stamp") == 0)) { + mOutImageType = FW_SET_STAMP_IMAGE; + if (argv[1] == NULL || argv[1][0] == '-') { + Error (NULL, 0, 1003, "Invalid option value", "time stamp is missing for -s option"); + goto Finish; + } + TimeStamp = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--replace") == 0)) { + ReplaceFlag = TRUE; + argc --; + argv ++; + continue; + } + + if (stricmp (argv[0], "--keepexceptiontable") == 0) { + KeepExceptionTableFlag = TRUE; + argc --; + argv ++; + continue; + } + + if (stricmp(argv[0], "--keepoptionalheader") == 0) { + KeepOptionalHeaderFlag = TRUE; + argc--; + argv++; + continue; + } + + if (stricmp (argv[0], "--keepzeropending") == 0) { + KeepZeroPendingFlag = TRUE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-m") == 0) || (stricmp (argv[0], "--mcifile") == 0)) { + mOutImageType = FW_MCI_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--join") == 0)) { + mOutImageType = FW_MERGE_IMAGE; + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) { + if (AsciiStringToUint64 (argv[1], FALSE, &Temp64) != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + MciAlignment = (UINT32) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "--rebase") == 0)) { + if (argv[1][0] == '-') { + NegativeAddr = TRUE; + Status = AsciiStringToUint64 (argv[1] + 1, FALSE, &Temp64); + } else { + NegativeAddr = FALSE; + Status = AsciiStringToUint64 (argv[1], FALSE, &Temp64); + } + if (Status != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + mOutImageType = FW_REBASE_IMAGE; + NewBaseAddress = (UINT64) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "--address") == 0)) { + if (argv[1][0] == '-') { + NegativeAddr = TRUE; + Status = AsciiStringToUint64 (argv[1] + 1, FALSE, &Temp64); + } else { + NegativeAddr = FALSE; + Status = AsciiStringToUint64 (argv[1], FALSE, &Temp64); + } + if (Status != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + mOutImageType = FW_SET_ADDRESS_IMAGE; + NewBaseAddress = (UINT64) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-p") == 0) || (stricmp (argv[0], "--pad") == 0)) { + if (AsciiStringToUint64 (argv[1], FALSE, &Temp64) != EFI_SUCCESS) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + MciPadValue = (UINT8) Temp64; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) { + SetPrintLevel (VERBOSE_LOG_LEVEL); + VerboseMsg ("Verbose output Mode Set!"); + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) { + SetPrintLevel (KEY_LOG_LEVEL); + KeyMsg ("Quiet output Mode Set!"); + argc --; + argv ++; + continue; + } + + if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) { + Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + if (LogLevel > 9) { + Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel); + goto Finish; + } + SetPrintLevel (LogLevel); + DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]); + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--hiiguid") == 0)) { + Status = StringToGuid (argv[1], &HiiPackageListGuid); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); + goto Finish; + } + argc -= 2; + argv += 2; + continue; + } + + if (stricmp (argv[0], "--hiipackage") == 0) { + mOutImageType = FW_HII_PACKAGE_LIST_RCIMAGE; + argc --; + argv ++; + continue; + } + + if (stricmp (argv[0], "--hiibinpackage") == 0) { + mOutImageType = FW_HII_PACKAGE_LIST_BINIMAGE; + argc --; + argv ++; + continue; + } + + if (stricmp (argv[0], "--prm") == 0) { + if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") != 0 ){ + Error (NULL, 0, 1001, "Invalid", "--prm option only supports DXE RUNTIME driver."); + goto Finish; + } + + if (!mExportFlag) { + mExportFlag = TRUE; + } + argc --; + argv ++; + continue; + } + + if (argv[0][0] == '-') { + Error (NULL, 0, 1000, "Unknown option", argv[0]); + goto Finish; + } + // + // Get Input file name + // + if ((InputFileNum == 0) && (InputFileName == NULL)) { + InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)); + if (InputFileName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + + memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); + } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) { + // + // InputFileName buffer too small, need to realloc + // + InputFileName = (CHAR8 **) realloc ( + InputFileName, + (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *) + ); + + if (InputFileName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + + memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); + } + + InputFileName [InputFileNum ++] = argv[0]; + argc --; + argv ++; + } + + VerboseMsg ("%s tool start.", UTILITY_NAME); + + if (mOutImageType == FW_DUMMY_IMAGE) { + Error (NULL, 0, 1001, "Missing option", "No create file action specified; pls specify -e, -c or -t option to create efi image, or acpi table or TeImage!"); + if (ReplaceFlag) { + Error (NULL, 0, 1001, "Missing option", "-r option is not supported as the independent option. It can be used together with other create file option specified at the above."); + } + goto Finish; + } + + // + // check input files + // + if (InputFileNum == 0) { + Error (NULL, 0, 1001, "Missing option", "Input files"); + goto Finish; + } + + // + // Combine MciBinary files to one file + // + if ((mOutImageType == FW_MERGE_IMAGE) && ReplaceFlag) { + Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with -j merge files option."); + goto Finish; + } + + // + // Combine HiiBinary packages to a single package list + // + if ((mOutImageType == FW_HII_PACKAGE_LIST_RCIMAGE) && ReplaceFlag) { + Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with --hiipackage merge files option."); + goto Finish; + } + + if ((mOutImageType == FW_HII_PACKAGE_LIST_BINIMAGE) && ReplaceFlag) { + Error (NULL, 0, 1002, "Conflicting option", "-r replace option cannot be used with --hiibinpackage merge files option."); + goto Finish; + } + + // + // Input image file + // + mInImageName = InputFileName [InputFileNum - 1]; + VerboseMsg ("the input file name is %s", mInImageName); + + // + // Action will be taken for the input file. + // + switch (mOutImageType) { + case FW_EFI_IMAGE: + VerboseMsg ("Create efi image on module type %s based on the input PE image.", ModuleType); + break; + case FW_TE_IMAGE: + VerboseMsg ("Create Te Image based on the input PE image."); + break; + case FW_ACPI_IMAGE: + VerboseMsg ("Get acpi table data from the input PE image."); + break; + case FW_RELOC_STRIPEED_IMAGE: + VerboseMsg ("Remove relocation section from Pe or Te image."); + break; + case FW_BIN_IMAGE: + VerboseMsg ("Convert the input EXE to the output BIN file."); + break; + case FW_ZERO_DEBUG_IMAGE: + VerboseMsg ("Zero the Debug Data Fields and Time Stamp in input PE image."); + break; + case FW_SET_STAMP_IMAGE: + VerboseMsg ("Set new time stamp %s in the input PE image.", TimeStamp); + break; + case DUMP_TE_HEADER: + VerboseMsg ("Dump the TE header information of the input TE image."); + break; + case FW_MCI_IMAGE: + VerboseMsg ("Convert input MicroCode.txt file to MicroCode.bin file."); + break; + case FW_MERGE_IMAGE: + VerboseMsg ("Combine the input multi microcode bin files to one bin file."); + break; + case FW_HII_PACKAGE_LIST_RCIMAGE: + VerboseMsg ("Combine the input multi hii bin packages to one text package list RC file."); + break; + case FW_HII_PACKAGE_LIST_BINIMAGE: + VerboseMsg ("Combine the input multi hii bin packages to one binary package list file."); + break; + case FW_REBASE_IMAGE: + VerboseMsg ("Rebase the input image to new base address."); + break; + case FW_SET_ADDRESS_IMAGE: + VerboseMsg ("Set the preferred address into the section header of the input image"); + break; + default: + break; + } + + if (ReplaceFlag) { + VerboseMsg ("Overwrite the input file with the output content."); + } + + // + // Open output file and Write image into the output file. + // + if (OutImageName != NULL) { + fpOut = fopen (LongFilePath (OutImageName), "rb"); + if (fpOut != NULL) { + // + // Get Output file time stamp + // + fstat(fileno (fpOut), &Stat_Buf); + OutputFileTime = Stat_Buf.st_mtime; + // + // Get Output file data + // + OutputFileLength = _filelength (fileno (fpOut)); + OutputFileBuffer = malloc (OutputFileLength); + if (OutputFileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + fclose (fpOut); + fpOut = NULL; + goto Finish; + } + fread (OutputFileBuffer, 1, OutputFileLength, fpOut); + fclose (fpOut); + fpOut = NULL; + } + VerboseMsg ("Output file name is %s", OutImageName); + } else if (!ReplaceFlag && mOutImageType != DUMP_TE_HEADER) { + Error (NULL, 0, 1001, "Missing option", "output file"); + goto Finish; + } + + // + // Open input file and read file data into file buffer. + // + fpIn = fopen (LongFilePath (mInImageName), "rb"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + // + // Get Iutput file time stamp + // + fstat(fileno (fpIn), &Stat_Buf); + InputFileTime = Stat_Buf.st_mtime; + // + // Get Input file data + // + InputFileLength = _filelength (fileno (fpIn)); + InputFileBuffer = malloc (InputFileLength); + if (InputFileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + fclose (fpIn); + goto Finish; + } + fread (InputFileBuffer, 1, InputFileLength, fpIn); + fclose (fpIn); + DebugMsg (NULL, 0, 9, "input file info", "the input file size is %u bytes", (unsigned) InputFileLength); + + // + // Combine multi binary HII package files. + // + if (mOutImageType == FW_HII_PACKAGE_LIST_RCIMAGE || mOutImageType == FW_HII_PACKAGE_LIST_BINIMAGE) { + // + // Open output file handle. + // + fpOut = fopen (LongFilePath (OutImageName), "wb"); + if (!fpOut) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + // + // Get hii package list length + // + HiiPackageListHeader.PackageLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + for (Index = 0; Index < InputFileNum; Index ++) { + fpIn = fopen (LongFilePath (InputFileName [Index]), "rb"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]); + goto Finish; + } + FileLength = _filelength (fileno (fpIn)); + fread (&HiiPackageHeader, 1, sizeof (HiiPackageHeader), fpIn); + if (HiiPackageHeader.Type == EFI_HII_PACKAGE_FORM) { + if (HiiPackageHeader.Length != FileLength) { + Error (NULL, 0, 3000, "Invalid", "The wrong package size is in HII package file %s", InputFileName [Index]); + fclose (fpIn); + goto Finish; + } + if (memcmp (&HiiPackageListGuid, &mZeroGuid, sizeof (EFI_GUID)) == 0) { + fread (&IfrFormSet, 1, sizeof (IfrFormSet), fpIn); + memcpy (&HiiPackageListGuid, &IfrFormSet.Guid, sizeof (EFI_GUID)); + } + NumberOfFormPackage ++; + } + HiiPackageListHeader.PackageLength += FileLength; + fclose (fpIn); + } + HiiPackageListHeader.PackageLength += sizeof (EndPackage); + // + // Check whether hii packages are valid + // + if (NumberOfFormPackage > 1) { + Error (NULL, 0, 3000, "Invalid", "The input hii packages contains more than one hii form package"); + goto Finish; + } + if (memcmp (&HiiPackageListGuid, &mZeroGuid, sizeof (EFI_GUID)) == 0) { + Error (NULL, 0, 3000, "Invalid", "HII package list guid is not specified!"); + goto Finish; + } + memcpy (&HiiPackageListHeader.PackageListGuid, &HiiPackageListGuid, sizeof (EFI_GUID)); + // + // read hii packages + // + HiiPackageListBuffer = malloc (HiiPackageListHeader.PackageLength); + if (HiiPackageListBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + memcpy (HiiPackageListBuffer, &HiiPackageListHeader, sizeof (HiiPackageListHeader)); + HiiPackageDataPointer = HiiPackageListBuffer + sizeof (HiiPackageListHeader); + for (Index = 0; Index < InputFileNum; Index ++) { + fpIn = fopen (LongFilePath (InputFileName [Index]), "rb"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]); + free (HiiPackageListBuffer); + goto Finish; + } + + FileLength = _filelength (fileno (fpIn)); + fread (HiiPackageDataPointer, 1, FileLength, fpIn); + fclose (fpIn); + HiiPackageDataPointer = HiiPackageDataPointer + FileLength; + } + memcpy (HiiPackageDataPointer, &EndPackage, sizeof (EndPackage)); + + // + // write the hii package into the binary package list file with the resource section header + // + if (mOutImageType == FW_HII_PACKAGE_LIST_BINIMAGE) { + // + // Create the resource section header + // + HiiSectionHeader = CreateHiiResouceSectionHeader (&HiiSectionHeaderSize, HiiPackageListHeader.PackageLength); + if (HiiSectionHeader == NULL) { + free (HiiPackageListBuffer); + goto Finish; + } + // + // Wrtie section header and HiiData into File. + // + fwrite (HiiSectionHeader, 1, HiiSectionHeaderSize, fpOut); + fwrite (HiiPackageListBuffer, 1, HiiPackageListHeader.PackageLength, fpOut); + // + // Free allocated resources. + // + free (HiiSectionHeader); + free (HiiPackageListBuffer); + // + // Done successfully + // + goto Finish; + } + + // + // write the hii package into the text package list rc file. + // + if (mOutImageType == FW_HII_PACKAGE_LIST_RCIMAGE) { + for (Index = 0; gHiiPackageRCFileHeader[Index] != NULL; Index++) { + fprintf (fpOut, "%s\n", gHiiPackageRCFileHeader[Index]); + } + fprintf (fpOut, "\n%d %s\n{", HII_RESOURCE_SECTION_INDEX, HII_RESOURCE_SECTION_NAME); + + HiiPackageDataPointer = HiiPackageListBuffer; + for (Index = 0; Index + 2 < HiiPackageListHeader.PackageLength; Index += 2) { + if (Index % 16 == 0) { + fprintf (fpOut, "\n "); + } + fprintf (fpOut, " 0x%04X,", *(UINT16 *) HiiPackageDataPointer); + HiiPackageDataPointer += 2; + } + + if (Index % 16 == 0) { + fprintf (fpOut, "\n "); + } + if ((Index + 2) == HiiPackageListHeader.PackageLength) { + fprintf (fpOut, " 0x%04X\n}\n", *(UINT16 *) HiiPackageDataPointer); + } + if ((Index + 1) == HiiPackageListHeader.PackageLength) { + fprintf (fpOut, " 0x%04X\n}\n", *(UINT8 *) HiiPackageDataPointer); + } + free (HiiPackageListBuffer); + // + // Done successfully + // + goto Finish; + } + } + + // + // Combine MciBinary files to one file + // + if (mOutImageType == FW_MERGE_IMAGE) { + // + // Open output file handle. + // + fpOut = fopen (LongFilePath (OutImageName), "wb"); + if (!fpOut) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + for (Index = 0; Index < InputFileNum; Index ++) { + fpIn = fopen (LongFilePath (InputFileName [Index]), "rb"); + if (!fpIn) { + Error (NULL, 0, 0001, "Error opening file", InputFileName [Index]); + goto Finish; + } + + FileLength = _filelength (fileno (fpIn)); + FileBuffer = malloc (FileLength); + if (FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + fclose (fpIn); + goto Finish; + } + + fread (FileBuffer, 1, FileLength, fpIn); + fclose (fpIn); + // + // write input file to out file + // + fwrite (FileBuffer, 1, FileLength, fpOut); + // + // write pad value to out file. + // + while (FileLength ++ % MciAlignment != 0) { + fwrite (&MciPadValue, 1, 1, fpOut); + } + // + // free allocated memory space + // + free (FileBuffer); + FileBuffer = NULL; + } + // + // Done successfully + // + goto Finish; + } + + // + // Convert MicroCode.txt file to MicroCode.bin file + // + if (mOutImageType == FW_MCI_IMAGE) { + fpIn = fopen (LongFilePath (mInImageName), "r"); + if (fpIn == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + + // + // The first pass is to determine + // how much data is in the file so we can allocate a working buffer. + // + FileLength = 0; + do { + Status = MicrocodeReadData (fpIn, &Data); + if (Status == STATUS_SUCCESS) { + FileLength += sizeof (Data); + } + if (Status == STATUS_IGNORE) { + Status = STATUS_SUCCESS; + } + } while (Status == STATUS_SUCCESS); + // + // Error if no data. + // + if (FileLength == 0) { + Error (NULL, 0, 3000, "Invalid", "no parseable data found in file %s", mInImageName); + goto Finish; + } + if (FileLength < sizeof (MICROCODE_IMAGE_HEADER)) { + Error (NULL, 0, 3000, "Invalid", "amount of parseable data in %s is insufficient to contain a microcode header", mInImageName); + goto Finish; + } + + // + // Allocate a buffer for the data + // + FileBuffer = malloc (FileLength); + if (FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + // + // Re-read the file, storing the data into our buffer + // + fseek (fpIn, 0, SEEK_SET); + DataPointer = (UINT32 *) FileBuffer; + OldDataPointer = DataPointer; + do { + OldDataPointer = DataPointer; + Status = MicrocodeReadData (fpIn, DataPointer++); + if (Status == STATUS_IGNORE) { + DataPointer = OldDataPointer; + Status = STATUS_SUCCESS; + } + } while (Status == STATUS_SUCCESS); + // + // close input file after read data + // + fclose (fpIn); + + // + // Can't do much checking on the header because, per the spec, the + // DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K, + // and the TotalSize field is invalid (actually missing). Thus we can't + // even verify the Reserved fields are 0. + // + MciHeader = (MICROCODE_IMAGE_HEADER *) FileBuffer; + if (MciHeader->DataSize == 0) { + Index = 2048; + } else { + Index = MciHeader->TotalSize; + } + + if (Index != FileLength) { + Error (NULL, 0, 3000, "Invalid", "file length of %s (0x%x) does not equal expected TotalSize: 0x%04X.", mInImageName, (unsigned) FileLength, (unsigned) Index); + goto Finish; + } + + // + // Checksum the contents + // + DataPointer = (UINT32 *) FileBuffer; + CheckSum = 0; + Index = 0; + while (Index < FileLength) { + CheckSum += *DataPointer; + DataPointer ++; + Index += sizeof (*DataPointer); + } + if (CheckSum != 0) { + Error (NULL, 0, 3000, "Invalid", "checksum (0x%x) failed on file %s.", (unsigned) CheckSum, mInImageName); + goto Finish; + } + // + // Open the output file and write the buffer contents + // + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Open input file and read file data into file buffer. + // + FileLength = InputFileLength; + FileBuffer = malloc (FileLength); + if (FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + goto Finish; + } + memcpy (FileBuffer, InputFileBuffer, InputFileLength); + + // + // Dump TeImage Header into output file. + // + if (mOutImageType == DUMP_TE_HEADER) { + memcpy (&TEImageHeader, FileBuffer, sizeof (TEImageHeader)); + if (TEImageHeader.Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "TE header signature of file %s is not correct.", mInImageName); + goto Finish; + } + // + // Open the output file handle. + // + if (ReplaceFlag) { + fpInOut = fopen (LongFilePath (mInImageName), "wb"); + if (fpInOut == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + } else { + if (OutImageName != NULL) { + fpOut = fopen (LongFilePath (OutImageName), "wb"); + } else { + fpOut = stdout; + } + if (fpOut == NULL) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + } + if (fpInOut != NULL) { + fprintf (fpInOut, "Dump of file %s\n\n", mInImageName); + fprintf (fpInOut, "TE IMAGE HEADER VALUES\n"); + fprintf (fpInOut, "%17X machine\n", TEImageHeader.Machine); + fprintf (fpInOut, "%17X number of sections\n", TEImageHeader.NumberOfSections); + fprintf (fpInOut, "%17X subsystems\n", TEImageHeader.Subsystem); + fprintf (fpInOut, "%17X stripped size\n", TEImageHeader.StrippedSize); + fprintf (fpInOut, "%17X entry point\n", (unsigned) TEImageHeader.AddressOfEntryPoint); + fprintf (fpInOut, "%17X base of code\n", (unsigned) TEImageHeader.BaseOfCode); + fprintf (fpInOut, "%17llX image base\n", (unsigned long long)TEImageHeader.ImageBase); + fprintf (fpInOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", (unsigned) TEImageHeader.DataDirectory[0].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[0].Size); + fprintf (fpInOut, "%17X [%8X] RVA [size] of Debug Directory\n", (unsigned) TEImageHeader.DataDirectory[1].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[1].Size); + } + if (fpOut != NULL) { + fprintf (fpOut, "Dump of file %s\n\n", mInImageName); + fprintf (fpOut, "TE IMAGE HEADER VALUES\n"); + fprintf (fpOut, "%17X machine\n", TEImageHeader.Machine); + fprintf (fpOut, "%17X number of sections\n", TEImageHeader.NumberOfSections); + fprintf (fpOut, "%17X subsystems\n", TEImageHeader.Subsystem); + fprintf (fpOut, "%17X stripped size\n", TEImageHeader.StrippedSize); + fprintf (fpOut, "%17X entry point\n", (unsigned) TEImageHeader.AddressOfEntryPoint); + fprintf (fpOut, "%17X base of code\n", (unsigned) TEImageHeader.BaseOfCode); + fprintf (fpOut, "%17llX image base\n", (unsigned long long)TEImageHeader.ImageBase); + fprintf (fpOut, "%17X [%8X] RVA [size] of Base Relocation Directory\n", (unsigned) TEImageHeader.DataDirectory[0].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[0].Size); + fprintf (fpOut, "%17X [%8X] RVA [size] of Debug Directory\n", (unsigned) TEImageHeader.DataDirectory[1].VirtualAddress, (unsigned) TEImageHeader.DataDirectory[1].Size); + } + goto Finish; + } + + // + // Following code to convert dll to efi image or te image. + // Get new image type + // + if ((mOutImageType == FW_EFI_IMAGE) || (mOutImageType == FW_TE_IMAGE)) { + if (ModuleType == NULL) { + if (mOutImageType == FW_EFI_IMAGE) { + Error (NULL, 0, 1001, "Missing option", "EFI_FILETYPE"); + goto Finish; + } else if (mOutImageType == FW_TE_IMAGE) { + // + // Default TE Image Type is Boot service driver + // + Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi boot service driver."); + } + } else { + if (stricmp (ModuleType, "BASE") == 0 || + stricmp (ModuleType, "SEC") == 0 || + stricmp (ModuleType, "SECURITY_CORE") == 0 || + stricmp (ModuleType, "PEI_CORE") == 0 || + stricmp (ModuleType, "PEIM") == 0 || + stricmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0 || + stricmp (ModuleType, "PIC_PEIM") == 0 || + stricmp (ModuleType, "RELOCATABLE_PEIM") == 0 || + stricmp (ModuleType, "DXE_CORE") == 0 || + stricmp (ModuleType, "BS_DRIVER") == 0 || + stricmp (ModuleType, "DXE_DRIVER") == 0 || + stricmp (ModuleType, "DXE_SMM_DRIVER") == 0 || + stricmp (ModuleType, "UEFI_DRIVER") == 0 || + stricmp (ModuleType, "SMM_CORE") == 0 || + stricmp (ModuleType, "MM_STANDALONE") == 0 || + stricmp (ModuleType, "MM_CORE_STANDALONE") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi boot service driver."); + + } else if (stricmp (ModuleType, "UEFI_APPLICATION") == 0 || + stricmp (ModuleType, "APPLICATION") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION; + VerboseMsg ("Efi Image subsystem type is efi application."); + + } else if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0 || + stricmp (ModuleType, "RT_DRIVER") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi runtime driver."); + + } else if (stricmp (ModuleType, "DXE_SAL_DRIVER") == 0 || + stricmp (ModuleType, "SAL_RT_DRIVER") == 0) { + Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER; + VerboseMsg ("Efi Image subsystem type is efi sal runtime driver."); + + } else { + Error (NULL, 0, 1003, "Invalid option value", "EFI_FILETYPE = %s", ModuleType); + goto Finish; + } + } + } + + // + // Convert ELF image to PeImage + // + if (IsElfHeader(FileBuffer)) { + VerboseMsg ("Convert %s from ELF to PE/COFF.", mInImageName); + if (!ConvertElf(&FileBuffer, &FileLength)) { + Error (NULL, 0, 3000, "Invalid", "Unable to convert %s from ELF to PE/COFF.", mInImageName); + goto Finish; + } + } + + // + // Make sure File Offsets and Virtual Offsets are the same in the image so it is XIP + // XIP == eXecute In Place + // + PeCoffConvertImageToXip (&FileBuffer, &FileLength); + + // + // Remove reloc section from PE or TE image + // + if (mOutImageType == FW_RELOC_STRIPEED_IMAGE) { + // + // Check TeImage + // + TeHdr = (EFI_TE_IMAGE_HEADER *) FileBuffer; + if (TeHdr->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TeHdr + 1); + for (Index = 0; Index < TeHdr->NumberOfSections; Index ++, SectionHeader ++) { + if (strcmp ((char *)SectionHeader->Name, ".reloc") == 0) { + // + // Check the reloc section is in the end of image. + // + if ((SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData) == + (FileLength + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER))) { + // + // Remove .reloc section and update TeImage Header + // + FileLength = FileLength - SectionHeader->SizeOfRawData; + SectionHeader->SizeOfRawData = 0; + SectionHeader->Misc.VirtualSize = 0; + TeHdr->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + TeHdr->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; + break; + } + } + } + } else { + // + // Check PE Image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "TE and DOS header signatures were not found in %s image.", mInImageName); + goto Finish; + } + DosHdr = NULL; + } else { + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + DosHdr->e_lfanew); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "PE header signature was not found in %s image.", mInImageName); + goto Finish; + } + } + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if (strcmp ((char *)SectionHeader->Name, ".reloc") == 0) { + // + // Check the reloc section is in the end of image. + // + if ((SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData) == FileLength) { + // + // Remove .reloc section and update PeImage Header + // + FileLength = FileLength - SectionHeader->SizeOfRawData; + + PeHdr->Pe32.FileHeader.Characteristics |= EFI_IMAGE_FILE_RELOCS_STRIPPED; + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + Optional32->SizeOfImage -= SectionHeader->SizeOfRawData; + Optional32->SizeOfInitializedData -= SectionHeader->SizeOfRawData; + if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; + } + } + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + Optional64->SizeOfImage -= SectionHeader->SizeOfRawData; + Optional64->SizeOfInitializedData -= SectionHeader->SizeOfRawData; + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; + } + } + SectionHeader->Misc.VirtualSize = 0; + SectionHeader->SizeOfRawData = 0; + break; + } + } + } + } + // + // Write file + // + goto WriteFile; + } + // + // Read the dos & pe hdrs of the image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, check for PE/COFF header + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "DOS header signature was not found in %s image.", mInImageName); + goto Finish; + } + DosHdr = NULL; + } else { + + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + DosHdr->e_lfanew); + if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "PE header signature was not found in %s image.", mInImageName); + goto Finish; + } + } + + // + // Set new base address into image + // + if (mOutImageType == FW_REBASE_IMAGE || mOutImageType == FW_SET_ADDRESS_IMAGE) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (NewBaseAddress >= 0x100000000ULL) { + Error (NULL, 0, 3000, "Invalid", "New base address is larger than 4G for 32bit PE image"); + goto Finish; + } + } + + if (NegativeAddr) { + // + // Set Base Address to a negative value. + // + NewBaseAddress = (UINT64) (0 - NewBaseAddress); + } + if (mOutImageType == FW_REBASE_IMAGE) { + Status = RebaseImage (mInImageName, FileBuffer, NewBaseAddress); + } else { + Status = SetAddressToSectionHeader (mInImageName, FileBuffer, NewBaseAddress); + } + if (EFI_ERROR (Status)) { + if (NegativeAddr) { + Error (NULL, 0, 3000, "Invalid", "Rebase/Set Image %s to Base address -0x%llx can't success", mInImageName, 0 - NewBaseAddress); + } else { + Error (NULL, 0, 3000, "Invalid", "Rebase/Set Image %s to Base address 0x%llx can't success", mInImageName, NewBaseAddress); + } + goto Finish; + } + + // + // Write file + // + goto WriteFile; + } + + // + // Extract bin data from Pe image. + // + if (mOutImageType == FW_BIN_IMAGE) { + if (FileLength < PeHdr->Pe32.OptionalHeader.SizeOfHeaders) { + Error (NULL, 0, 3000, "Invalid", "FileSize of %s is not a legal size.", mInImageName); + goto Finish; + } + // + // Output bin data from exe file + // + FileLength = FileLength - PeHdr->Pe32.OptionalHeader.SizeOfHeaders; + memmove (FileBuffer, FileBuffer + PeHdr->Pe32.OptionalHeader.SizeOfHeaders, FileLength); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Zero Debug Information of Pe Image + // + if (mOutImageType == FW_ZERO_DEBUG_IMAGE) { + Status = ZeroDebugData (FileBuffer, TRUE); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "Zero DebugData Error status is 0x%x", (int) Status); + goto Finish; + } + + // + // Write the updated Image + // + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Set Time Stamp of Pe Image + // + if (mOutImageType == FW_SET_STAMP_IMAGE) { + Status = SetStamp (FileBuffer, TimeStamp); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Write the updated Image + // + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + + // + // Extract acpi data from pe image. + // + if (mOutImageType == FW_ACPI_IMAGE) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { + if (strcmp ((char *)SectionHeader->Name, ".data") == 0 || strcmp ((char *)SectionHeader->Name, ".sdata") == 0) { + // + // Check Acpi Table + // + if (SectionHeader->Misc.VirtualSize < SectionHeader->SizeOfRawData) { + FileLength = SectionHeader->Misc.VirtualSize; + } else { + FileLength = SectionHeader->SizeOfRawData; + } + + if (CheckAcpiTable (FileBuffer + SectionHeader->PointerToRawData, FileLength) != STATUS_SUCCESS) { + Error (NULL, 0, 3000, "Invalid", "ACPI table check failed in %s.", mInImageName); + goto Finish; + } + + // + // Output Apci data to file + // + memmove (FileBuffer, FileBuffer + SectionHeader->PointerToRawData, FileLength); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + goto WriteFile; + } + } + Error (NULL, 0, 3000, "Invalid", "failed to get ACPI table from %s.", mInImageName); + goto Finish; + } + // + // Zero all unused fields of the DOS header + // + if (DosHdr != NULL) { + memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER)); + memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER)); + DosHdr->e_magic = BackupDosHdr.e_magic; + DosHdr->e_lfanew = BackupDosHdr.e_lfanew; + + for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (UINT32 ) DosHdr->e_lfanew; Index++) { + FileBuffer[Index] = (UINT8) DosHdr->e_cp; + } + } + + // + // Initialize TeImage Header + // + memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER)); + TEImageHeader.Signature = EFI_TE_IMAGE_HEADER_SIGNATURE; + TEImageHeader.Machine = PeHdr->Pe32.FileHeader.Machine; + TEImageHeader.NumberOfSections = (UINT8) PeHdr->Pe32.FileHeader.NumberOfSections; + TEImageHeader.StrippedSize = (UINT16) ((UINTN) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader) - (UINTN) FileBuffer); + TEImageHeader.Subsystem = (UINT8) Type; + + // + // Patch the PE header + // + PeHdr->Pe32.OptionalHeader.Subsystem = (UINT16) Type; + + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + if (!KeepOptionalHeaderFlag) { + Optional32->MajorOperatingSystemVersion = 0; + Optional32->MinorOperatingSystemVersion = 0; + Optional32->MajorImageVersion = 0; + Optional32->MinorImageVersion = 0; + Optional32->MajorSubsystemVersion = 0; + Optional32->MinorSubsystemVersion = 0; + Optional32->Win32VersionValue = 0; + Optional32->CheckSum = 0; + Optional32->SizeOfStackReserve = 0; + Optional32->SizeOfStackCommit = 0; + Optional32->SizeOfHeapReserve = 0; + Optional32->SizeOfHeapCommit = 0; + } + TEImageHeader.AddressOfEntryPoint = Optional32->AddressOfEntryPoint; + TEImageHeader.BaseOfCode = Optional32->BaseOfCode; + TEImageHeader.ImageBase = (UINT64) (Optional32->ImageBase); + + if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + } + + // + // Zero .pdata section data. + // + if (!KeepExceptionTableFlag && Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION && + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0 && + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) { + // + // Zero .pdata Section data + // + memset (FileBuffer + SectionHeader->PointerToRawData, 0, SectionHeader->SizeOfRawData); + // + // Zero .pdata Section header name + // + memset (SectionHeader->Name, 0, sizeof (SectionHeader->Name)); + // + // Zero Exception Table + // + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0; + DebugMsg (NULL, 0, 9, "Zero the .pdata section for PE image", NULL); + break; + } + } + } + + // + // Strip zero padding at the end of the .reloc section + // + if (!KeepZeroPendingFlag && Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + if (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + // + // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory + // + if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) { + SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + AllignedRelocSize = (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1)); + // + // Check to see if there is zero padding at the end of the base relocations + // + if (AllignedRelocSize < SectionHeader->SizeOfRawData) { + // + // Check to see if the base relocations are at the end of the file + // + if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) { + // + // All the required conditions are met to strip the zero padding of the end of the base relocations section + // + Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + SectionHeader->SizeOfRawData = AllignedRelocSize; + FileLength = Optional32->SizeOfImage; + DebugMsg (NULL, 0, 9, "Remove the zero padding bytes at the end of the base relocations", "The size of padding bytes is %u", (unsigned) (SectionHeader->SizeOfRawData - AllignedRelocSize)); + } + } + } + } + } + } + } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + if (!KeepOptionalHeaderFlag) { + Optional64->MajorOperatingSystemVersion = 0; + Optional64->MinorOperatingSystemVersion = 0; + Optional64->MajorImageVersion = 0; + Optional64->MinorImageVersion = 0; + Optional64->MajorSubsystemVersion = 0; + Optional64->MinorSubsystemVersion = 0; + Optional64->Win32VersionValue = 0; + Optional64->CheckSum = 0; + Optional64->SizeOfStackReserve = 0; + Optional64->SizeOfStackCommit = 0; + Optional64->SizeOfHeapReserve = 0; + Optional64->SizeOfHeapCommit = 0; + } + TEImageHeader.AddressOfEntryPoint = Optional64->AddressOfEntryPoint; + TEImageHeader.BaseOfCode = Optional64->BaseOfCode; + TEImageHeader.ImageBase = (UINT64) (Optional64->ImageBase); + + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + } + + // + // Zero the .pdata section for X64 machine and don't check the Debug Directory is empty + // For Itaninum and X64 Image, remove .pdata section. + // + if ((!KeepExceptionTableFlag && PeHdr->Pe32.FileHeader.Machine == IMAGE_FILE_MACHINE_X64)) { + if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION && + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0 && + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) { + // + // Zero .pdata Section header name + // + memset (SectionHeader->Name, 0, sizeof (SectionHeader->Name)); + + RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData); + for (Index1 = 0; Index1 < Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index2 = 0; Index2 < PeHdr->Pe32.FileHeader.NumberOfSections; Index2++, SectionHeader++) { + if (RuntimeFunction->UnwindInfoAddress >= SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) { + UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress)); + if (UnwindInfo->Version == 1) { + memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16)); + memset (UnwindInfo, 0, sizeof (UNWIND_INFO)); + } + break; + } + } + memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION)); + } + // + // Zero Exception Table + // + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0; + DebugMsg (NULL, 0, 9, "Zero the .pdata section if the machine type is X64 for PE32+ image", NULL); + break; + } + } + } + } + + // + // Strip zero padding at the end of the .reloc section + // + if (!KeepZeroPendingFlag && Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + if (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + // + // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory + // + if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) { + SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + AllignedRelocSize = (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1)); + // + // Check to see if there is zero padding at the end of the base relocations + // + if (AllignedRelocSize < SectionHeader->SizeOfRawData) { + // + // Check to see if the base relocations are at the end of the file + // + if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) { + // + // All the required conditions are met to strip the zero padding of the end of the base relocations section + // + Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize); + SectionHeader->SizeOfRawData = AllignedRelocSize; + FileLength = Optional64->SizeOfImage; + DebugMsg (NULL, 0, 9, "Remove the zero padding bytes at the end of the base relocations", "The size of padding bytes is %u", (unsigned) (SectionHeader->SizeOfRawData - AllignedRelocSize)); + } + } + } + } + } + } + } else { + Error (NULL, 0, 3000, "Invalid", "Magic 0x%x of PeImage %s is unknown.", PeHdr->Pe32.OptionalHeader.Magic, mInImageName); + goto Finish; + } + + if (((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) == 0) && \ + (TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0) && \ + (TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0)) { + // + // PeImage can be loaded into memory, but it has no relocation section. + // Fix TeImage Header to set VA of relocation data directory to not zero, the size is still zero. + // + if (Optional32 != NULL) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->SizeOfImage - sizeof (EFI_IMAGE_BASE_RELOCATION); + } else if (Optional64 != NULL) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->SizeOfImage - sizeof (EFI_IMAGE_BASE_RELOCATION); + } + } + + // + // Fill HII section data + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) { + if (stricmp ((char *)SectionHeader[Index].Name, ".hii") == 0) { + // + // Update resource section header offset + // + SetHiiResourceHeader ((UINT8*) FileBuffer + SectionHeader[Index].PointerToRawData, SectionHeader[Index].VirtualAddress); + // + // Update resource section name + // + strcpy((char *) SectionHeader[Index].Name, ".rsrc"); + // + // Update resource data directory. + // + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = SectionHeader[Index].VirtualAddress; + Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = SectionHeader[Index].Misc.VirtualSize; + } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = SectionHeader[Index].VirtualAddress; + Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = SectionHeader[Index].Misc.VirtualSize; + } + break; + } + } + + // + // Zero ExceptionTable Xdata + // + if (!KeepExceptionTableFlag) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader); + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) { + if (stricmp ((char *)SectionHeader[Index].Name, ".xdata") == 0) { + // + // zero .xdata section + // + memset (FileBuffer + SectionHeader[Index].PointerToRawData, 0, SectionHeader[Index].SizeOfRawData); + DebugMsg (NULL, 0, 9, NULL, "Zero the .xdata section for PE image at Offset 0x%x and Length 0x%x", (unsigned) SectionHeader[Index].PointerToRawData, (unsigned) SectionHeader[Index].SizeOfRawData); + break; + } + } + } + + // + // Zero Time/Data field + // + ZeroDebugData (FileBuffer, ZeroDebugFlag); + + if (mOutImageType == FW_TE_IMAGE) { + if ((PeHdr->Pe32.FileHeader.NumberOfSections &~0xFF) || (Type &~0xFF)) { + // + // Pack the subsystem and NumberOfSections into 1 byte. Make sure they fit both. + // + Error (NULL, 0, 3000, "Invalid", "Image's subsystem or NumberOfSections of PeImage %s cannot be packed into 1 byte.", mInImageName); + goto Finish; + } + + if ((PeHdr->Pe32.OptionalHeader.SectionAlignment != PeHdr->Pe32.OptionalHeader.FileAlignment)) { + // + // TeImage has the same section alignment and file alignment. + // + Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment of PeImage %s do not match, they must be equal for a TeImage.", mInImageName); + goto Finish; + } + + DebugMsg (NULL, 0, 9, "TeImage Header Info", "Machine type is %X, Number of sections is %X, Stripped size is %X, EntryPoint is %X, BaseOfCode is %X, ImageBase is %llX", + TEImageHeader.Machine, TEImageHeader.NumberOfSections, TEImageHeader.StrippedSize, (unsigned) TEImageHeader.AddressOfEntryPoint, (unsigned) TEImageHeader.BaseOfCode, (unsigned long long) TEImageHeader.ImageBase); + // + // Update Image to TeImage + // + FileLength = FileLength - TEImageHeader.StrippedSize; + memmove (FileBuffer + sizeof (EFI_TE_IMAGE_HEADER), FileBuffer + TEImageHeader.StrippedSize, FileLength); + FileLength = FileLength + sizeof (EFI_TE_IMAGE_HEADER); + memcpy (FileBuffer, &TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER)); + VerboseMsg ("the size of output file is %u bytes", (unsigned) (FileLength)); + } else { + + // + // Following codes are to fix the objcopy's issue: + // objcopy in binutil 2.50.18 will set PE image's charactices to "RELOC_STRIPPED" if image has no ".reloc" section + // It cause issue for EFI image which has no ".reloc" sections. + // Following codes will be removed when objcopy in binutil fix this problem for PE image. + // + if ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->Pe32.OptionalHeader; + if (Optional32->ImageBase == 0) { + PeHdr->Pe32.FileHeader.Characteristics &= ~EFI_IMAGE_FILE_RELOCS_STRIPPED; + } + } else if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->Pe32.OptionalHeader; + if (Optional64->ImageBase == 0) { + PeHdr->Pe32.FileHeader.Characteristics &= ~EFI_IMAGE_FILE_RELOCS_STRIPPED; + } + } + } + } + +WriteFile: + // + // Update Image to EfiImage or TE image + // + if (ReplaceFlag) { + if ((FileLength != InputFileLength) || (memcmp (FileBuffer, InputFileBuffer, FileLength) != 0)) { + // + // Update File when File is changed. + // + fpInOut = fopen (LongFilePath (mInImageName), "wb"); + if (fpInOut == NULL) { + Error (NULL, 0, 0001, "Error opening file", mInImageName); + goto Finish; + } + fwrite (FileBuffer, 1, FileLength, fpInOut); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + } + } else { + if ((OutputFileTime < InputFileTime) || (FileLength != OutputFileLength) || (memcmp (FileBuffer, OutputFileBuffer, FileLength) != 0)) { + // + // Update File when File is changed or File is old. + // + fpOut = fopen (LongFilePath (OutImageName), "wb"); + if (fpOut == NULL) { + Error (NULL, 0, 0001, "Error opening output file", OutImageName); + goto Finish; + } + fwrite (FileBuffer, 1, FileLength, fpOut); + VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength); + } + } + mImageSize = FileLength; + +Finish: + if (fpInOut != NULL) { + if (GetUtilityStatus () != STATUS_SUCCESS) { + // + // when file updates failed, original file is still recovered. + // + fwrite (InputFileBuffer, 1, InputFileLength, fpInOut); + } + // + // Write converted data into fpInOut file and close input file. + // + fclose (fpInOut); + } + + if (FileBuffer != NULL) { + free (FileBuffer); + } + + if (InputFileName != NULL) { + free (InputFileName); + } + + if (fpOut != NULL) { + // + // Write converted data into fpOut file and close output file. + // + fclose (fpOut); + if (GetUtilityStatus () != STATUS_SUCCESS) { + if (OutputFileBuffer == NULL) { + remove (OutImageName); + } else { + fpOut = fopen (LongFilePath (OutImageName), "wb"); + fwrite (OutputFileBuffer, 1, OutputFileLength, fpOut); + fclose (fpOut); + } + } + } + + if (InputFileBuffer != NULL) { + free (InputFileBuffer); + } + + if (OutputFileBuffer != NULL) { + free (OutputFileBuffer); + } + + // + // Write module size and time stamp to report file. + // + if (OutImageName != NULL) { + FileLen = strlen (OutImageName); + } + if (FileLen >= 4 && strcmp (OutImageName + (FileLen - 4), ".efi") == 0) { + ReportFileName = (CHAR8 *) malloc (FileLen + 1); + if (ReportFileName != NULL) { + strcpy (ReportFileName, OutImageName); + strcpy (ReportFileName + (FileLen - 4), ".txt"); + ReportFile = fopen (LongFilePath (ReportFileName), "w+"); + if (ReportFile != NULL) { + fprintf (ReportFile, "MODULE_SIZE = %u\n", (unsigned) mImageSize); + fprintf (ReportFile, "TIME_STAMP = %u\n", (unsigned) mImageTimeStamp); + fclose(ReportFile); + } + free (ReportFileName); + } + } + VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ()); + + return GetUtilityStatus (); +} + +STATIC +EFI_STATUS +ZeroDebugData ( + IN OUT UINT8 *FileBuffer, + BOOLEAN ZeroDebugFlag + ) +/*++ + +Routine Description: + + Zero debug information in PeImage. + +Arguments: + + FileBuffer - Pointer to PeImage. + ZeroDebugFlag - TRUE to zero Debug information, FALSE to only zero time/stamp + +Returns: + + EFI_ABORTED - PeImage is invalid. + EFI_SUCCESS - Zero debug data successfully. + +--*/ +{ + UINT32 Index; + UINT32 DebugDirectoryEntryRva; + UINT32 DebugDirectoryEntrySize; + UINT32 DebugDirectoryEntryFileOffset; + UINT32 ExportDirectoryEntryRva; + UINT32 ExportDirectoryEntryFileOffset; + UINT32 ResourceDirectoryEntryRva; + UINT32 ResourceDirectoryEntryFileOffset; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_FILE_HEADER *FileHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY *RsdsEntry; + UINT32 *NewTimeStamp; + + // + // Init variable. + // + DebugDirectoryEntryRva = 0; + DebugDirectoryEntrySize = 0; + ExportDirectoryEntryRva = 0; + ResourceDirectoryEntryRva = 0; + DebugDirectoryEntryFileOffset = 0; + ExportDirectoryEntryFileOffset = 0; + ResourceDirectoryEntryFileOffset = 0; + DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer; + FileHdr = (EFI_IMAGE_FILE_HEADER *) (FileBuffer + DosHdr->e_lfanew + sizeof (UINT32)); + + + DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, must start with PE/COFF header + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32)); + } else { + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32)); + } + + // + // Get Debug, Export and Resource EntryTable RVA address. + // Resource Directory entry need to review. + // + Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + DebugDirectoryEntrySize = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if (ZeroDebugFlag) { + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0; + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0; + } + } + } else { + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + DebugDirectoryEntrySize = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if (ZeroDebugFlag) { + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0; + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0; + } + } + } + + // + // Get DirectoryEntryTable file offset. + // + for (Index = 0; Index < FileHdr->NumberOfSections; Index ++, SectionHeader ++) { + if (DebugDirectoryEntryRva >= SectionHeader->VirtualAddress && + DebugDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = + DebugDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ExportDirectoryEntryRva >= SectionHeader->VirtualAddress && + ExportDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ExportDirectoryEntryFileOffset = + ExportDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ResourceDirectoryEntryRva >= SectionHeader->VirtualAddress && + ResourceDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ResourceDirectoryEntryFileOffset = + ResourceDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + } + + // + //Zero Debug Data and TimeStamp + // + FileHdr->TimeDateStamp = 0; + mImageTimeStamp = 0; + if (ExportDirectoryEntryFileOffset != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ExportDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = 0; + } + + if (ResourceDirectoryEntryFileOffset != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ResourceDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = 0; + } + + if (DebugDirectoryEntryFileOffset != 0) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (FileBuffer + DebugDirectoryEntryFileOffset); + Index = 0; + for (Index=0; Index < DebugDirectoryEntrySize / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); Index ++, DebugEntry ++) { + DebugEntry->TimeDateStamp = 0; + if (mIsConvertXip) { + DebugEntry->FileOffset = DebugEntry->RVA; + } + if ((ZeroDebugFlag || DebugEntry->Type != EFI_IMAGE_DEBUG_TYPE_CODEVIEW) && + (DebugEntry->Type != EFI_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS)) { + memset (FileBuffer + DebugEntry->FileOffset, 0, DebugEntry->SizeOfData); + memset (DebugEntry, 0, sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)); + } + if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + RsdsEntry = (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY *) (FileBuffer + DebugEntry->FileOffset); + if (RsdsEntry->Signature == CODEVIEW_SIGNATURE_MTOC) { + // MTOC sets DebugDirectoryEntrySize to size of the .debug section, so fix it. + if (!ZeroDebugFlag) { + if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + } else { + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + } + } + break; + } + } + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetStamp ( + IN OUT UINT8 *FileBuffer, + IN CHAR8 *TimeStamp + ) +/*++ + +Routine Description: + + Set new time stamp into PeImage FileHdr and Directory table: + Debug, Export and Resource. + +Arguments: + + FileBuffer - Pointer to PeImage. + TimeStamp - Time stamp string. + +Returns: + + EFI_INVALID_PARAMETER - TimeStamp format is not recognized. + EFI_SUCCESS - Set new time stamp in this image successfully. + +--*/ +{ + struct tm stime; + struct tm *ptime; + time_t newtime; + UINT32 Index; + UINT32 DebugDirectoryEntryRva; + UINT32 DebugDirectoryEntryFileOffset; + UINT32 ExportDirectoryEntryRva; + UINT32 ExportDirectoryEntryFileOffset; + UINT32 ResourceDirectoryEntryRva; + UINT32 ResourceDirectoryEntryFileOffset; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_FILE_HEADER *FileHdr; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINT32 *NewTimeStamp; + + // + // Init variable. + // + DebugDirectoryEntryRva = 0; + DebugDirectoryEntryFileOffset = 0; + ExportDirectoryEntryRva = 0; + ExportDirectoryEntryFileOffset = 0; + ResourceDirectoryEntryRva = 0; + ResourceDirectoryEntryFileOffset = 0; + // + // Get time and date that will be set. + // + if (TimeStamp == NULL) { + Error (NULL, 0, 3000, "Invalid", "TimeStamp cannot be NULL."); + return EFI_INVALID_PARAMETER; + } + // + // compare the value with "NOW", if yes, current system time is set. + // + if (stricmp (TimeStamp, "NOW") == 0) { + // + // get system current time and date + // + time (&newtime); + } else { + // + // Check Time Format strictly yyyy-mm-dd 00:00:00 + // + for (Index = 0; TimeStamp[Index] != '\0' && Index < 20; Index ++) { + if (Index == 4 || Index == 7) { + if (TimeStamp[Index] == '-') { + continue; + } + } else if (Index == 13 || Index == 16) { + if (TimeStamp[Index] == ':') { + continue; + } + } else if (Index == 10 && TimeStamp[Index] == ' ') { + continue; + } else if ((TimeStamp[Index] < '0') || (TimeStamp[Index] > '9')) { + break; + } + } + + if (Index < 19 || TimeStamp[19] != '\0') { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect Time \"%s\"\n Correct Format \"yyyy-mm-dd 00:00:00\"", TimeStamp); + return EFI_INVALID_PARAMETER; + } + + // + // get the date and time from TimeStamp + // + if (sscanf (TimeStamp, "%d-%d-%d %d:%d:%d", + &stime.tm_year, + &stime.tm_mon, + &stime.tm_mday, + &stime.tm_hour, + &stime.tm_min, + &stime.tm_sec + ) != 6) { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect Tiem \"%s\"\n Correct Format \"yyyy-mm-dd 00:00:00\"", TimeStamp); + return EFI_INVALID_PARAMETER; + } + + // + // in struct, Month (0 - 11; Jan = 0). So decrease 1 from it + // + if (stime.tm_mon <= 0 || stime.tm_mday <=0) { + Error (NULL, 0, 3000, "Invalid", "%s Invalid date!", TimeStamp); + return EFI_INVALID_PARAMETER; + } + stime.tm_mon -= 1; + + // + // in struct, Year (current year minus 1900) + // and only the dates can be handled from Jan 1, 1970 to Jan 18, 2038 + // + // + // convert 0 -> 100 (2000), 1 -> 101 (2001), ..., 38 -> 138 (2038) + // + if (stime.tm_year >= 1970 && stime.tm_year <= 2038) { + // + // convert 1970 -> 70, 2000 -> 100, ... + // + stime.tm_year -= 1900; + } else { + Error (NULL, 0, 3000, "Invalid", "%s Invalid or unsupported datetime!", TimeStamp); + return EFI_INVALID_PARAMETER; + } + + // + // convert the date and time to time_t format + // + newtime = mktime (&stime); + if (newtime == (time_t) - 1) { + Error (NULL, 0, 3000, "Invalid", "%s Invalid or unsupported datetime!", TimeStamp); + return EFI_INVALID_PARAMETER; + } + } + + ptime = localtime (&newtime); + if (ptime != NULL) { + DebugMsg (NULL, 0, 9, "New Image Time Stamp", "%04d-%02d-%02d %02d:%02d:%02d", + ptime->tm_year + 1900, ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec); + } + // + // Set new time and data into PeImage. + // + DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer; + if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + // NO DOS header, must start with PE/COFF header + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32)); + } else { + FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32)); + } + + // + // Get Debug, Export and Resource EntryTable RVA address. + // Resource Directory entry need to review. + // + if (FileHdr->Machine == IMAGE_FILE_MACHINE_I386) { + Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + } + } else { + Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER)); + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader); + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXPORT && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0) { + ExportDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0) { + ResourceDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + } + if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && \ + Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) { + DebugDirectoryEntryRva = Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + } + } + + // + // Get DirectoryEntryTable file offset. + // + for (Index = 0; Index < FileHdr->NumberOfSections; Index ++, SectionHeader ++) { + if (DebugDirectoryEntryRva >= SectionHeader->VirtualAddress && + DebugDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = + DebugDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ExportDirectoryEntryRva >= SectionHeader->VirtualAddress && + ExportDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ExportDirectoryEntryFileOffset = + ExportDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + if (ResourceDirectoryEntryRva >= SectionHeader->VirtualAddress && + ResourceDirectoryEntryRva < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize) { + ResourceDirectoryEntryFileOffset = + ResourceDirectoryEntryRva - SectionHeader->VirtualAddress + SectionHeader->PointerToRawData; + } + } + + // + // Set new stamp + // + FileHdr->TimeDateStamp = (UINT32) newtime; + mImageTimeStamp = (UINT32) newtime; + if (ExportDirectoryEntryRva != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ExportDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = (UINT32) newtime; + } + + if (ResourceDirectoryEntryRva != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + ResourceDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = (UINT32) newtime; + } + + if (DebugDirectoryEntryRva != 0) { + NewTimeStamp = (UINT32 *) (FileBuffer + DebugDirectoryEntryFileOffset + sizeof (UINT32)); + *NewTimeStamp = (UINT32) newtime; + } + + return EFI_SUCCESS; +} + +STATIC +STATUS +MicrocodeReadData ( + FILE *InFptr, + UINT32 *Data + ) +/*++ + +Routine Description: + Read a 32-bit microcode data value from a text file and convert to raw binary form. + +Arguments: + InFptr - file pointer to input text file + Data - pointer to where to return the data parsed + +Returns: + STATUS_SUCCESS - no errors or warnings, Data contains valid information + STATUS_ERROR - errors were encountered + +--*/ +{ + CHAR8 Line[MAX_LINE_LEN]; + CHAR8 *cptr; + int ScannedData = 0; + + Line[MAX_LINE_LEN - 1] = 0; + while (1) { + if (fgets (Line, MAX_LINE_LEN, InFptr) == NULL) { + return STATUS_ERROR; + } + // + // If it was a binary file, then it may have overwritten our null terminator + // + if (Line[MAX_LINE_LEN - 1] != 0) { + return STATUS_ERROR; + } + + // + // strip space + // + for (cptr = Line; *cptr && isspace((int)*cptr); cptr++) { + } + + // Skip Blank Lines and Comment Lines + if ((strlen(cptr) != 0) && (*cptr != ';')) { + break; + } + } + + // Look for + // dd 000000001h ; comment + // dd XXXXXXXX + // DD XXXXXXXXX + // DD XXXXXXXXX + // + if ((tolower((int)cptr[0]) == 'd') && (tolower((int)cptr[1]) == 'd') && isspace ((int)cptr[2])) { + // + // Skip blanks and look for a hex digit + // + cptr += 3; + for (; *cptr && isspace((int)*cptr); cptr++) { + } + if (isxdigit ((int)*cptr)) { + if (sscanf (cptr, "%X", &ScannedData) != 1) { + return STATUS_ERROR; + } + } + *Data = (UINT32) ScannedData; + return STATUS_SUCCESS; + } + + return STATUS_ERROR; +} diff --git a/tools/src/GenFw/GenFw/src/GenFw.h b/tools/src/GenFw/GenFw/src/GenFw.h new file mode 100644 index 0000000..ff20649 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/GenFw.h @@ -0,0 +1,50 @@ +/** @file +Header file for GenFw + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _GEN_FW_H_ +#define _GEN_FW_H_ + +// +// Action for this tool. +// +#define FW_DUMMY_IMAGE 0 +#define FW_EFI_IMAGE 1 +#define FW_TE_IMAGE 2 +#define FW_ACPI_IMAGE 3 +#define FW_BIN_IMAGE 4 +#define FW_ZERO_DEBUG_IMAGE 5 +#define FW_SET_STAMP_IMAGE 6 +#define FW_MCI_IMAGE 7 +#define FW_MERGE_IMAGE 8 +#define FW_RELOC_STRIPEED_IMAGE 9 +#define FW_HII_PACKAGE_LIST_RCIMAGE 10 +#define FW_HII_PACKAGE_LIST_BINIMAGE 11 +#define FW_REBASE_IMAGE 12 +#define FW_SET_ADDRESS_IMAGE 13 + +#define DUMP_TE_HEADER 0x11 + +VOID +SetHiiResourceHeader ( + UINT8 *HiiBinData, + UINT32 OffsetToFile + ); + +INTN +IsElfHeader ( + UINT8 *FileBuffer + ); + +BOOLEAN +ConvertElf ( + UINT8 **FileBuffer, + UINT32 *FileLength + ); + +#endif diff --git a/tools/src/GenFw/GenFw/src/elf32.h b/tools/src/GenFw/GenFw/src/elf32.h new file mode 100644 index 0000000..8795fab --- /dev/null +++ b/tools/src/GenFw/GenFw/src/elf32.h @@ -0,0 +1,252 @@ +/** @file +Ported ELF include files from FreeBSD + +Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * 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. + * + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.2 2007/12/03 21:30:36 marius Exp $ + */ + +#ifndef _SYS_ELF32_H_ +#define _SYS_ELF32_H_ 1 + + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef UINT32 Elf32_Addr; +typedef UINT16 Elf32_Half; +typedef UINT32 Elf32_Off; +typedef INT32 Elf32_Sword; +typedef UINT32 Elf32_Word; +typedef UINT64 Elf32_Lword; + +typedef Elf32_Word Elf32_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Sword Elf32_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Word sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Word sh_addralign; /* Alignment in bytes. */ + Elf32_Word sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Word p_filesz; /* Size of contents in file. */ + Elf32_Word p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Word p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Note entry header + */ +typedef Elf_Note Elf32_Nhdr; + +/* + * Move entry + */ +typedef struct { + Elf32_Lword m_value; /* symbol value */ + Elf32_Word m_info; /* size + index */ + Elf32_Word m_poffset; /* symbol offset */ + Elf32_Half m_repeat; /* repeat count */ + Elf32_Half m_stride; /* stride info */ +} Elf32_Move; + +/* + * The macros compose and decompose values for Move.r_info + * + * sym = ELF32_M_SYM(M.m_info) + * size = ELF32_M_SIZE(M.m_info) + * M.m_info = ELF32_M_INFO(sym, size) + */ +#define ELF32_M_SYM(info) ((info)>>8) +#define ELF32_M_SIZE(info) ((unsigned char)(info)) +#define ELF32_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size)) + +/* + * Hardware/Software capabilities entry + */ +typedef struct { + Elf32_Word c_tag; /* how to interpret value */ + union { + Elf32_Word c_val; + Elf32_Addr c_ptr; + } c_un; +} Elf32_Cap; + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* Structures used by Sun & GNU symbol versioning. */ +typedef struct +{ + Elf32_Half vd_version; + Elf32_Half vd_flags; + Elf32_Half vd_ndx; + Elf32_Half vd_cnt; + Elf32_Word vd_hash; + Elf32_Word vd_aux; + Elf32_Word vd_next; +} Elf32_Verdef; + +typedef struct +{ + Elf32_Word vda_name; + Elf32_Word vda_next; +} Elf32_Verdaux; + +typedef struct +{ + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct +{ + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef Elf32_Half Elf32_Versym; + +typedef struct { + Elf32_Half si_boundto; /* direct bindings - symbol bound to */ + Elf32_Half si_flags; /* per symbol flags */ +} Elf32_Syminfo; + +#endif /* !_SYS_ELF32_H_ */ diff --git a/tools/src/GenFw/GenFw/src/elf64.h b/tools/src/GenFw/GenFw/src/elf64.h new file mode 100644 index 0000000..8dc10f6 --- /dev/null +++ b/tools/src/GenFw/GenFw/src/elf64.h @@ -0,0 +1,254 @@ +/** @file +Ported ELF include files from FreeBSD + +Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * 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. + * + * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.2 2007/12/03 21:30:36 marius Exp $ + */ + +#ifndef _SYS_ELF64_H_ +#define _SYS_ELF64_H_ 1 + + +/* + * ELF definitions common to all 64-bit architectures. + */ + +typedef UINT64 Elf64_Addr; +typedef UINT16 Elf64_Half; +typedef UINT64 Elf64_Off; +typedef INT32 Elf64_Sword; +typedef INT64 Elf64_Sxword; +typedef UINT32 Elf64_Word; +typedef UINT64 Elf64_Lword; +typedef UINT64 Elf64_Xword; + +/* + * Types of dynamic symbol hash table bucket and chain elements. + * + * This is inconsistent among 64 bit architectures, so a machine dependent + * typedef is required. + */ + +typedef Elf64_Word Elf64_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Sxword Elf64_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf64_Half e_type; /* File type. */ + Elf64_Half e_machine; /* Machine architecture. */ + Elf64_Word e_version; /* ELF format version. */ + Elf64_Addr e_entry; /* Entry point. */ + Elf64_Off e_phoff; /* Program header file offset. */ + Elf64_Off e_shoff; /* Section header file offset. */ + Elf64_Word e_flags; /* Architecture-specific flags. */ + Elf64_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf64_Half e_phentsize; /* Size of program header entry. */ + Elf64_Half e_phnum; /* Number of program header entries. */ + Elf64_Half e_shentsize; /* Size of section header entry. */ + Elf64_Half e_shnum; /* Number of section header entries. */ + Elf64_Half e_shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf64_Word sh_name; /* Section name (index into the + section header string table). */ + Elf64_Word sh_type; /* Section type. */ + Elf64_Xword sh_flags; /* Section flags. */ + Elf64_Addr sh_addr; /* Address in memory image. */ + Elf64_Off sh_offset; /* Offset in file. */ + Elf64_Xword sh_size; /* Size in bytes. */ + Elf64_Word sh_link; /* Index of a related section. */ + Elf64_Word sh_info; /* Depends on section type. */ + Elf64_Xword sh_addralign; /* Alignment in bytes. */ + Elf64_Xword sh_entsize; /* Size of each entry in section. */ +} Elf64_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf64_Word p_type; /* Entry type. */ + Elf64_Word p_flags; /* Access permission flags. */ + Elf64_Off p_offset; /* File offset of contents. */ + Elf64_Addr p_vaddr; /* Virtual address in memory image. */ + Elf64_Addr p_paddr; /* Physical address (not used). */ + Elf64_Xword p_filesz; /* Size of contents in file. */ + Elf64_Xword p_memsz; /* Size of contents in memory. */ + Elf64_Xword p_align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf64_Sxword d_tag; /* Entry type. */ + union { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Relocation type and symbol index. */ +} Elf64_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Relocation type and symbol index. */ + Elf64_Sxword r_addend; /* Addend. */ +} Elf64_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xffffffffL) + +/* Macro for constructing r_info from field values. */ +#define ELF64_R_INFO(sym, type) (((sym) << 32) + ((type) & 0xffffffffL)) + +#define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info)<<32)>>40) +#define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info)<<56)>>56) +#define ELF64_R_TYPE_INFO(data, type) \ + (((Elf64_Xword)(data)<<8)+(Elf64_Xword)(type)) + +/* + * Note entry header + */ +typedef Elf_Note Elf64_Nhdr; + +/* + * Move entry + */ +typedef struct { + Elf64_Lword m_value; /* symbol value */ + Elf64_Xword m_info; /* size + index */ + Elf64_Xword m_poffset; /* symbol offset */ + Elf64_Half m_repeat; /* repeat count */ + Elf64_Half m_stride; /* stride info */ +} Elf64_Move; + +#define ELF64_M_SYM(info) ((info)>>8) +#define ELF64_M_SIZE(info) ((unsigned char)(info)) +#define ELF64_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size)) + +/* + * Hardware/Software capabilities entry + */ +typedef struct { + Elf64_Xword c_tag; /* how to interpret value */ + union { + Elf64_Xword c_val; + Elf64_Addr c_ptr; + } c_un; +} Elf64_Cap; + +/* + * Symbol table entries. + */ + +typedef struct { + Elf64_Word st_name; /* String table index of name. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf64_Half st_shndx; /* Section index of symbol. */ + Elf64_Addr st_value; /* Symbol value. */ + Elf64_Xword st_size; /* Size of associated object. */ +} Elf64_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* Structures used by Sun & GNU-style symbol versioning. */ +typedef struct { + Elf64_Half vd_version; + Elf64_Half vd_flags; + Elf64_Half vd_ndx; + Elf64_Half vd_cnt; + Elf64_Word vd_hash; + Elf64_Word vd_aux; + Elf64_Word vd_next; +} Elf64_Verdef; + +typedef struct { + Elf64_Word vda_name; + Elf64_Word vda_next; +} Elf64_Verdaux; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + +typedef Elf64_Half Elf64_Versym; + +typedef struct { + Elf64_Half si_boundto; /* direct bindings - symbol bound to */ + Elf64_Half si_flags; /* per symbol flags */ +} Elf64_Syminfo; + +#endif /* !_SYS_ELF64_H_ */ diff --git a/tools/src/GenFw/GenFw/src/elf_common.h b/tools/src/GenFw/GenFw/src/elf_common.h new file mode 100644 index 0000000..08ff75c --- /dev/null +++ b/tools/src/GenFw/GenFw/src/elf_common.h @@ -0,0 +1,1148 @@ +/** @file +Ported ELF include files from FreeBSD + +Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.
+Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+Portion Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ +/*- + * Copyright (c) 1998 John D. Polstra. + * 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. + * + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.2 2007/12/03 21:30:36 marius Exp $ + */ + +#ifndef _SYS_ELF_COMMON_H_ +#define _SYS_ELF_COMMON_H_ 1 + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + UINT32 n_namesz; /* Length of name. */ + UINT32 n_descsz; /* Length of descriptor. */ + UINT32 n_type; /* Type of this note. */ +} Elf_Note; + +#define NT_GNU_PROPERTY_TYPE_0 5 + +#define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002 +#define GNU_PROPERTY_X86_FEATURE_1_IBT 0x1 + +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 0x1 +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 0x2 + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developers/gabi/latest/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* Open VMS */ +#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ +#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ +#define ET_LOOS 0xfe00 /* First operating system specific. */ +#define ET_HIOS 0xfeff /* Last operating system-specific. */ +#define ET_LOPROC 0xff00 /* First processor-specific. */ +#define ET_HIPROC 0xffff /* Last processor-specific. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ +#define EM_S370 9 /* IBM System/370. */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ +#define EM_PARISC 15 /* HP PA-RISC. */ +#define EM_VPP500 17 /* Fujitsu VPP500. */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus. */ +#define EM_960 19 /* Intel 80960. */ +#define EM_PPC 20 /* PowerPC 32-bit. */ +#define EM_PPC64 21 /* PowerPC 64-bit. */ +#define EM_S390 22 /* IBM System/390. */ +#define EM_V800 36 /* NEC V800. */ +#define EM_FR20 37 /* Fujitsu FR20. */ +#define EM_RH32 38 /* TRW RH-32. */ +#define EM_RCE 39 /* Motorola RCE. */ +#define EM_ARM 40 /* ARM. */ +#define EM_SH 42 /* Hitachi SH. */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit. */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ +#define EM_ARC 45 /* Argonaut RISC Core. */ +#define EM_H8_300 46 /* Hitachi H8/300. */ +#define EM_H8_300H 47 /* Hitachi H8/300H. */ +#define EM_H8S 48 /* Hitachi H8S. */ +#define EM_H8_500 49 /* Hitachi H8/500. */ +#define EM_MIPS_X 51 /* Stanford MIPS-X. */ +#define EM_COLDFIRE 52 /* Motorola ColdFire. */ +#define EM_68HC12 53 /* Motorola M68HC12. */ +#define EM_MMA 54 /* Fujitsu MMA. */ +#define EM_PCP 55 /* Siemens PCP. */ +#define EM_NCPU 56 /* Sony nCPU. */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor. */ +#define EM_STARCORE 58 /* Motorola Star*Core processor. */ +#define EM_ME16 59 /* Toyota ME16 processor. */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor. */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ +#define EM_AARCH64 183 /* ARM 64bit Architecture */ +#define EM_RISCV64 243 /* 64bit RISC-V Architecture */ +#define EM_RISCV 244 /* 32bit RISC-V Architecture */ +#define EM_LOONGARCH 258 /* LoongArch Architecture */ + +/* Non-standard or deprecated. */ +#define EM_486 6 /* Intel i486. */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_LOOS 0xff20 /* First operating system-specific. */ +#define SHN_HIOS 0xff3f /* Last operating system-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers. */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ +#define SHT_GROUP 17 /* Section group. */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_LOSUNW 0x6ffffff4 +#define SHT_SUNW_dof 0x6ffffff4 +#define SHT_SUNW_cap 0x6ffffff5 +#define SHT_SUNW_SIGNATURE 0x6ffffff6 +#define SHT_SUNW_ANNOTATE 0x6ffffff7 +#define SHT_SUNW_DEBUGSTR 0x6ffffff8 +#define SHT_SUNW_DEBUG 0x6ffffff9 +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_SUNW_verdef 0x6ffffffd +#define SHT_GNU_verdef 0x6ffffffd /* Symbol versions provided */ +#define SHT_SUNW_verneed 0x6ffffffe +#define SHT_GNU_verneed 0x6ffffffe /* Symbol versions required */ +#define SHT_SUNW_versym 0x6fffffff +#define SHT_GNU_versym 0x6fffffff /* Symbol version table */ +#define SHT_HISUNW 0x6fffffff +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_AMD64_UNWIND 0x70000001 /* unwind information */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_MERGE 0x10 /* Section may be merged. */ +#define SHF_STRINGS 0x20 /* Section contains strings. */ +#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ +#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ +#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ +#define SHF_GROUP 0x200 /* Member of section group. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* First OS-specific. */ +#define PT_SUNW_UNWIND 0x6464e550 /* amd64 UNWIND program header */ +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* describes the stack segment */ +#define PT_SUNWDTRACE 0x6ffffffc /* private */ +#define PT_SUNWCAP 0x6ffffffd /* hard/soft capabilities segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* Last OS-specific. */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ +#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific. */ + +/* Extended program header index. */ +#define PN_XNUM 0xffff + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ +#define DT_MAXPOSTAGS 34 /* number of positive tags */ +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_SUNW_AUXILIARY 0x6000000d /* symbol auxiliary name */ +#define DT_SUNW_RTLDINF 0x6000000e /* ld.so.1 info (private) */ +#define DT_SUNW_FILTER 0x6000000f /* symbol filter name */ +#define DT_SUNW_CAP 0x60000010 /* hardware/software */ +#define DT_HIOS 0x6ffff000 /* Last OS-specific */ + +/* + * DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + * Dyn.d_un.d_val field of the Elf*_Dyn structure. + */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_CHECKSUM 0x6ffffdf8 /* elf checksum */ +#define DT_PLTPADSZ 0x6ffffdf9 /* pltpadding size */ +#define DT_MOVEENT 0x6ffffdfa /* move table entry size */ +#define DT_MOVESZ 0x6ffffdfb /* move table size */ +#define DT_FEATURE_1 0x6ffffdfc /* feature holder */ +#define DT_POSFLAG_1 0x6ffffdfd /* flags for DT_* entries, effecting */ + /* the following DT_* entry. */ + /* See DF_P1_* definitions */ +#define DT_SYMINSZ 0x6ffffdfe /* syminfo table size (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* syminfo entry size (in bytes) */ +#define DT_VALRNGHI 0x6ffffdff + +/* + * DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + * Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + * + * If any adjustment is made to the ELF object after it has been + * built, these entries will need to be adjusted. + */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_CONFIG 0x6ffffefa /* configuration information */ +#define DT_DEPAUDIT 0x6ffffefb /* dependency auditing */ +#define DT_AUDIT 0x6ffffefc /* object auditing */ +#define DT_PLTPAD 0x6ffffefd /* pltpadding (sparcv9) */ +#define DT_MOVETAB 0x6ffffefe /* move table */ +#define DT_SYMINFO 0x6ffffeff /* syminfo table */ +#define DT_ADDRRNGHI 0x6ffffeff + +#define DT_VERSYM 0x6ffffff0 /* Address of versym section. */ +#define DT_RELACOUNT 0x6ffffff9 /* number of RELATIVE relocations */ +#define DT_RELCOUNT 0x6ffffffa /* number of RELATIVE relocations */ +#define DT_FLAGS_1 0x6ffffffb /* state flags - see DF_1_* defs */ +#define DT_VERDEF 0x6ffffffc /* Address of verdef section. */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of elems in verdef section */ +#define DT_VERNEED 0x6ffffffe /* Address of verneed section. */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of elems in verneed section */ + +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_DEPRECATED_SPARC_REGISTER 0x7000001 +#define DT_AUXILIARY 0x7ffffffd /* shared library auxiliary name */ +#define DT_USED 0x7ffffffe /* ignored - same as needed */ +#define DT_FILTER 0x7fffffff /* shared library filter name */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOOS 10 /* Reserved range for operating system */ +#define STB_HIOS 12 /* specific semantics. */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific semantics. */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_COMMON 5 /* Uninitialized common block. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_NUM 7 +#define STT_LOOS 10 /* Reserved range for operating system */ +#define STT_HIOS 12 /* specific semantics. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific semantics. */ + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0x0 /* Default visibility (see binding). */ +#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ +#define STV_HIDDEN 0x2 /* Not visible. */ +#define STV_PROTECTED 0x3 /* Visible but not preemptible. */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +/* Symbol versioning flags. */ +#define VER_DEF_CURRENT 1 +#define VER_DEF_IDX(x) VER_NDX(x) + +#define VER_FLG_BASE 0x01 +#define VER_FLG_WEAK 0x02 + +#define VER_NEED_CURRENT 1 +#define VER_NEED_WEAK (1u << 15) +#define VER_NEED_HIDDEN VER_NDX_HIDDEN +#define VER_NEED_IDX(x) VER_NDX(x) + +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 +#define VER_NDX_GIVEN 2 + +#define VER_NDX_HIDDEN (1u << 15) +#define VER_NDX(x) ((x) & ~(1u << 15)) + +#define CA_SUNW_NULL 0 +#define CA_SUNW_HW_1 1 /* first hardware capabilities entry */ +#define CA_SUNW_SF_1 2 /* first software capabilities entry */ + +/* + * Syminfo flag values + */ +#define SYMINFO_FLG_DIRECT 0x0001 /* symbol ref has direct association */ + /* to object containing defn. */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* ignored - see SYMINFO_FLG_FILTER */ +#define SYMINFO_FLG_COPY 0x0004 /* symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* object containing defn should be */ + /* lazily-loaded */ +#define SYMINFO_FLG_DIRECTBIND 0x0010 /* ref should be bound directly to */ + /* object containing defn. */ +#define SYMINFO_FLG_NOEXTDIRECT 0x0020 /* don't let an external reference */ + /* directly bind to this symbol */ +#define SYMINFO_FLG_FILTER 0x0002 /* symbol ref is associated to a */ +#define SYMINFO_FLG_AUXILIARY 0x0040 /* standard or auxiliary filter */ + +/* + * Syminfo.si_boundto values. + */ +#define SYMINFO_BT_SELF 0xffff /* symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* symbol bound to parent */ +#define SYMINFO_BT_NONE 0xfffd /* no special symbol binding */ +#define SYMINFO_BT_EXTERN 0xfffc /* symbol defined as external */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* beginning of reserved entries */ + +/* + * Syminfo version values. + */ +#define SYMINFO_NONE 0 /* Syminfo version */ +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* + * Relocation types. + * + * All machine architectures are defined here to allow tools on one to + * handle others. + */ + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +/* Null relocation */ +#define R_AARCH64_NONE 256 /* No relocation */ +/* Static AArch64 relocations */ + /* Static data relocations */ +#define R_AARCH64_ABS64 257 /* S + A */ +#define R_AARCH64_ABS32 258 /* S + A */ +#define R_AARCH64_ABS16 259 /* S + A */ +#define R_AARCH64_PREL64 260 /* S + A - P */ +#define R_AARCH64_PREL32 261 /* S + A - P */ +#define R_AARCH64_PREL16 262 /* S + A - P */ + /* Group relocations to create a 16, 32, 48, or 64 bit unsigned data value or address inline */ +#define R_AARCH64_MOVW_UABS_G0 263 /* S + A */ +#define R_AARCH64_MOVW_UABS_G0_NC 264 /* S + A */ +#define R_AARCH64_MOVW_UABS_G1 265 /* S + A */ +#define R_AARCH64_MOVW_UABS_G1_NC 266 /* S + A */ +#define R_AARCH64_MOVW_UABS_G2 267 /* S + A */ +#define R_AARCH64_MOVW_UABS_G2_NC 268 /* S + A */ +#define R_AARCH64_MOVW_UABS_G3 269 /* S + A */ + /* Group relocations to create a 16, 32, 48, or 64 bit signed data or offset value inline */ +#define R_AARCH64_MOVW_SABS_G0 270 /* S + A */ +#define R_AARCH64_MOVW_SABS_G1 271 /* S + A */ +#define R_AARCH64_MOVW_SABS_G2 272 /* S + A */ + /* Relocations to generate 19, 21 and 33 bit PC-relative addresses */ +#define R_AARCH64_LD_PREL_LO19 273 /* S + A - P */ +#define R_AARCH64_ADR_PREL_LO21 274 /* S + A - P */ +#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page(S+A) - Page(P) */ +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Page(S+A) - Page(P) */ +#define R_AARCH64_ADD_ABS_LO12_NC 277 /* S + A */ +#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* S + A */ +#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* S + A */ +#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* S + A */ +#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* S + A */ +#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* S + A */ + /* Relocations for control-flow instructions - all offsets are a multiple of 4 */ +#define R_AARCH64_TSTBR14 279 /* S+A-P */ +#define R_AARCH64_CONDBR19 280 /* S+A-P */ +#define R_AARCH64_JUMP26 282 /* S+A-P */ +#define R_AARCH64_CALL26 283 /* S+A-P */ + /* Group relocations to create a 16, 32, 48, or 64 bit PC-relative offset inline */ +#define R_AARCH64_MOVW_PREL_G0 287 /* S+A-P */ +#define R_AARCH64_MOVW_PREL_G0_NC 288 /* S+A-P */ +#define R_AARCH64_MOVW_PREL_G1 289 /* S+A-P */ +#define R_AARCH64_MOVW_PREL_G1_NC 290 /* S+A-P */ +#define R_AARCH64_MOVW_PREL_G2 291 /* S+A-P */ +#define R_AARCH64_MOVW_PREL_G2_NC 292 /* S+A-P */ +#define R_AARCH64_MOVW_PREL_G3 293 /* S+A-P */ + /* Group relocations to create a 16, 32, 48, or 64 bit GOT-relative offsets inline */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 /* G(S)-GOT */ +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* G(S)-GOT */ +#define R_AARCH64_MOVW_GOTOFF_G1 302 /* G(S)-GOT */ +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* G(S)-GOT */ +#define R_AARCH64_MOVW_GOTOFF_G2 304 /* G(S)-GOT */ +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* G(S)-GOT */ +#define R_AARCH64_MOVW_GOTOFF_G3 306 /* G(S)-GOT */ + /* GOT-relative data relocations */ +#define R_AARCH64_GOTREL64 307 /* S+A-GOT */ +#define R_AARCH64_GOTREL32 308 /* S+A-GOT */ + /* GOT-relative instruction relocations */ +#define R_AARCH64_GOT_LD_PREL19 309 /* G(S)-P */ +#define R_AARCH64_LD64_GOTOFF_LO15 310 /* G(S)-GOT */ +#define R_AARCH64_ADR_GOT_PAGE 311 /* Page(G(S))-Page(P) */ +#define R_AARCH64_LD64_GOT_LO12_NC 312 /* G(S) */ +#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* G(S)-Page(GOT) */ +/* Relocations for thread-local storage */ + /* General Dynamic TLS relocations */ +#define R_AARCH64_TLSGD_ADR_PREL21 512 /* G(TLSIDX(S+A)) - P */ +#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* Page(G(TLSIDX(S+A))) - Page(P) */ +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* G(TLSIDX(S+A)) */ +#define R_AARCH64_TLSGD_MOVW_G1 515 /* G(TLSIDX(S+A)) - GOT */ +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* G(TLSIDX(S+A)) - GOT */ + /* Local Dynamic TLS relocations */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 /* G(LDM(S))) - P */ +#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Page(G(LDM(S)))-Page(P) */ +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* G(LDM(S)) */ +#define R_AARCH64_TLSLD_MOVW_G1 520 /* G(LDM(S)) - GOT */ +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* G(LDM(S)) - GOT */ +#define R_AARCH64_TLSLD_LD_PREL19 522 /* G(LDM(S)) - P */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTPREL(S+A) */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* DTPREL(S+A) */ + /* Initial Exec TLS relocations */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* G(TPREL(S+A)) - GOT */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* G(TPREL(S+A)) - GOT */ +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page(G(TPREL(S+A))) - Page(P) */ +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* G(TPREL(S+A)) */ +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* G(TPREL(S+A)) - P */ + /* Local Exec TLS relocations */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TPREL(S+A) */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* TPREL(S+A) */ +/* Dynamic relocations */ + /* Dynamic relocations */ +#define R_AARCH64_COPY 1024 +#define R_AARCH64_GLOB_DAT 1025 /* S + A */ +#define R_AARCH64_JUMP_SLOT 1026 /* S + A */ +#define R_AARCH64_RELATIVE 1027 /* Delta(S) + A , Delta(P) + A */ +#define R_AARCH64_TLS_DTPREL64 1028 /* DTPREL(S+A) */ +#define R_AARCH64_TLS_DTPMOD64 1029 /* LDM(S) */ +#define R_AARCH64_TLS_TPREL64 1030 /* TPREL(S+A) */ +#define R_AARCH64_TLS_DTPREL32 1031 /* DTPREL(S+A) */ +#define R_AARCH64_TLS_DTPMOD32 1032 /* LDM(S) */ +#define R_AARCH64_TLS_TPREL32 1033 /* DTPREL(S+A) */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_OP_PUSH 12 /* OP stack push */ +#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ +#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ +#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ +#define R_ALPHA_GPVALUE 16 +#define R_ALPHA_GPRELHIGH 17 +#define R_ALPHA_GPRELLOW 18 +#define R_ALPHA_IMMED_GP_16 19 +#define R_ALPHA_IMMED_GP_HI32 20 +#define R_ALPHA_IMMED_SCN_HI32 21 +#define R_ALPHA_IMMED_BR_HI32 22 +#define R_ALPHA_IMMED_LO32 23 +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_CALL 28 +#define R_ARM_JMP24 29 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 + +// Block of PC-relative relocations added to work around gcc putting +// object relocations in static executables. +#define R_ARM_THM_JUMP24 30 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_PREL_NC 45 +#define R_ARM_MOVT_PREL 46 +#define R_ARM_THM_MOVW_PREL_NC 49 +#define R_ARM_THM_MOVT_PREL 50 +#define R_ARM_THM_JMP6 52 +#define R_ARM_THM_ALU_PREL_11_0 53 +#define R_ARM_THM_PC12 54 +#define R_ARM_REL32_NOI 56 +#define R_ARM_ALU_PC_G0_NC 57 +#define R_ARM_ALU_PC_G0 58 +#define R_ARM_ALU_PC_G1_NC 59 +#define R_ARM_ALU_PC_G1 60 +#define R_ARM_ALU_PC_G2 61 +#define R_ARM_LDR_PC_G1 62 +#define R_ARM_LDR_PC_G2 63 +#define R_ARM_LDRS_PC_G0 64 +#define R_ARM_LDRS_PC_G1 65 +#define R_ARM_LDRS_PC_G2 66 +#define R_ARM_LDC_PC_G0 67 +#define R_ARM_LDC_PC_G1 68 +#define R_ARM_LDC_PC_G2 69 +#define R_ARM_GOT_PREL 96 +#define R_ARM_THM_JUMP11 102 +#define R_ARM_THM_JUMP8 103 +#define R_ARM_TLS_GD32 104 +#define R_ARM_TLS_LDM32 105 +#define R_ARM_TLS_IE32 107 + +#define R_ARM_THM_JUMP19 51 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_PPC_NONE 0 /* No relocation. */ +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* + * TLS relocations + */ +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 + +/* + * The remaining relocs are from the Embedded ELF ABI, and are not in the + * SVR4 ELF ABI. + */ + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ +#define R_X86_64_PC64 24 /* PC relative 64 bit */ +#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ +#define R_X86_64_GOTPC3 26 /* 32 bit signed pc relative offset to GOT */ +#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ +#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset to GOT entry */ +#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ +#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ +#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset to PLT entry */ +#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ +#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ +#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ +#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS descriptor. */ +#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ +#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ +#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ +#define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc relative offset to GOT entry without REX prefix, relaxable. */ +#define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc relative offset to GOT entry with REX prefix, relaxable. */ + +/* + * RISC-V relocation types + */ + +/* Relocation types used by the dynamic linker */ +#define R_RISCV_NONE 0 +#define R_RISCV_32 1 +#define R_RISCV_64 2 +#define R_RISCV_RELATIVE 3 +#define R_RISCV_COPY 4 +#define R_RISCV_JUMP_SLOT 5 +#define R_RISCV_TLS_DTPMOD32 6 +#define R_RISCV_TLS_DTPMOD64 7 +#define R_RISCV_TLS_DTPREL32 8 +#define R_RISCV_TLS_DTPREL64 9 +#define R_RISCV_TLS_TPREL32 10 +#define R_RISCV_TLS_TPREL64 11 + +/* Relocation types not used by the dynamic linker */ +#define R_RISCV_BRANCH 16 +#define R_RISCV_JAL 17 +#define R_RISCV_CALL 18 +#define R_RISCV_CALL_PLT 19 +#define R_RISCV_GOT_HI20 20 +#define R_RISCV_TLS_GOT_HI20 21 +#define R_RISCV_TLS_GD_HI20 22 +#define R_RISCV_PCREL_HI20 23 +#define R_RISCV_PCREL_LO12_I 24 +#define R_RISCV_PCREL_LO12_S 25 +#define R_RISCV_HI20 26 +#define R_RISCV_LO12_I 27 +#define R_RISCV_LO12_S 28 +#define R_RISCV_TPREL_HI20 29 +#define R_RISCV_TPREL_LO12_I 30 +#define R_RISCV_TPREL_LO12_S 31 +#define R_RISCV_TPREL_ADD 32 +#define R_RISCV_ADD8 33 +#define R_RISCV_ADD16 34 +#define R_RISCV_ADD32 35 +#define R_RISCV_ADD64 36 +#define R_RISCV_SUB8 37 +#define R_RISCV_SUB16 38 +#define R_RISCV_SUB32 39 +#define R_RISCV_SUB64 40 +#define R_RISCV_GNU_VTINHERIT 41 +#define R_RISCV_GNU_VTENTRY 42 +#define R_RISCV_ALIGN 43 +#define R_RISCV_RVC_BRANCH 44 +#define R_RISCV_RVC_JUMP 45 +#define R_RISCV_RVC_LUI 46 +#define R_RISCV_GPREL_I 47 +#define R_RISCV_GPREL_S 48 +#define R_RISCV_TPREL_I 49 +#define R_RISCV_TPREL_S 50 +#define R_RISCV_RELAX 51 +#define R_RISCV_SUB6 52 +#define R_RISCV_SET6 53 +#define R_RISCV_SET8 54 +#define R_RISCV_SET16 55 +#define R_RISCV_SET32 56 + +/* + * LoongArch relocation types + */ +#define R_LARCH_NONE 0 +#define R_LARCH_32 1 +#define R_LARCH_64 2 +#define R_LARCH_RELATIVE 3 +#define R_LARCH_COPY 4 +#define R_LARCH_JUMP_SLOT 5 +#define R_LARCH_TLS_DTPMOD32 6 +#define R_LARCH_TLS_DTPMOD64 7 +#define R_LARCH_TLS_DTPREL32 8 +#define R_LARCH_TLS_DTPREL64 9 +#define R_LARCH_TLS_TPREL32 10 +#define R_LARCH_TLS_TPREL64 11 +#define R_LARCH_IRELATIVE 12 +#define R_LARCH_MARK_LA 20 +#define R_LARCH_MARK_PCREL 21 +#define R_LARCH_SOP_PUSH_PCREL 22 +#define R_LARCH_SOP_PUSH_ABSOLUTE 23 +#define R_LARCH_SOP_PUSH_DUP 24 +#define R_LARCH_SOP_PUSH_GPREL 25 +#define R_LARCH_SOP_PUSH_TLS_TPREL 26 +#define R_LARCH_SOP_PUSH_TLS_GOT 27 +#define R_LARCH_SOP_PUSH_TLS_GD 28 +#define R_LARCH_SOP_PUSH_PLT_PCREL 29 +#define R_LARCH_SOP_ASSERT 30 +#define R_LARCH_SOP_NOT 31 +#define R_LARCH_SOP_SUB 32 +#define R_LARCH_SOP_SL 33 +#define R_LARCH_SOP_SR 34 +#define R_LARCH_SOP_ADD 35 +#define R_LARCH_SOP_AND 36 +#define R_LARCH_SOP_IF_ELSE 37 +#define R_LARCH_SOP_POP_32_S_10_5 38 +#define R_LARCH_SOP_POP_32_U_10_12 39 +#define R_LARCH_SOP_POP_32_S_10_12 40 +#define R_LARCH_SOP_POP_32_S_10_16 41 +#define R_LARCH_SOP_POP_32_S_10_16_S2 42 +#define R_LARCH_SOP_POP_32_S_5_20 43 +#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 +#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 +#define R_LARCH_SOP_POP_32_U 46 +#define R_LARCH_ADD8 47 +#define R_LARCH_ADD16 48 +#define R_LARCH_ADD24 49 +#define R_LARCH_ADD32 50 +#define R_LARCH_ADD64 51 +#define R_LARCH_SUB8 52 +#define R_LARCH_SUB16 53 +#define R_LARCH_SUB24 54 +#define R_LARCH_SUB32 55 +#define R_LARCH_SUB64 56 +#define R_LARCH_GNU_VTINHERIT 57 +#define R_LARCH_GNU_VTENTRY 58 +#define R_LARCH_B16 64 +#define R_LARCH_B21 65 +#define R_LARCH_B26 66 +#define R_LARCH_ABS_HI20 67 +#define R_LARCH_ABS_LO12 68 +#define R_LARCH_ABS64_LO20 69 +#define R_LARCH_ABS64_HI12 70 +#define R_LARCH_PCALA_HI20 71 +#define R_LARCH_PCALA_LO12 72 +#define R_LARCH_PCALA64_LO20 73 +#define R_LARCH_PCALA64_HI12 74 +#define R_LARCH_GOT_PC_HI20 75 +#define R_LARCH_GOT_PC_LO12 76 +#define R_LARCH_GOT64_PC_LO20 77 +#define R_LARCH_GOT64_PC_HI12 78 +#define R_LARCH_GOT64_HI20 79 +#define R_LARCH_GOT64_LO12 80 +#define R_LARCH_GOT64_LO20 81 +#define R_LARCH_GOT64_HI12 82 +#define R_LARCH_TLS_LE_HI20 83 +#define R_LARCH_TLS_LE_LO12 84 +#define R_LARCH_TLS_LE64_LO20 85 +#define R_LARCH_TLS_LE64_HI12 86 +#define R_LARCH_TLS_IE_PC_HI20 87 +#define R_LARCH_TLS_IE_PC_LO12 88 +#define R_LARCH_TLS_IE64_PC_LO20 89 +#define R_LARCH_TLS_IE64_PC_HI12 90 +#define R_LARCH_TLS_IE64_HI20 91 +#define R_LARCH_TLS_IE64_LO12 92 +#define R_LARCH_TLS_IE64_LO20 93 +#define R_LARCH_TLS_IE64_HI12 94 +#define R_LARCH_TLS_LD_PC_HI20 95 +#define R_LARCH_TLS_LD64_HI20 96 +#define R_LARCH_TLS_GD_PC_HI20 97 +#define R_LARCH_TLS_GD64_HI20 98 +#define R_LARCH_RELAX 99 +#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/tools/src/GenFw/Include/Common/BaseTypes.h b/tools/src/GenFw/Include/Common/BaseTypes.h new file mode 100644 index 0000000..d8c275f --- /dev/null +++ b/tools/src/GenFw/Include/Common/BaseTypes.h @@ -0,0 +1,310 @@ +/** @file + Processor or Compiler specific defines for all supported processors. + + This file is stand alone self consistent set of definitions. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __BASE_TYPES_H__ +#define __BASE_TYPES_H__ + +// +// Include processor specific binding +// +#include +#include + +// +// Modifiers to abstract standard types to aid in debug of problems +// +#define CONST const +#define STATIC static +#define VOID void + +// +// Modifiers for Data Types used to self document code. +// This concept is borrowed for UEFI specification. +// +#ifndef IN +// +// Some other environments use this construct, so #ifndef to prevent +// multiple definition. +// +#define IN +#define OUT +#define OPTIONAL +#endif + +// +// Constants. They may exist in other build structures, so #ifndef them. +// +#ifndef TRUE +// +// BugBug: UEFI specification claims 1 and 0. We are concerned about the +// compiler portability so we did it this way. +// +#define TRUE ((BOOLEAN)(1==1)) +#endif + +#ifndef FALSE +#define FALSE ((BOOLEAN)(0==1)) +#endif + +#ifndef NULL +#define NULL ((VOID *) 0) +#endif + +#define PACKED + +// +// Support for variable length argument lists using the ANSI standard. +// +// Since we are using the ANSI standard we used the standard naming and +// did not follow the coding convention +// +// VA_LIST - typedef for argument list. +// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use. +// VA_END (VA_LIST Marker) - Clear Marker +// VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argument from +// the ... list. You must know the size and pass it in this macro. +// +// example: +// +// UINTN +// ExampleVarArg ( +// IN UINTN NumberOfArgs, +// ... +// ) +// { +// VA_LIST Marker; +// UINTN Index; +// UINTN Result; +// +// // +// // Initialize the Marker +// // +// VA_START (Marker, NumberOfArgs); +// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) { +// // +// // The ... list is a series of UINTN values, so average them up. +// // +// Result += VA_ARG (Marker, UINTN); +// } +// +// VA_END (Marker); +// return Result +// } +// + +#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1)) + +// +// Also support coding convention rules for var arg macros +// +#ifndef VA_START + +// typedef CHAR8 *VA_LIST; +// #define VA_START(ap, v) (ap = (VA_LIST) & (v) + _INT_SIZE_OF (v)) +// #define VA_ARG(ap, t) (*(t *) ((ap += _INT_SIZE_OF (t)) - _INT_SIZE_OF (t))) +// #define VA_END(ap) (ap = (VA_LIST) 0) +// Use the native arguments for tools. +#define VA_START va_start +#define VA_ARG va_arg +#define VA_END va_end +#define VA_LIST va_list + +#endif + +#ifndef GUID_DEFINED +#define GUID_DEFINED +/// +/// 128 bit buffer containing a unique identifier value. +/// Unless otherwise specified, aligned on a 64 bit boundary. +/// +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} GUID; +#endif + +/// +/// 4-byte buffer. An IPv4 internet protocol address. +/// +typedef struct { + UINT8 Addr[4]; +} IPv4_ADDRESS; + +/// +/// 16-byte buffer. An IPv6 internet protocol address. +/// +typedef struct { + UINT8 Addr[16]; +} IPv6_ADDRESS; + +// +// Macro that returns the byte offset of a field in a data structure. +// +#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field)) + +/// +/// _CR - returns a pointer to the structure +/// from one of its elements. +/// +#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) + +/// +/// ALIGN_POINTER - aligns a pointer to the lowest boundary +/// +#define ALIGN_POINTER(p, s) ((VOID *) ((UINTN)(p) + (((s) - ((UINTN) (p))) & ((s) - 1)))) + +/// +/// ALIGN_VARIABLE - aligns a variable up to the next natural boundary for int size of a processor +/// +#define ALIGN_VARIABLE(Value, Adjustment) \ + Adjustment = 0U; \ + if ((UINTN) (Value) % sizeof (UINTN)) { \ + (Adjustment) = (UINTN)(sizeof (UINTN) - ((UINTN) (Value) % sizeof (UINTN))); \ + } \ + (Value) = (UINTN)((UINTN) (Value) + (UINTN) (Adjustment)) + +// +// Return the maximum of two operands. +// This macro returns the maximum of two operand specified by a and b. +// Both a and b must be the same numerical types, signed or unsigned. +// +#define MAX(a, b) \ + (((a) > (b)) ? (a) : (b)) + + +// +// Return the minimum of two operands. +// This macro returns the minimal of two operand specified by a and b. +// Both a and b must be the same numerical types, signed or unsigned. +// +#define MIN(a, b) \ + (((a) < (b)) ? (a) : (b)) + + +// +// EFI Error Codes common to all execution phases +// + +typedef UINTN RETURN_STATUS; + +/// +/// Set the upper bit to indicate EFI Error. +/// +#define ENCODE_ERROR(a) ((RETURN_STATUS)(MAX_BIT | (a))) + +#define ENCODE_WARNING(a) ((RETURN_STATUS)(a)) +#define RETURN_ERROR(a) (((INTN)(RETURN_STATUS)(a)) < 0) + +#define RETURN_SUCCESS 0 +#define RETURN_LOAD_ERROR ENCODE_ERROR (1) +#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2) +#define RETURN_UNSUPPORTED ENCODE_ERROR (3) +#define RETURN_BAD_BUFFER_SIZE ENCODE_ERROR (4) +#define RETURN_BUFFER_TOO_SMALL ENCODE_ERROR (5) +#define RETURN_NOT_READY ENCODE_ERROR (6) +#define RETURN_DEVICE_ERROR ENCODE_ERROR (7) +#define RETURN_WRITE_PROTECTED ENCODE_ERROR (8) +#define RETURN_OUT_OF_RESOURCES ENCODE_ERROR (9) +#define RETURN_VOLUME_CORRUPTED ENCODE_ERROR (10) +#define RETURN_VOLUME_FULL ENCODE_ERROR (11) +#define RETURN_NO_MEDIA ENCODE_ERROR (12) +#define RETURN_MEDIA_CHANGED ENCODE_ERROR (13) +#define RETURN_NOT_FOUND ENCODE_ERROR (14) +#define RETURN_ACCESS_DENIED ENCODE_ERROR (15) +#define RETURN_NO_RESPONSE ENCODE_ERROR (16) +#define RETURN_NO_MAPPING ENCODE_ERROR (17) +#define RETURN_TIMEOUT ENCODE_ERROR (18) +#define RETURN_NOT_STARTED ENCODE_ERROR (19) +#define RETURN_ALREADY_STARTED ENCODE_ERROR (20) +#define RETURN_ABORTED ENCODE_ERROR (21) +#define RETURN_ICMP_ERROR ENCODE_ERROR (22) +#define RETURN_TFTP_ERROR ENCODE_ERROR (23) +#define RETURN_PROTOCOL_ERROR ENCODE_ERROR (24) +#define RETURN_INCOMPATIBLE_VERSION ENCODE_ERROR (25) +#define RETURN_SECURITY_VIOLATION ENCODE_ERROR (26) +#define RETURN_CRC_ERROR ENCODE_ERROR (27) +#define RETURN_END_OF_MEDIA ENCODE_ERROR (28) +#define RETURN_END_OF_FILE ENCODE_ERROR (31) + +#define RETURN_WARN_UNKNOWN_GLYPH ENCODE_WARNING (1) +#define RETURN_WARN_DELETE_FAILURE ENCODE_WARNING (2) +#define RETURN_WARN_WRITE_FAILURE ENCODE_WARNING (3) +#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4) + +typedef UINT64 PHYSICAL_ADDRESS; + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#define BIT32 0x0000000100000000ULL +#define BIT33 0x0000000200000000ULL +#define BIT34 0x0000000400000000ULL +#define BIT35 0x0000000800000000ULL +#define BIT36 0x0000001000000000ULL +#define BIT37 0x0000002000000000ULL +#define BIT38 0x0000004000000000ULL +#define BIT39 0x0000008000000000ULL +#define BIT40 0x0000010000000000ULL +#define BIT41 0x0000020000000000ULL +#define BIT42 0x0000040000000000ULL +#define BIT43 0x0000080000000000ULL +#define BIT44 0x0000100000000000ULL +#define BIT45 0x0000200000000000ULL +#define BIT46 0x0000400000000000ULL +#define BIT47 0x0000800000000000ULL +#define BIT48 0x0001000000000000ULL +#define BIT49 0x0002000000000000ULL +#define BIT50 0x0004000000000000ULL +#define BIT51 0x0008000000000000ULL +#define BIT52 0x0010000000000000ULL +#define BIT53 0x0020000000000000ULL +#define BIT54 0x0040000000000000ULL +#define BIT55 0x0080000000000000ULL +#define BIT56 0x0100000000000000ULL +#define BIT57 0x0200000000000000ULL +#define BIT58 0x0400000000000000ULL +#define BIT59 0x0800000000000000ULL +#define BIT60 0x1000000000000000ULL +#define BIT61 0x2000000000000000ULL +#define BIT62 0x4000000000000000ULL +#define BIT63 0x8000000000000000ULL + +#endif diff --git a/tools/src/GenFw/Include/Common/BuildVersion.h b/tools/src/GenFw/Include/Common/BuildVersion.h new file mode 100644 index 0000000..75f14c3 --- /dev/null +++ b/tools/src/GenFw/Include/Common/BuildVersion.h @@ -0,0 +1,9 @@ +/** @file +This file is for build version number auto generation + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#define __BUILD_VERSION "Developer Build based on Revision: Unknown" \ No newline at end of file diff --git a/tools/src/GenFw/Include/Common/PiFirmwareFile.h b/tools/src/GenFw/Include/Common/PiFirmwareFile.h new file mode 100644 index 0000000..3919aa0 --- /dev/null +++ b/tools/src/GenFw/Include/Common/PiFirmwareFile.h @@ -0,0 +1,350 @@ +/** @file + The firmware file related definitions in PI. + + @par Revision Reference: + Version 1.4. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PI_FIRMWARE_FILE_H__ +#define __PI_FIRMWARE_FILE_H__ + +#pragma pack(1) +// +// Used to verify the integrity of the file. +// +typedef union { + struct { + UINT8 Header; + UINT8 File; + } Checksum; + UINT16 Checksum16; +} EFI_FFS_INTEGRITY_CHECK; + +typedef UINT8 EFI_FV_FILETYPE; +typedef UINT8 EFI_FFS_FILE_ATTRIBUTES; +typedef UINT8 EFI_FFS_FILE_STATE; + +// +// File Types Definitions +// +#define EFI_FV_FILETYPE_ALL 0x00 +#define EFI_FV_FILETYPE_RAW 0x01 +#define EFI_FV_FILETYPE_FREEFORM 0x02 +#define EFI_FV_FILETYPE_SECURITY_CORE 0x03 +#define EFI_FV_FILETYPE_PEI_CORE 0x04 +#define EFI_FV_FILETYPE_DXE_CORE 0x05 +#define EFI_FV_FILETYPE_PEIM 0x06 +#define EFI_FV_FILETYPE_DRIVER 0x07 +#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08 +#define EFI_FV_FILETYPE_APPLICATION 0x09 +#define EFI_FV_FILETYPE_SMM 0x0A +#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B +#define EFI_FV_FILETYPE_COMBINED_SMM_DXE 0x0C +#define EFI_FV_FILETYPE_SMM_CORE 0x0D +#define EFI_FV_FILETYPE_MM_STANDALONE 0x0E +#define EFI_FV_FILETYPE_MM_CORE_STANDALONE 0x0F +#define EFI_FV_FILETYPE_OEM_MIN 0xc0 +#define EFI_FV_FILETYPE_OEM_MAX 0xdf +#define EFI_FV_FILETYPE_DEBUG_MIN 0xe0 +#define EFI_FV_FILETYPE_DEBUG_MAX 0xef +#define EFI_FV_FILETYPE_FFS_MIN 0xf0 +#define EFI_FV_FILETYPE_FFS_MAX 0xff +#define EFI_FV_FILETYPE_FFS_PAD 0xf0 +// +// FFS File Attributes. +// +#define FFS_ATTRIB_LARGE_FILE 0x01 +#define FFS_ATTRIB_DATA_ALIGNMENT2 0x02 +#define FFS_ATTRIB_FIXED 0x04 +#define FFS_ATTRIB_DATA_ALIGNMENT 0x38 +#define FFS_ATTRIB_CHECKSUM 0x40 +// +// FFS_FIXED_CHECKSUM is the checksum value used when the +// FFS_ATTRIB_CHECKSUM attribute bit is clear +// +#define FFS_FIXED_CHECKSUM 0xAA + +// +// FFS File State Bits. +// +#define EFI_FILE_HEADER_CONSTRUCTION 0x01 +#define EFI_FILE_HEADER_VALID 0x02 +#define EFI_FILE_DATA_VALID 0x04 +#define EFI_FILE_MARKED_FOR_UPDATE 0x08 +#define EFI_FILE_DELETED 0x10 +#define EFI_FILE_HEADER_INVALID 0x20 + +#define EFI_FILE_ALL_STATE_BITS (EFI_FILE_HEADER_CONSTRUCTION | \ + EFI_FILE_HEADER_VALID | \ + EFI_FILE_DATA_VALID | \ + EFI_FILE_MARKED_FOR_UPDATE | \ + EFI_FILE_DELETED | \ + EFI_FILE_HEADER_INVALID \ + ) + +// +// Each file begins with the header that describe the +// contents and state of the files. +// +typedef struct { + EFI_GUID Name; + EFI_FFS_INTEGRITY_CHECK IntegrityCheck; + EFI_FV_FILETYPE Type; + EFI_FFS_FILE_ATTRIBUTES Attributes; + UINT8 Size[3]; + EFI_FFS_FILE_STATE State; +} EFI_FFS_FILE_HEADER; + +typedef struct { + EFI_GUID Name; + EFI_FFS_INTEGRITY_CHECK IntegrityCheck; + EFI_FV_FILETYPE Type; + EFI_FFS_FILE_ATTRIBUTES Attributes; + UINT8 Size[3]; + EFI_FFS_FILE_STATE State; + UINT64 ExtendedSize; +} EFI_FFS_FILE_HEADER2; + +#define MAX_FFS_SIZE 0x1000000 + +typedef UINT8 EFI_SECTION_TYPE; + +// +// Pseudo type. It is +// used as a wild card when retrieving sections. The section +// type EFI_SECTION_ALL matches all section types. +// +#define EFI_SECTION_ALL 0x00 + +// +// Encapsulation section Type values +// +#define EFI_SECTION_COMPRESSION 0x01 + +#define EFI_SECTION_GUID_DEFINED 0x02 + +// +// Leaf section Type values +// +#define EFI_SECTION_PE32 0x10 +#define EFI_SECTION_PIC 0x11 +#define EFI_SECTION_TE 0x12 +#define EFI_SECTION_DXE_DEPEX 0x13 +#define EFI_SECTION_VERSION 0x14 +#define EFI_SECTION_USER_INTERFACE 0x15 +#define EFI_SECTION_COMPATIBILITY16 0x16 +#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17 +#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18 +#define EFI_SECTION_RAW 0x19 +#define EFI_SECTION_PEI_DEPEX 0x1B +#define EFI_SECTION_SMM_DEPEX 0x1C + +typedef struct { + UINT8 Size[3]; + EFI_SECTION_TYPE Type; +} EFI_COMMON_SECTION_HEADER; + +typedef struct { + UINT8 Size[3]; + EFI_SECTION_TYPE Type; + UINT32 ExtendedSize; +} EFI_COMMON_SECTION_HEADER2; + +#define MAX_SECTION_SIZE 0x1000000 + +// +// Leaf section type that contains an +// IA-32 16-bit executable image. +// +typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_COMPATIBILITY16_SECTION2; + +// +// CompressionType of EFI_COMPRESSION_SECTION. +// +#define EFI_NOT_COMPRESSED 0x00 +#define EFI_STANDARD_COMPRESSION 0x01 +// +// An encapsulation section type in which the +// section data is compressed. +// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + UINT32 UncompressedLength; + UINT8 CompressionType; +} EFI_COMPRESSION_SECTION; + +typedef struct { + EFI_COMMON_SECTION_HEADER2 CommonHeader; + UINT32 UncompressedLength; + UINT8 CompressionType; +} EFI_COMPRESSION_SECTION2; + +// +// Leaf section which could be used to determine the dispatch order of DXEs. +// +typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_DXE_DEPEX_SECTION2; + +// +// Leaf section witch contains a PI FV. +// +typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_FIRMWARE_VOLUME_IMAGE_SECTION2; + +// +// Leaf section which contains a single GUID. +// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + EFI_GUID SubTypeGuid; +} EFI_FREEFORM_SUBTYPE_GUID_SECTION; + +typedef struct { + EFI_COMMON_SECTION_HEADER2 CommonHeader; + EFI_GUID SubTypeGuid; +} EFI_FREEFORM_SUBTYPE_GUID_SECTION2; + +// +// Attributes of EFI_GUID_DEFINED_SECTION +// +#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01 +#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02 +// +// Leaf section which is encapsulation defined by specific GUID +// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + EFI_GUID SectionDefinitionGuid; + UINT16 DataOffset; + UINT16 Attributes; +} EFI_GUID_DEFINED_SECTION; + +typedef struct { + EFI_COMMON_SECTION_HEADER2 CommonHeader; + EFI_GUID SectionDefinitionGuid; + UINT16 DataOffset; + UINT16 Attributes; +} EFI_GUID_DEFINED_SECTION2; + +// +// Leaf section which contains PE32+ image. +// +typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_PE32_SECTION2; + +// +// Leaf section which contains PIC image. +// +typedef EFI_COMMON_SECTION_HEADER EFI_PIC_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_PIC_SECTION2; + +// +// Leaf section which used to determine the dispatch order of PEIMs. +// +typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_PEI_DEPEX_SECTION2; + +// +// Leaf section which constains the position-independent-code image. +// +typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_TE_SECTION2; + +// +// Leaf section which contains an array of zero or more bytes. +// +typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION; +typedef EFI_COMMON_SECTION_HEADER2 EFI_RAW_SECTION2; + +// +// Leaf section which contains a unicode string that +// is human readable file name. +// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + + // + // Array of unicode string. + // + CHAR16 FileNameString[1]; +} EFI_USER_INTERFACE_SECTION; + +typedef struct { + EFI_COMMON_SECTION_HEADER2 CommonHeader; + + // + // Array of unicode string. + // + CHAR16 FileNameString[1]; +} EFI_USER_INTERFACE_SECTION2; + +// +// Leaf section which contains a numeric build number and +// an optional unicode string that represent the file revision. +// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + UINT16 BuildNumber; + CHAR16 VersionString[1]; +} EFI_VERSION_SECTION; + +typedef struct { + EFI_COMMON_SECTION_HEADER2 CommonHeader; + UINT16 BuildNumber; + CHAR16 VersionString[1]; +} EFI_VERSION_SECTION2; + +// +// The argument passed as the SectionHeaderPtr parameter to the SECTION_SIZE() +// function-like macro below must not have side effects: SectionHeaderPtr is +// evaluated multiple times. +// +#define SECTION_SIZE(SectionHeaderPtr) ((UINT32) ( \ + (((EFI_COMMON_SECTION_HEADER *) (SectionHeaderPtr))->Size[0] ) | \ + (((EFI_COMMON_SECTION_HEADER *) (SectionHeaderPtr))->Size[1] << 8) | \ + (((EFI_COMMON_SECTION_HEADER *) (SectionHeaderPtr))->Size[2] << 16))) + +#pragma pack() + +typedef union { + EFI_COMMON_SECTION_HEADER *CommonHeader; + EFI_COMPRESSION_SECTION *CompressionSection; + EFI_GUID_DEFINED_SECTION *GuidDefinedSection; + EFI_PE32_SECTION *Pe32Section; + EFI_PIC_SECTION *PicSection; + EFI_TE_SECTION *TeSection; + EFI_PEI_DEPEX_SECTION *PeimHeaderSection; + EFI_DXE_DEPEX_SECTION *DependencySection; + EFI_VERSION_SECTION *VersionSection; + EFI_USER_INTERFACE_SECTION *UISection; + EFI_COMPATIBILITY16_SECTION *Code16Section; + EFI_FIRMWARE_VOLUME_IMAGE_SECTION *FVImageSection; + EFI_FREEFORM_SUBTYPE_GUID_SECTION *FreeformSubtypeSection; + EFI_RAW_SECTION *RawSection; + // + // For section whose size is equal or greater than 0x1000000 + // + EFI_COMMON_SECTION_HEADER2 *CommonHeader2; + EFI_COMPRESSION_SECTION2 *CompressionSection2; + EFI_GUID_DEFINED_SECTION2 *GuidDefinedSection2; + EFI_PE32_SECTION2 *Pe32Section2; + EFI_PIC_SECTION2 *PicSection2; + EFI_TE_SECTION2 *TeSection2; + EFI_PEI_DEPEX_SECTION2 *PeimHeaderSection2; + EFI_DXE_DEPEX_SECTION2 *DependencySection2; + EFI_VERSION_SECTION2 *VersionSection2; + EFI_USER_INTERFACE_SECTION2 *UISection2; + EFI_COMPATIBILITY16_SECTION2 *Code16Section2; + EFI_FIRMWARE_VOLUME_IMAGE_SECTION2 *FVImageSection2; + EFI_FREEFORM_SUBTYPE_GUID_SECTION2 *FreeformSubtypeSection2; + EFI_RAW_SECTION2 *RawSection2; +} EFI_FILE_SECTION_POINTER; + +#endif + diff --git a/tools/src/GenFw/Include/Common/PiFirmwareVolume.h b/tools/src/GenFw/Include/Common/PiFirmwareVolume.h new file mode 100644 index 0000000..dec5a32 --- /dev/null +++ b/tools/src/GenFw/Include/Common/PiFirmwareVolume.h @@ -0,0 +1,157 @@ +/** @file + The firmware volume related definitions in PI. + + @par Revision Reference: + Version 1.2C + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PI_FIRMWAREVOLUME_H__ +#define __PI_FIRMWAREVOLUME_H__ + +// +// EFI_FV_FILE_ATTRIBUTES +// +typedef UINT32 EFI_FV_FILE_ATTRIBUTES; + +// +// Value of EFI_FV_FILE_ATTRIBUTES. +// +#define EFI_FV_FILE_ATTRIB_ALIGNMENT 0x0000001F +#define EFI_FV_FILE_ATTRIB_FIXED 0x00000100 +#define EFI_FV_FILE_ATTRIB_MEMORY_MAPPED 0x00000200 + +typedef UINT32 EFI_FVB_ATTRIBUTES_2; + +// +// Attributes bit definitions +// +#define EFI_FVB2_READ_DISABLED_CAP 0x00000001 +#define EFI_FVB2_READ_ENABLED_CAP 0x00000002 +#define EFI_FVB2_READ_STATUS 0x00000004 +#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008 +#define EFI_FVB2_WRITE_ENABLED_CAP 0x00000010 +#define EFI_FVB2_WRITE_STATUS 0x00000020 +#define EFI_FVB2_LOCK_CAP 0x00000040 +#define EFI_FVB2_LOCK_STATUS 0x00000080 +#define EFI_FVB2_STICKY_WRITE 0x00000200 +#define EFI_FVB2_MEMORY_MAPPED 0x00000400 +#define EFI_FVB2_ERASE_POLARITY 0x00000800 +#define EFI_FVB2_READ_LOCK_CAP 0x00001000 +#define EFI_FVB2_READ_LOCK_STATUS 0x00002000 +#define EFI_FVB2_WRITE_LOCK_CAP 0x00004000 +#define EFI_FVB2_WRITE_LOCK_STATUS 0x00008000 +#define EFI_FVB2_ALIGNMENT 0x001F0000 +#define EFI_FVB2_WEAK_ALIGNMENT 0x80000000 +#define EFI_FVB2_ALIGNMENT_1 0x00000000 +#define EFI_FVB2_ALIGNMENT_2 0x00010000 +#define EFI_FVB2_ALIGNMENT_4 0x00020000 +#define EFI_FVB2_ALIGNMENT_8 0x00030000 +#define EFI_FVB2_ALIGNMENT_16 0x00040000 +#define EFI_FVB2_ALIGNMENT_32 0x00050000 +#define EFI_FVB2_ALIGNMENT_64 0x00060000 +#define EFI_FVB2_ALIGNMENT_128 0x00070000 +#define EFI_FVB2_ALIGNMENT_256 0x00080000 +#define EFI_FVB2_ALIGNMENT_512 0x00090000 +#define EFI_FVB2_ALIGNMENT_1K 0x000A0000 +#define EFI_FVB2_ALIGNMENT_2K 0x000B0000 +#define EFI_FVB2_ALIGNMENT_4K 0x000C0000 +#define EFI_FVB2_ALIGNMENT_8K 0x000D0000 +#define EFI_FVB2_ALIGNMENT_16K 0x000E0000 +#define EFI_FVB2_ALIGNMENT_32K 0x000F0000 +#define EFI_FVB2_ALIGNMENT_64K 0x00100000 +#define EFI_FVB2_ALIGNMENT_128K 0x00110000 +#define EFI_FVB2_ALIGNMENT_256K 0x00120000 +#define EFI_FVB2_ALIGNMENT_512K 0x00130000 +#define EFI_FVB2_ALIGNMENT_1M 0x00140000 +#define EFI_FVB2_ALIGNMENT_2M 0x00150000 +#define EFI_FVB2_ALIGNMENT_4M 0x00160000 +#define EFI_FVB2_ALIGNMENT_8M 0x00170000 +#define EFI_FVB2_ALIGNMENT_16M 0x00180000 +#define EFI_FVB2_ALIGNMENT_32M 0x00190000 +#define EFI_FVB2_ALIGNMENT_64M 0x001A0000 +#define EFI_FVB2_ALIGNMENT_128M 0x001B0000 +#define EFI_FVB2_ALIGNMENT_256M 0x001C0000 +#define EFI_FVB2_ALIGNMENT_512M 0x001D0000 +#define EFI_FVB2_ALIGNMENT_1G 0x001E0000 +#define EFI_FVB2_ALIGNMENT_2G 0x001F0000 + + +typedef struct { + UINT32 NumBlocks; + UINT32 Length; +} EFI_FV_BLOCK_MAP_ENTRY; + +// +// Describes the features and layout of the firmware volume. +// +typedef struct { + UINT8 ZeroVector[16]; + EFI_GUID FileSystemGuid; + UINT64 FvLength; + UINT32 Signature; + EFI_FVB_ATTRIBUTES_2 Attributes; + UINT16 HeaderLength; + UINT16 Checksum; + UINT16 ExtHeaderOffset; + UINT8 Reserved[1]; + UINT8 Revision; + EFI_FV_BLOCK_MAP_ENTRY BlockMap[1]; +} EFI_FIRMWARE_VOLUME_HEADER; + +#define EFI_FVH_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', 'H') + +/// +/// Firmware Volume Header Revision definition +/// +#define EFI_FVH_REVISION 0x02 + +// +// Extension header pointed by ExtHeaderOffset of volume header. +// +typedef struct { + EFI_GUID FvName; + UINT32 ExtHeaderSize; +} EFI_FIRMWARE_VOLUME_EXT_HEADER; + +typedef struct { + UINT16 ExtEntrySize; + UINT16 ExtEntryType; +} EFI_FIRMWARE_VOLUME_EXT_ENTRY; + +#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01 +typedef struct { + EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr; + UINT32 TypeMask; + + // + // Array of GUIDs. + // Each GUID represents an OEM file type. + // + // EFI_GUID Types[1]; + // +} EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE; + +#define EFI_FV_EXT_TYPE_GUID_TYPE 0x0002 +typedef struct { + EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr; + EFI_GUID FormatType; + + // + // An array of bytes of length Length. + // + // UINT8 Data[1]; + // +} EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE; + +#define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03 +typedef struct { + EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr; + UINT32 UsedSize; +} EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE; + +#endif diff --git a/tools/src/GenFw/Include/Common/UefiBaseTypes.h b/tools/src/GenFw/Include/Common/UefiBaseTypes.h new file mode 100644 index 0000000..8f0cdf6 --- /dev/null +++ b/tools/src/GenFw/Include/Common/UefiBaseTypes.h @@ -0,0 +1,168 @@ +/** @file + Defines data types and constants introduced in UEFI. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UEFI_BASETYPE_H__ +#define __UEFI_BASETYPE_H__ + +#include + +// +// Basical data type definitions introduced in UEFI. +// +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} EFI_GUID; + +typedef RETURN_STATUS EFI_STATUS; +typedef VOID *EFI_HANDLE; + +typedef VOID *EFI_EVENT; + +typedef UINTN EFI_TPL; + + +typedef UINT64 EFI_LBA; + + +typedef UINT16 STRING_REF; + +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; + +// +// EFI Time Abstraction: +// Year: 2000 - 20XX +// Month: 1 - 12 +// Day: 1 - 31 +// Hour: 0 - 23 +// Minute: 0 - 59 +// Second: 0 - 59 +// Nanosecond: 0 - 999,999,999 +// TimeZone: -1440 to 1440 or 2047 +// +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Pad1; + UINT32 Nanosecond; + INT16 TimeZone; + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + + +// +// Networking Definitions +// +typedef struct { + UINT8 Addr[4]; +} EFI_IPv4_ADDRESS; + +typedef struct { + UINT8 Addr[16]; +} EFI_IPv6_ADDRESS; + +typedef struct { + UINT8 Addr[32]; +} EFI_MAC_ADDRESS; + +typedef union { + UINT32 Addr[4]; + EFI_IPv4_ADDRESS v4; + EFI_IPv6_ADDRESS v6; +} EFI_IP_ADDRESS; + + +// +// Enumeration of EFI_STATUS. +// +#define EFI_SUCCESS RETURN_SUCCESS +#define EFI_LOAD_ERROR RETURN_LOAD_ERROR +#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER +#define EFI_UNSUPPORTED RETURN_UNSUPPORTED +#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE +#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL +#define EFI_NOT_READY RETURN_NOT_READY +#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR +#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED +#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES +#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED +#define EFI_VOLUME_FULL RETURN_VOLUME_FULL +#define EFI_NO_MEDIA RETURN_NO_MEDIA +#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED +#define EFI_NOT_FOUND RETURN_NOT_FOUND +#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED +#define EFI_NO_RESPONSE RETURN_NO_RESPONSE +#define EFI_NO_MAPPING RETURN_NO_MAPPING +#define EFI_TIMEOUT RETURN_TIMEOUT +#define EFI_NOT_STARTED RETURN_NOT_STARTED +#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED +#define EFI_ABORTED RETURN_ABORTED +#define EFI_ICMP_ERROR RETURN_ICMP_ERROR +#define EFI_TFTP_ERROR RETURN_TFTP_ERROR +#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR +#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION +#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION +#define EFI_CRC_ERROR RETURN_CRC_ERROR +#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA +#define EFI_END_OF_FILE RETURN_END_OF_FILE + +#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH +#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE +#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE +#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL + + +#define NULL_HANDLE ((VOID *) 0) + +// +// Define macro to encode the status code. +// +#define EFIERR(_a) ENCODE_ERROR(_a) + +#define EFI_ERROR(A) RETURN_ERROR(A) + +// +// Define macros to build data structure signatures from characters. +// +#define SIGNATURE_16(A, B) ((A) | (B << 8)) +#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) + + +// +// Returns the byte offset to a field within a structure +// +#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field))) + +// +// The EFI memory allocation functions work in units of EFI_PAGEs that are +// 4K. This should in no way be confused with the page size of the processor. +// An EFI_PAGE is just the quanta of memory in EFI. +// +#define EFI_PAGE_SIZE 0x1000 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) (((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0)) + +#define EFI_PAGES_TO_SIZE(a) ( (a) << EFI_PAGE_SHIFT) + + +#define EFI_MAX_BIT MAX_BIT + +#endif diff --git a/tools/src/GenFw/Include/Common/UefiInternalFormRepresentation.h b/tools/src/GenFw/Include/Common/UefiInternalFormRepresentation.h new file mode 100644 index 0000000..22c99a1 --- /dev/null +++ b/tools/src/GenFw/Include/Common/UefiInternalFormRepresentation.h @@ -0,0 +1,1680 @@ +/** @file + This file defines the encoding for the VFR (Visual Form Representation) language. + IFR is primarily consumed by the EFI presentation engine, and produced by EFI + internal application and drivers as well as all add-in card option-ROM drivers + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + These definitions are from UEFI 2.6 + +**/ + +#ifndef __UEFI_INTERNAL_FORMREPRESENTATION_H__ +#define __UEFI_INTERNAL_FORMREPRESENTATION_H__ + + +#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \ + { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4, 0xe } } + +// +// The following types are currently defined: +// +typedef UINT32 RELOFST; + +typedef VOID* EFI_HII_HANDLE; +typedef CHAR16* EFI_STRING; +typedef UINT16 EFI_IMAGE_ID; +typedef UINT16 EFI_QUESTION_ID; +typedef UINT16 EFI_STRING_ID; +typedef UINT16 EFI_FORM_ID; +typedef UINT16 EFI_VARSTORE_ID; +typedef UINT16 EFI_DEFAULT_ID; +typedef UINT32 EFI_HII_FONT_STYLE; + + + +#pragma pack(1) + + +// +// HII package list +// +typedef struct { + EFI_GUID PackageListGuid; + UINT32 PackageLength; +} EFI_HII_PACKAGE_LIST_HEADER; + +/** + + Each package starts with a header, as defined above, which + indicates the size and type of the package. When added to a + pointer pointing to the start of the header, Length points at + the next package. The package lists form a package list when + concatenated together and terminated with an + EFI_HII_PACKAGE_HEADER with a Type of EFI_HII_PACKAGE_END. The + type EFI_HII_PACKAGE_TYPE_GUID is used for vendor-defined HII + packages, whose contents are determined by the Guid. The range + of package types starting with EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN + through EFI_HII_PACKAGE_TYPE_SYSTEM_END are reserved for system + firmware implementers. + + @param Length The size of the package in bytes. + + @param Type The package type. See EFI_HII_PACKAGE_TYPE_x, + below. + + @param Data The package data, the format of which is + determined by Type. + +**/ +typedef struct { + UINT32 Length:24; + UINT32 Type:8; + // UINT8 Data[...]; +} EFI_HII_PACKAGE_HEADER; + +// +// EFI_HII_PACKAGE_TYPE_x. +// +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORM 0x02 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x03 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +// +// Simplified Font Package +// + +#define EFI_GLYPH_HEIGHT 19 +#define EFI_GLYPH_WIDTH 8 +// +// Contents of EFI_NARROW_GLYPH.Attributes +// +#define EFI_GLYPH_NON_SPACING 0x01 +#define EFI_GLYPH_WIDE 0x02 + +typedef struct { + CHAR16 UnicodeWeight; + UINT8 Attributes; + UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; +} EFI_NARROW_GLYPH; + +typedef struct { + CHAR16 UnicodeWeight; + UINT8 Attributes; + UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; + UINT8 GlyphCol2[EFI_GLYPH_HEIGHT]; + UINT8 Pad[3]; +} EFI_WIDE_GLYPH; + + +typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT16 NumberOfNarrowGlyphs; + UINT16 NumberOfWideGlyphs; + // EFI_NARROW_GLYPH NarrowGlyphs[]; + // EFI_WIDE_GLYPH WideGlyphs[]; +} EFI_HII_SIMPLE_FONT_PACKAGE_HDR; + +// +// Font Package +// + +#define EFI_HII_FONT_STYLE_BOLD 0x00000001 +#define EFI_HII_FONT_STYLE_ITALIC 0x00000002 +#define EFI_HII_FONT_STYLE_EMBOSS 0x00010000 +#define EFI_HII_FONT_STYLE_OUTLINE 0x00020000 +#define EFI_HII_FONT_STYLE_SHADOW 0x00040000 +#define EFI_HII_FONT_STYLE_UNDERLINE 0x00080000 +#define EFI_HII_FONT_STYLE_DBL_UNDER 0x00100000 + +typedef struct _EFI_HII_GLYPH_INFO { + UINT16 Width; + UINT16 Height; + INT16 OffsetX; + INT16 OffsetY; + INT16 AdvanceX; +} EFI_HII_GLYPH_INFO; + +typedef struct _EFI_HII_FONT_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 HdrSize; + UINT32 GlyphBlockOffset; + EFI_HII_GLYPH_INFO Cell; + EFI_HII_FONT_STYLE FontStyle; + CHAR16 FontFamily[1]; +} EFI_HII_FONT_PACKAGE_HDR; + +#define EFI_HII_GIBT_END 0x00 +#define EFI_HII_GIBT_GLYPH 0x10 +#define EFI_HII_GIBT_GLYPHS 0x11 +#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12 +#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13 +#define EFI_HII_GIBT_GLYPH_VARIABILITY 0x14 +#define EFI_HII_GIBT_DUPLICATE 0x20 +#define EFI_HII_GIBT_SKIP2 0x21 +#define EFI_HII_GIBT_SKIP1 0x22 +#define EFI_HII_GIBT_DEFAULTS 0x23 +#define EFI_HII_GIBT_EXT1 0x30 +#define EFI_HII_GIBT_EXT2 0x31 +#define EFI_HII_GIBT_EXT4 0x32 + +typedef struct _EFI_HII_GLYPH_BLOCK { + UINT8 BlockType; +} EFI_HII_GLYPH_BLOCK; + +typedef struct _EFI_HII_GIBT_DEFAULTS_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; +} EFI_HII_GIBT_DEFAULTS_BLOCK; + +typedef struct _EFI_HII_GIBT_DUPLICATE_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + CHAR16 CharValue; +} EFI_HII_GIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_GLYPH_GIBT_END_BLOCK { + EFI_HII_GLYPH_BLOCK Header; +} EFI_GLYPH_GIBT_END_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT1_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_GIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT2_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_GIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT4_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_GIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPH_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Cell.Width+7)/8)*Cell.Height +} EFI_HII_GIBT_GLYPH_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT16 Count; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Cell.Width+7)/8)*Cell.Height +} EFI_HII_GIBT_GLYPHS_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Global.Cell.Width+7)/8)*Global.Cell.Height +} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT16 Count; + UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Global.Cell.Width+7)/8)*Global.Cell.Height +} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK; + +typedef struct _EFI_HII_GIBT_VARIABILITY_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT8 GlyphPackInBits; + UINT8 BitmapData [1]; +} EFI_HII_GIBT_VARIABILITY_BLOCK; + +typedef struct _EFI_HII_GIBT_SKIP1_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_GIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_GIBT_SKIP2_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_GIBT_SKIP2_BLOCK; + +// +// Device Path Package +// +typedef struct _EFI_HII_DEVICE_PATH_PACKAGE { + EFI_HII_PACKAGE_HEADER Header; + // EFI_DEVICE_PATH_PROTOCOL DevicePath[]; +} EFI_HII_DEVICE_PATH_PACKAGE; + +// +// GUID Package +// +typedef struct _EFI_HII_GUID_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + EFI_GUID Guid; + // Data per GUID definition may follow +} EFI_HII_GUID_PACKAGE_HDR; + +// +// String Package +// + +#define UEFI_CONFIG_LANG "x-UEFI" +#define UEFI_CONFIG_LANG2 "x-i-UEFI" + +typedef struct _EFI_HII_STRING_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 HdrSize; + UINT32 StringInfoOffset; + CHAR16 LanguageWindow[16]; + EFI_STRING_ID LanguageName; + CHAR8 Language[1]; +} EFI_HII_STRING_PACKAGE_HDR; + +typedef struct { + UINT8 BlockType; +} EFI_HII_STRING_BLOCK; + +#define EFI_HII_SIBT_END 0x00 +#define EFI_HII_SIBT_STRING_SCSU 0x10 +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 +#define EFI_HII_SIBT_STRING_UCS2 0x14 +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 +#define EFI_HII_SIBT_DUPLICATE 0x20 +#define EFI_HII_SIBT_SKIP2 0x21 +#define EFI_HII_SIBT_SKIP1 0x22 +#define EFI_HII_SIBT_EXT1 0x30 +#define EFI_HII_SIBT_EXT2 0x31 +#define EFI_HII_SIBT_EXT4 0x32 +#define EFI_HII_SIBT_FONT 0x40 + +typedef struct _EFI_HII_SIBT_DUPLICATE_BLOCK { + EFI_HII_STRING_BLOCK Header; + EFI_STRING_ID StringId; +} EFI_HII_SIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_HII_SIBT_END_BLOCK { + EFI_HII_STRING_BLOCK Header; +} EFI_HII_SIBT_END_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT1_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_SIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_SIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT4_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_SIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_SIBT_FONT_BLOCK { + EFI_HII_SIBT_EXT2_BLOCK Header; + UINT8 FontId; + UINT16 FontSize; + EFI_HII_FONT_STYLE FontStyle; + CHAR16 FontName[1]; +} EFI_HII_SIBT_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_SKIP1_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_SIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_SIBT_SKIP2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_SIBT_SKIP2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_SCSU_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRING_SCSU_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_SCSU_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 StringCount; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRINGS_SCSU_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT16 StringCount; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_UCS2_BLOCK { + EFI_HII_STRING_BLOCK Header; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRING_UCS2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_UCS2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 StringCount; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRINGS_UCS2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT16 StringCount; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK; + +// +// Image Packages +// + +typedef struct _EFI_HII_IMAGE_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 ImageInfoOffset; + UINT32 PaletteInfoOffset; +} EFI_HII_IMAGE_PACKAGE_HDR; + +typedef struct _EFI_HII_IMAGE_BLOCK { + UINT8 BlockType; +} EFI_HII_IMAGE_BLOCK; + +#define EFI_HII_IIBT_END 0x00 +#define EFI_HII_IIBT_IMAGE_1BIT 0x10 +#define EFI_HII_IIBT_IMAGE_1BIT_TRANS 0x11 +#define EFI_HII_IIBT_IMAGE_4BIT 0x12 +#define EFI_HII_IIBT_IMAGE_4BIT_TRANS 0x13 +#define EFI_HII_IIBT_IMAGE_8BIT 0x14 +#define EFI_HII_IIBT_IMAGE_8BIT_TRANS 0x15 +#define EFI_HII_IIBT_IMAGE_24BIT 0x16 +#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17 +#define EFI_HII_IIBT_IMAGE_JPEG 0x18 +#define EFI_HII_IIBT_IMAGE_PNG 0x19 +#define EFI_HII_IIBT_DUPLICATE 0x20 +#define EFI_HII_IIBT_SKIP2 0x21 +#define EFI_HII_IIBT_SKIP1 0x22 +#define EFI_HII_IIBT_EXT1 0x30 +#define EFI_HII_IIBT_EXT2 0x31 +#define EFI_HII_IIBT_EXT4 0x32 + +typedef struct _EFI_HII_IIBT_END_BLOCK { + EFI_HII_IMAGE_BLOCK Header; +} EFI_HII_IIBT_END_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT1_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_IIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT2_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_IIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT4_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_IIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_1BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_1BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_RGB_PIXEL { + UINT8 b; + UINT8 g; + UINT8 r; +} EFI_HII_RGB_PIXEL; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BASE { + UINT16 Width; + UINT16 Height; + EFI_HII_RGB_PIXEL Bitmap[1]; +} EFI_HII_IIBT_IMAGE_24BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_24BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_4BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_4BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_8BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_PALETTE_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_8BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_8BIT_TRAN_BLOCK; + +typedef struct _EFI_HII_IIBT_DUPLICATE_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_IMAGE_ID ImageId; +} EFI_HII_IIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_HII_IIBT_JPEG_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT32 Size; + UINT8 Data[1]; +} EFI_HII_IIBT_JPEG_BLOCK; + +typedef struct _EFI_HII_IIBT_PNG_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT32 Size; + UINT8 Data[1]; +} EFI_HII_IIBT_PNG_BLOCK; + +typedef struct _EFI_HII_IIBT_SKIP1_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_IIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_IIBT_SKIP2_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_IIBT_SKIP2_BLOCK; + +typedef struct _EFI_HII_IMAGE_PALETTE_INFO_HEADER { + UINT16 PaletteCount; +} EFI_HII_IMAGE_PALETTE_INFO_HEADER; + +typedef struct _EFI_HII_IMAGE_PALETTE_INFO { + UINT16 PaletteSize; + EFI_HII_RGB_PIXEL PaletteValue[1]; +} EFI_HII_IMAGE_PALETTE_INFO; + +// +// Forms Package +// + +typedef struct _EFI_HII_FORM_PACKAGE { + EFI_HII_PACKAGE_HEADER Header; + // EFI_IFR_OP_HEADER OpCodeHeader; + // More op-codes follow +} EFI_HII_FORM_PACKAGE; + +typedef struct { + UINT8 Hour; + UINT8 Minute; + UINT8 Second; +} EFI_HII_TIME; + +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; +} EFI_HII_DATE; + +typedef struct { + EFI_QUESTION_ID QuestionId; + EFI_FORM_ID FormId; + EFI_GUID FormSetGuid; + EFI_STRING_ID DevicePath; +} EFI_HII_REF; + +typedef union { + UINT8 u8; + UINT16 u16; + UINT32 u32; + UINT64 u64; + BOOLEAN b; + EFI_HII_TIME time; + EFI_HII_DATE date; + EFI_STRING_ID string; + EFI_HII_REF ref; +} EFI_IFR_TYPE_VALUE; + +#define EFI_IFR_FORM_OP 0x01 +#define EFI_IFR_SUBTITLE_OP 0x02 +#define EFI_IFR_TEXT_OP 0x03 +#define EFI_IFR_IMAGE_OP 0x04 +#define EFI_IFR_ONE_OF_OP 0x05 +#define EFI_IFR_CHECKBOX_OP 0x06 +#define EFI_IFR_NUMERIC_OP 0x07 +#define EFI_IFR_PASSWORD_OP 0x08 +#define EFI_IFR_ONE_OF_OPTION_OP 0x09 +#define EFI_IFR_SUPPRESS_IF_OP 0x0A +#define EFI_IFR_LOCKED_OP 0x0B +#define EFI_IFR_ACTION_OP 0x0C +#define EFI_IFR_RESET_BUTTON_OP 0x0D +#define EFI_IFR_FORM_SET_OP 0x0E +#define EFI_IFR_REF_OP 0x0F +#define EFI_IFR_NO_SUBMIT_IF_OP 0x10 +#define EFI_IFR_INCONSISTENT_IF_OP 0x11 +#define EFI_IFR_EQ_ID_VAL_OP 0x12 +#define EFI_IFR_EQ_ID_ID_OP 0x13 +#define EFI_IFR_EQ_ID_VAL_LIST_OP 0x14 +#define EFI_IFR_AND_OP 0x15 +#define EFI_IFR_OR_OP 0x16 +#define EFI_IFR_NOT_OP 0x17 +#define EFI_IFR_RULE_OP 0x18 +#define EFI_IFR_GRAY_OUT_IF_OP 0x19 +#define EFI_IFR_DATE_OP 0x1A +#define EFI_IFR_TIME_OP 0x1B +#define EFI_IFR_STRING_OP 0x1C +#define EFI_IFR_REFRESH_OP 0x1D +#define EFI_IFR_DISABLE_IF_OP 0x1E +#define EFI_IFR_TO_LOWER_OP 0x20 +#define EFI_IFR_TO_UPPER_OP 0x21 +#define EFI_IFR_MAP_OP 0x22 +#define EFI_IFR_ORDERED_LIST_OP 0x23 +#define EFI_IFR_VARSTORE_OP 0x24 +#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25 +#define EFI_IFR_VARSTORE_EFI_OP 0x26 +#define EFI_IFR_VARSTORE_DEVICE_OP 0x27 +#define EFI_IFR_VERSION_OP 0x28 +#define EFI_IFR_END_OP 0x29 +#define EFI_IFR_MATCH_OP 0x2A +#define EFI_IFR_GET_OP 0x2B +#define EFI_IFR_SET_OP 0x2C +#define EFI_IFR_READ_OP 0x2D +#define EFI_IFR_WRITE_OP 0x2E +#define EFI_IFR_EQUAL_OP 0x2F +#define EFI_IFR_NOT_EQUAL_OP 0x30 +#define EFI_IFR_GREATER_THAN_OP 0x31 +#define EFI_IFR_GREATER_EQUAL_OP 0x32 +#define EFI_IFR_LESS_THAN_OP 0x33 +#define EFI_IFR_LESS_EQUAL_OP 0x34 +#define EFI_IFR_BITWISE_AND_OP 0x35 +#define EFI_IFR_BITWISE_OR_OP 0x36 +#define EFI_IFR_BITWISE_NOT_OP 0x37 +#define EFI_IFR_SHIFT_LEFT_OP 0x38 +#define EFI_IFR_SHIFT_RIGHT_OP 0x39 +#define EFI_IFR_ADD_OP 0x3A +#define EFI_IFR_SUBTRACT_OP 0x3B +#define EFI_IFR_MULTIPLY_OP 0x3C +#define EFI_IFR_DIVIDE_OP 0x3D +#define EFI_IFR_MODULO_OP 0x3E +#define EFI_IFR_RULE_REF_OP 0x3F +#define EFI_IFR_QUESTION_REF1_OP 0x40 +#define EFI_IFR_QUESTION_REF2_OP 0x41 +#define EFI_IFR_UINT8_OP 0x42 +#define EFI_IFR_UINT16_OP 0x43 +#define EFI_IFR_UINT32_OP 0x44 +#define EFI_IFR_UINT64_OP 0x45 +#define EFI_IFR_TRUE_OP 0x46 +#define EFI_IFR_FALSE_OP 0x47 +#define EFI_IFR_TO_UINT_OP 0x48 +#define EFI_IFR_TO_STRING_OP 0x49 +#define EFI_IFR_TO_BOOLEAN_OP 0x4A +#define EFI_IFR_MID_OP 0x4B +#define EFI_IFR_FIND_OP 0x4C +#define EFI_IFR_TOKEN_OP 0x4D +#define EFI_IFR_STRING_REF1_OP 0x4E +#define EFI_IFR_STRING_REF2_OP 0x4F +#define EFI_IFR_CONDITIONAL_OP 0x50 +#define EFI_IFR_QUESTION_REF3_OP 0x51 +#define EFI_IFR_ZERO_OP 0x52 +#define EFI_IFR_ONE_OP 0x53 +#define EFI_IFR_ONES_OP 0x54 +#define EFI_IFR_UNDEFINED_OP 0x55 +#define EFI_IFR_LENGTH_OP 0x56 +#define EFI_IFR_DUP_OP 0x57 +#define EFI_IFR_THIS_OP 0x58 +#define EFI_IFR_SPAN_OP 0x59 +#define EFI_IFR_VALUE_OP 0x5A +#define EFI_IFR_DEFAULT_OP 0x5B +#define EFI_IFR_DEFAULTSTORE_OP 0x5C +#define EFI_IFR_FORM_MAP_OP 0x5D +#define EFI_IFR_CATENATE_OP 0x5E +#define EFI_IFR_GUID_OP 0x5F +#define EFI_IFR_SECURITY_OP 0x60 +#define EFI_IFR_MODAL_TAG_OP 0x61 +#define EFI_IFR_REFRESH_ID_OP 0x62 +#define EFI_IFR_WARNING_IF_OP 0x63 +#define EFI_IFR_MATCH2_OP 0x64 + + +typedef struct _EFI_IFR_OP_HEADER { + UINT8 OpCode; + UINT8 Length:7; + UINT8 Scope:1; +} EFI_IFR_OP_HEADER; + +typedef struct _EFI_IFR_STATEMENT_HEADER { + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; +} EFI_IFR_STATEMENT_HEADER; + +typedef struct _EFI_IFR_QUESTION_HEADER { + EFI_IFR_STATEMENT_HEADER Header; + EFI_QUESTION_ID QuestionId; + EFI_VARSTORE_ID VarStoreId; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT8 Flags; +} EFI_IFR_QUESTION_HEADER; + +#define EFI_IFR_FLAG_READ_ONLY 0x01 +#define EFI_IFR_FLAG_CALLBACK 0x04 +#define EFI_IFR_FLAG_RESET_REQUIRED 0x10 +#define EFI_IFR_FLAG_REST_STYLE 0x20 +#define EFI_IFR_FLAG_RECONNECT_REQUIRED 0x40 +#define EFI_IFR_FLAG_OPTIONS_ONLY 0x80 + +typedef struct _EFI_IFR_DEFAULTSTORE { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DefaultName; + UINT16 DefaultId; +} EFI_IFR_DEFAULTSTORE; + +#define EFI_HII_DEFAULT_CLASS_STANDARD 0x0000 +#define EFI_HII_DEFAULT_CLASS_MANUFACTURING 0x0001 +#define EFI_HII_DEFAULT_CLASS_SAFE 0x0002 +#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000 +#define EFI_HII_DEFAULT_CLASS_PLATFORM_END 0x7fff +#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000 +#define EFI_HII_DEFAULT_CLASS_HARDWARE_END 0xbfff +#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000 +#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END 0xffff + +typedef struct _EFI_IFR_VARSTORE { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + EFI_VARSTORE_ID VarStoreId; + UINT16 Size; + UINT8 Name[1]; +} EFI_IFR_VARSTORE; + +typedef struct _EFI_IFR_VARSTORE_EFI { + EFI_IFR_OP_HEADER Header; + EFI_VARSTORE_ID VarStoreId; + EFI_GUID Guid; + UINT32 Attributes; + UINT16 Size; + UINT8 Name[1]; +} EFI_IFR_VARSTORE_EFI; + +typedef struct _EFI_IFR_VARSTORE_NAME_VALUE { + EFI_IFR_OP_HEADER Header; + EFI_VARSTORE_ID VarStoreId; + EFI_GUID Guid; +} EFI_IFR_VARSTORE_NAME_VALUE; + +typedef struct _EFI_IFR_FORM_SET { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; + UINT8 Flags; + // EFI_GUID ClassGuid[]; +} EFI_IFR_FORM_SET; + +typedef struct _EFI_IFR_END { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_END; + +typedef struct _EFI_IFR_FORM { + EFI_IFR_OP_HEADER Header; + UINT16 FormId; + EFI_STRING_ID FormTitle; +} EFI_IFR_FORM; + +typedef struct _EFI_IFR_IMAGE { + EFI_IFR_OP_HEADER Header; + EFI_IMAGE_ID Id; +} EFI_IFR_IMAGE; + +typedef struct _EFI_IFR_MODAL_TAG { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MODAL_TAG; + +typedef struct _EFI_IFR_LOCKED { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LOCKED; + +typedef struct _EFI_IFR_RULE { + EFI_IFR_OP_HEADER Header; + UINT8 RuleId; +} EFI_IFR_RULE; + +typedef struct _EFI_IFR_DEFAULT { + EFI_IFR_OP_HEADER Header; + UINT16 DefaultId; + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_IFR_DEFAULT; + +typedef struct _EFI_IFR_DEFAULT_2 { + EFI_IFR_OP_HEADER Header; + UINT16 DefaultId; + UINT8 Type; +} EFI_IFR_DEFAULT_2; + +typedef struct _EFI_IFR_VALUE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_VALUE; + +typedef struct _EFI_IFR_SUBTITLE { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + UINT8 Flags; +} EFI_IFR_SUBTITLE; + +#define EFI_IFR_FLAGS_HORIZONTAL 0x01 + +typedef struct _EFI_IFR_CHECKBOX { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_CHECKBOX; + +#define EFI_IFR_CHECKBOX_DEFAULT 0x01 +#define EFI_IFR_CHECKBOX_DEFAULT_MFG 0x02 + +typedef struct _EFI_IFR_TEXT { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + EFI_STRING_ID TextTwo; +} EFI_IFR_TEXT; + +typedef struct _EFI_IFR_REF { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; +} EFI_IFR_REF; + +typedef struct _EFI_IFR_REF2 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; +} EFI_IFR_REF2; + +typedef struct _EFI_IFR_REF3 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; + EFI_GUID FormSetId; +} EFI_IFR_REF3; + +typedef struct _EFI_IFR_REF4 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; + EFI_GUID FormSetId; + EFI_STRING_ID DevicePath; +} EFI_IFR_REF4; + +typedef struct _EFI_IFR_REF5 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; +} EFI_IFR_REF5; + +typedef struct _EFI_IFR_RESET_BUTTON { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + EFI_DEFAULT_ID DefaultId; +} EFI_IFR_RESET_BUTTON; + +typedef struct _EFI_IFR_ACTION { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_STRING_ID QuestionConfig; +} EFI_IFR_ACTION; + +typedef struct _EFI_IFR_ACTION_1 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; +} EFI_IFR_ACTION_1; + +typedef struct _EFI_IFR_DATE { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_DATE; + +#define EFI_QF_DATE_YEAR_SUPPRESS 0x01 +#define EFI_QF_DATE_MONTH_SUPPRESS 0x02 +#define EFI_QF_DATE_DAY_SUPPRESS 0x04 + +#define EFI_QF_DATE_STORAGE 0x30 +#define QF_DATE_STORAGE_NORMAL 0x00 +#define QF_DATE_STORAGE_TIME 0x10 +#define QF_DATE_STORAGE_WAKEUP 0x20 + +typedef union { + struct { + UINT8 MinValue; + UINT8 MaxValue; + UINT8 Step; + } u8; + struct { + UINT16 MinValue; + UINT16 MaxValue; + UINT16 Step; + } u16; + struct { + UINT32 MinValue; + UINT32 MaxValue; + UINT32 Step; + } u32; + struct { + UINT64 MinValue; + UINT64 MaxValue; + UINT64 Step; + } u64; +} MINMAXSTEP_DATA; + +typedef struct _EFI_IFR_NUMERIC { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; + MINMAXSTEP_DATA data; +} EFI_IFR_NUMERIC; + +#define EFI_IFR_NUMERIC_SIZE 0x03 +#define EFI_IFR_NUMERIC_SIZE_1 0x00 +#define EFI_IFR_NUMERIC_SIZE_2 0x01 +#define EFI_IFR_NUMERIC_SIZE_4 0x02 +#define EFI_IFR_NUMERIC_SIZE_8 0x03 + +#define EFI_IFR_DISPLAY 0x30 +#define EFI_IFR_DISPLAY_INT_DEC 0x00 +#define EFI_IFR_DISPLAY_UINT_DEC 0x10 +#define EFI_IFR_DISPLAY_UINT_HEX 0x20 + +typedef struct _EFI_IFR_ONE_OF { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; + MINMAXSTEP_DATA data; +} EFI_IFR_ONE_OF; + +typedef struct _EFI_IFR_STRING { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 MinSize; + UINT8 MaxSize; + UINT8 Flags; +} EFI_IFR_STRING; + +#define EFI_IFR_STRING_MULTI_LINE 0x01 + +typedef struct _EFI_IFR_PASSWORD { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT16 MinSize; + UINT16 MaxSize; +} EFI_IFR_PASSWORD; + +typedef struct _EFI_IFR_ORDERED_LIST { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 MaxContainers; + UINT8 Flags; +} EFI_IFR_ORDERED_LIST; + +#define EFI_IFR_UNIQUE_SET 0x01 +#define EFI_IFR_NO_EMPTY_SET 0x02 + +typedef struct _EFI_IFR_TIME { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_TIME; + +#define QF_TIME_HOUR_SUPPRESS 0x01 +#define QF_TIME_MINUTE_SUPPRESS 0x02 +#define QF_TIME_SECOND_SUPPRESS 0x04 + +#define QF_TIME_STORAGE 0x30 +#define QF_TIME_STORAGE_NORMAL 0x00 +#define QF_TIME_STORAGE_TIME 0x10 +#define QF_TIME_STORAGE_WAKEUP 0x20 + +typedef struct _EFI_IFR_DISABLE_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DISABLE_IF; + +typedef struct _EFI_IFR_SUPPRESS_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SUPPRESS_IF; + +typedef struct _EFI_IFR_GRAY_OUT_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GRAY_OUT_IF; + +typedef struct _EFI_IFR_INCONSISTENT_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Error; +} EFI_IFR_INCONSISTENT_IF; + +typedef struct _EFI_IFR_NO_SUBMIT_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Error; +} EFI_IFR_NO_SUBMIT_IF; + +typedef struct _EFI_IFR_WARNING_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Warning; + UINT8 TimeOut; +} EFI_IFR_WARNING_IF; + +typedef struct _EFI_IFR_REFRESH { + EFI_IFR_OP_HEADER Header; + UINT8 RefreshInterval; +} EFI_IFR_REFRESH; + +typedef struct _EFI_IFR_REFRESH_ID { + EFI_IFR_OP_HEADER Header; + EFI_GUID RefreshEventGroupId; +} EFI_IFR_REFRESH_ID; + +typedef struct _EFI_IFR_VARSTORE_DEVICE { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; +} EFI_IFR_VARSTORE_DEVICE; + +typedef struct _EFI_IFR_ONE_OF_OPTION { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Option; + UINT8 Flags; + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_IFR_ONE_OF_OPTION; + +#define EFI_IFR_TYPE_NUM_SIZE_8 0x00 +#define EFI_IFR_TYPE_NUM_SIZE_16 0x01 +#define EFI_IFR_TYPE_NUM_SIZE_32 0x02 +#define EFI_IFR_TYPE_NUM_SIZE_64 0x03 +#define EFI_IFR_TYPE_BOOLEAN 0x04 +#define EFI_IFR_TYPE_TIME 0x05 +#define EFI_IFR_TYPE_DATE 0x06 +#define EFI_IFR_TYPE_STRING 0x07 +#define EFI_IFR_TYPE_OTHER 0x08 +#define EFI_IFR_TYPE_UNDEFINED 0x09 +#define EFI_IFR_TYPE_ACTION 0x0A +#define EFI_IFR_TYPE_BUFFER 0x0B +#define EFI_IFR_TYPE_REF 0x0C + +#define EFI_IFR_OPTION_DEFAULT 0x10 +#define EFI_IFR_OPTION_DEFAULT_MFG 0x20 + +typedef struct _EFI_IFR_GUID { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + //Optional Data Follows +} EFI_IFR_GUID; + +typedef struct _EFI_IFR_DUP { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DUP; + +typedef struct _EFI_IFR_EQ_ID_ID { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId1; + EFI_QUESTION_ID QuestionId2; +} EFI_IFR_EQ_ID_ID; + +typedef struct _EFI_IFR_EQ_ID_VAL { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; + UINT16 Value; +} EFI_IFR_EQ_ID_VAL; + +typedef struct _EFI_IFR_EQ_ID_VAL_LIST { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; + UINT16 ListLength; + UINT16 ValueList[1]; +} EFI_IFR_EQ_ID_VAL_LIST; + +typedef struct _EFI_IFR_QUESTION_REF1 { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; +} EFI_IFR_QUESTION_REF1; + +typedef struct _EFI_IFR_UINT8 { + EFI_IFR_OP_HEADER Header; + UINT8 Value; +} EFI_IFR_UINT8; + +typedef struct _EFI_IFR_UINT16 { + EFI_IFR_OP_HEADER Header; + UINT16 Value; +} EFI_IFR_UINT16; + +typedef struct _EFI_IFR_QUESTION_REF2 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_QUESTION_REF2; + +typedef struct _EFI_IFR_UINT32 { + EFI_IFR_OP_HEADER Header; + UINT32 Value; +} EFI_IFR_UINT32; + +typedef struct _EFI_IFR_UINT64 { + EFI_IFR_OP_HEADER Header; + UINT64 Value; +} EFI_IFR_UINT64; + +typedef struct _EFI_IFR_QUESTION_REF3 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_QUESTION_REF3; + +typedef struct _EFI_IFR_QUESTION_REF3_2 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; +} EFI_IFR_QUESTION_REF3_2; + +typedef struct _EFI_IFR_QUESTION_REF3_3 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; + EFI_GUID Guid; +} EFI_IFR_QUESTION_REF3_3; + +typedef struct _EFI_IFR_RULE_REF { + EFI_IFR_OP_HEADER Header; + UINT8 RuleId; +} EFI_IFR_RULE_REF; + +typedef struct _EFI_IFR_STRING_REF1 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID StringId; +} EFI_IFR_STRING_REF1; + +typedef struct _EFI_IFR_STRING_REF2 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_STRING_REF2; + +typedef struct _EFI_IFR_THIS { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_THIS; + +typedef struct _EFI_IFR_TRUE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TRUE; + +typedef struct _EFI_IFR_FALSE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_FALSE; + +typedef struct _EFI_IFR_ONE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ONE; + +typedef struct _EFI_IFR_ONES { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ONES; + +typedef struct _EFI_IFR_ZERO { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ZERO; + +typedef struct _EFI_IFR_UNDEFINED { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_UNDEFINED; + +typedef struct _EFI_IFR_VERSION { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_VERSION; + +typedef struct _EFI_IFR_LENGTH { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LENGTH; + +typedef struct _EFI_IFR_NOT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_NOT; + +typedef struct _EFI_IFR_BITWISE_NOT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_NOT; + +typedef struct _EFI_IFR_TO_BOOLEAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_BOOLEAN; + +#define EFI_IFR_STRING_UNSIGNED_DEC 0 +#define EFI_IFR_STRING_SIGNED_DEC 1 +#define EFI_IFR_STRING_LOWERCASE_HEX 2 +#define EFI_IFR_STRING_UPPERCASE_HEX 3 + +#define EFI_IFR_STRING_ASCII 0 +#define EFI_IFR_STRING_UNICODE 8 + +typedef struct _EFI_IFR_TO_STRING { + EFI_IFR_OP_HEADER Header; + UINT8 Format; +} EFI_IFR_TO_STRING; + +typedef struct _EFI_IFR_TO_UINT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_UINT; + +typedef struct _EFI_IFR_TO_UPPER { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_UPPER; + +typedef struct _EFI_IFR_TO_LOWER { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_LOWER; + +typedef struct _EFI_IFR_ADD { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ADD; + +typedef struct _EFI_IFR_AND { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_AND; + +typedef struct _EFI_IFR_BITWISE_AND { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_AND; + +typedef struct _EFI_IFR_BITWISE_OR { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_OR; + +typedef struct _EFI_IFR_CATENATE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_CATENATE; + +typedef struct _EFI_IFR_DIVIDE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DIVIDE; + +typedef struct _EFI_IFR_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_EQUAL; + +typedef struct _EFI_IFR_GREATER_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GREATER_EQUAL; + +typedef struct _EFI_IFR_GREATER_THAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GREATER_THAN; + +typedef struct _EFI_IFR_LESS_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LESS_EQUAL; + +typedef struct _EFI_IFR_LESS_THAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LESS_THAN; + +typedef struct _EFI_IFR_MATCH { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MATCH; + +typedef struct _EFI_IFR_MATCH2 { + EFI_IFR_OP_HEADER Header; + EFI_GUID SyntaxType; +} EFI_IFR_MATCH2; + +typedef struct _EFI_IFR_MULTIPLY { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MULTIPLY; + +typedef struct _EFI_IFR_MODULO { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MODULO; + +typedef struct _EFI_IFR_NOT_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_NOT_EQUAL; + +typedef struct _EFI_IFR_OR { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_OR; + +typedef struct _EFI_IFR_SHIFT_LEFT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SHIFT_LEFT; + +typedef struct _EFI_IFR_SHIFT_RIGHT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SHIFT_RIGHT; + +typedef struct _EFI_IFR_SUBTRACT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SUBTRACT; + +typedef struct _EFI_IFR_CONDITIONAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_CONDITIONAL; + +#define EFI_IFR_FF_CASE_SENSITIVE 0x00 +#define EFI_IFR_FF_CASE_INSENSITIVE 0x01 + +typedef struct _EFI_IFR_FIND { + EFI_IFR_OP_HEADER Header; + UINT8 Format; +} EFI_IFR_FIND; + +typedef struct _EFI_IFR_MID { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MID; + +typedef struct _EFI_IFR_TOKEN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TOKEN; + +#define EFI_IFR_FLAGS_FIRST_MATCHING 0x00 +#define EFI_IFR_FLAGS_FIRST_NON_MATCHING 0x01 + +typedef struct _EFI_IFR_SPAN { + EFI_IFR_OP_HEADER Header; + UINT8 Flags; +} EFI_IFR_SPAN; + +typedef struct _EFI_IFR_SECURITY { + /// + /// Standard opcode header, where Header.Op = EFI_IFR_SECURITY_OP. + /// + EFI_IFR_OP_HEADER Header; + /// + /// Security permission level. + /// + EFI_GUID Permissions; +} EFI_IFR_SECURITY; + +typedef struct _EFI_IFR_FORM_MAP_METHOD { + /// + /// The string identifier which provides the human-readable name of + /// the configuration method for this standards map form. + /// + EFI_STRING_ID MethodTitle; + /// + /// Identifier which uniquely specifies the configuration methods + /// associated with this standards map form. + /// + EFI_GUID MethodIdentifier; +} EFI_IFR_FORM_MAP_METHOD; + +typedef struct _EFI_IFR_FORM_MAP { + /// + /// The sequence that defines the type of opcode as well as the length + /// of the opcode being defined. Header.OpCode = EFI_IFR_FORM_MAP_OP. + /// + EFI_IFR_OP_HEADER Header; + /// + /// The unique identifier for this particular form. + /// + EFI_FORM_ID FormId; + /// + /// One or more configuration method's name and unique identifier. + /// + // EFI_IFR_FORM_MAP_METHOD Methods[]; +} EFI_IFR_FORM_MAP; + +typedef struct _EFI_IFR_SET { + /// + /// The sequence that defines the type of opcode as well as the length + /// of the opcode being defined. Header.OpCode = EFI_IFR_SET_OP. + /// + EFI_IFR_OP_HEADER Header; + /// + /// Specifies the identifier of a previously declared variable store to + /// use when storing the question's value. + /// + EFI_VARSTORE_ID VarStoreId; + union { + /// + /// A 16-bit Buffer Storage offset. + /// + EFI_STRING_ID VarName; + /// + /// A Name Value or EFI Variable name (VarName). + /// + UINT16 VarOffset; + } VarStoreInfo; + /// + /// Specifies the type used for storage. + /// + UINT8 VarStoreType; +} EFI_IFR_SET; + +typedef struct _EFI_IFR_GET { + /// + /// The sequence that defines the type of opcode as well as the length + /// of the opcode being defined. Header.OpCode = EFI_IFR_GET_OP. + /// + EFI_IFR_OP_HEADER Header; + /// + /// Specifies the identifier of a previously declared variable store to + /// use when retrieving the value. + /// + EFI_VARSTORE_ID VarStoreId; + union { + /// + /// A 16-bit Buffer Storage offset. + /// + EFI_STRING_ID VarName; + /// + /// A Name Value or EFI Variable name (VarName). + /// + UINT16 VarOffset; + } VarStoreInfo; + /// + /// Specifies the type used for storage. + /// + UINT8 VarStoreType; +} EFI_IFR_GET; + +typedef struct _EFI_IFR_READ { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_READ; + +typedef struct _EFI_IFR_WRITE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_WRITE; + +typedef struct _EFI_IFR_MAP { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MAP; +// +// Keyboard Package +// + +typedef enum { + EfiKeyLCtrl, + EfiKeyA0, + EfiKeyLAlt, + EfiKeySpaceBar, + EfiKeyA2, + EfiKeyA3, + EfiKeyA4, + EfiKeyRCtrl, + EfiKeyLeftArrow, + EfiKeyDownArrow, + EfiKeyRightArrow, + EfiKeyZero, + EfiKeyPeriod, + EfiKeyEnter, + EfiKeyLShift, + EfiKeyB0, + EfiKeyB1, + EfiKeyB2, + EfiKeyB3, + EfiKeyB4, + EfiKeyB5, + EfiKeyB6, + EfiKeyB7, + EfiKeyB8, + EfiKeyB9, + EfiKeyB10, + EfiKeyRshift, + EfiKeyUpArrow, + EfiKeyOne, + EfiKeyTwo, + EfiKeyThree, + EfiKeyCapsLock, + EfiKeyC1, + EfiKeyC2, + EfiKeyC3, + EfiKeyC4, + EfiKeyC5, + EfiKeyC6, + EfiKeyC7, + EfiKeyC8, + EfiKeyC9, + EfiKeyC10, + EfiKeyC11, + EfiKeyC12, + EfiKeyFour, + EfiKeyFive, + EfiKeySix, + EfiKeyPlus, + EfiKeyTab, + EfiKeyD1, + EfiKeyD2, + EfiKeyD3, + EfiKeyD4, + EfiKeyD5, + EfiKeyD6, + EfiKeyD7, + EfiKeyD8, + EfiKeyD9, + EfiKeyD10, + EfiKeyD11, + EfiKeyD12, + EfiKeyD13, + EfiKeyDel, + EfiKeyEnd, + EfiKeyPgDn, + EfiKeySeven, + EfiKeyEight, + EfiKeyNine, + EfiKeyE0, + EfiKeyE1, + EfiKeyE2, + EfiKeyE3, + EfiKeyE4, + EfiKeyE5, + EfiKeyE6, + EfiKeyE7, + EfiKeyE8, + EfiKeyE9, + EfiKeyE10, + EfiKeyE11, + EfiKeyE12, + EfiKeyBackSpace, + EfiKeyIns, + EfiKeyHome, + EfiKeyPgUp, + EfiKeyNLck, + EfiKeySlash, + EfiKeyAsterisk, + EfiKeyMinus, + EfiKeyEsc, + EfiKeyF1, + EfiKeyF2, + EfiKeyF3, + EfiKeyF4, + EfiKeyF5, + EfiKeyF6, + EfiKeyF7, + EfiKeyF8, + EfiKeyF9, + EfiKeyF10, + EfiKeyF11, + EfiKeyF12, + EfiKeyPrint, + EfiKeySLck, + EfiKeyPause +} EFI_KEY; + +typedef struct { + EFI_KEY Key; + CHAR16 Unicode; + CHAR16 ShiftedUnicode; + CHAR16 AltGrUnicode; + CHAR16 ShiftedAltGrUnicode; + UINT16 Modifier; + UINT16 AffectedAttribute; +} EFI_KEY_DESCRIPTOR; + +// +// A key which is affected by all the standard shift modifiers. +// Most keys would be expected to have this bit active. +// +#define EFI_AFFECTED_BY_STANDARD_SHIFT 0x0001 +// +// This key is affected by the caps lock so that if a keyboard driver +// would need to disambiguate between a key which had a "1" defined +// versus a "a" character. Having this bit turned on would tell +// the keyboard driver to use the appropriate shifted state or not. +// +#define EFI_AFFECTED_BY_CAPS_LOCK 0x0002 +// +// Similar to the case of CAPS lock, if this bit is active, the key +// is affected by the num lock being turned on. +// +#define EFI_AFFECTED_BY_NUM_LOCK 0x0004 + +typedef struct { + UINT16 LayoutLength; + EFI_GUID Guid; + UINT32 LayoutDescriptorStringOffset; + UINT8 DescriptorCount; + // EFI_KEY_DESCRIPTOR Descriptors[]; +} EFI_HII_KEYBOARD_LAYOUT; + +typedef struct { + EFI_HII_PACKAGE_HEADER Header; + UINT16 LayoutCount; + // EFI_HII_KEYBOARD_LAYOUT Layout[]; +} EFI_HII_KEYBOARD_PACKAGE_HDR; + +typedef struct { + CHAR16 Language[3]; + CHAR16 Space; + CHAR16 DescriptionString[1]; +} EFI_DESCRIPTION_STRING; + +typedef struct { + UINT16 DescriptionCount; + EFI_DESCRIPTION_STRING DescriptionString[1]; +} EFI_DESCRIPTION_STRING_BUNDLE; + +// +// Modifier values +// +#define EFI_NULL_MODIFIER 0x0000 +#define EFI_LEFT_CONTROL_MODIFIER 0x0001 +#define EFI_RIGHT_CONTROL_MODIFIER 0x0002 +#define EFI_LEFT_ALT_MODIFIER 0x0003 +#define EFI_RIGHT_ALT_MODIFIER 0x0004 +#define EFI_ALT_GR_MODIFIER 0x0005 +#define EFI_INSERT_MODIFIER 0x0006 +#define EFI_DELETE_MODIFIER 0x0007 +#define EFI_PAGE_DOWN_MODIFIER 0x0008 +#define EFI_PAGE_UP_MODIFIER 0x0009 +#define EFI_HOME_MODIFIER 0x000A +#define EFI_END_MODIFIER 0x000B +#define EFI_LEFT_SHIFT_MODIFIER 0x000C +#define EFI_RIGHT_SHIFT_MODIFIER 0x000D +#define EFI_CAPS_LOCK_MODIFIER 0x000E +#define EFI_NUM_LOCK _MODIFIER 0x000F +#define EFI_LEFT_ARROW_MODIFIER 0x0010 +#define EFI_RIGHT_ARROW_MODIFIER 0x0011 +#define EFI_DOWN_ARROW_MODIFIER 0x0012 +#define EFI_UP_ARROW_MODIFIER 0x0013 +#define EFI_NS_KEY_MODIFIER 0x0014 +#define EFI_NS_KEY_DEPENDENCY_MODIFIER 0x0015 +#define EFI_FUNCTION_KEY_ONE_MODIFIER 0x0016 +#define EFI_FUNCTION_KEY_TWO_MODIFIER 0x0017 +#define EFI_FUNCTION_KEY_THREE_MODIFIER 0x0018 +#define EFI_FUNCTION_KEY_FOUR_MODIFIER 0x0019 +#define EFI_FUNCTION_KEY_FIVE_MODIFIER 0x001A +#define EFI_FUNCTION_KEY_SIX_MODIFIER 0x001B +#define EFI_FUNCTION_KEY_SEVEN_MODIFIER 0x001C +#define EFI_FUNCTION_KEY_EIGHT_MODIFIER 0x001D +#define EFI_FUNCTION_KEY_NINE_MODIFIER 0x001E +#define EFI_FUNCTION_KEY_TEN_MODIFIER 0x001F +#define EFI_FUNCTION_KEY_ELEVEN_MODIFIER 0x0020 +#define EFI_FUNCTION_KEY_TWELVE_MODIFIER 0x0021 + +// +// Keys that have multiple control functions based on modifier +// settings are handled in the keyboard driver implementation. +// For instance PRINT_KEY might have a modifier held down and +// is still a nonprinting character, but might have an alternate +// control function like SYSREQUEST +// +#define EFI_PRINT_MODIFIER 0x0022 +#define EFI_SYS_REQUEST_MODIFIER 0x0023 +#define EFI_SCROLL_LOCK_MODIFIER 0x0024 +#define EFI_PAUSE_MODIFIER 0x0025 +#define EFI_BREAK_MODIFIER 0x0026 + +#pragma pack() + + + +// +// References to string tokens must use this macro to enable scanning for +// token usages. +// +// +// STRING_TOKEN is not defined in UEFI specification. But it is placed +// here for the easy access by C files and VFR source files. +// +#define STRING_TOKEN(t) t + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi.h new file mode 100644 index 0000000..718b393 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi.h @@ -0,0 +1,17 @@ +/** @file + This file contains the latest ACPI definitions that are + consumed by drivers that do not care about ACPI versions. + + Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2021, ARM Ltd. All rights reserved.
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ACPI_H_ +#define _ACPI_H_ + +#include + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi10.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi10.h new file mode 100644 index 0000000..fb920d8 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi10.h @@ -0,0 +1,666 @@ +/** @file + ACPI 1.0b definitions from the ACPI Specification, revision 1.0b + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2020, Arm Limited. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_1_0_H_ +#define _ACPI_1_0_H_ + +#include + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure. +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_COMMON_HEADER; + +#pragma pack(1) +/// +/// The common ACPI description table header. This structure prefaces most ACPI tables. +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT8 Revision; + UINT8 Checksum; + UINT8 OemId[6]; + UINT64 OemTableId; + UINT32 OemRevision; + UINT32 CreatorId; + UINT32 CreatorRevision; +} EFI_ACPI_DESCRIPTION_HEADER; +#pragma pack() + +// +// Define for Descriptor +// +#define ACPI_SMALL_ITEM_FLAG 0x00 +#define ACPI_LARGE_ITEM_FLAG 0x01 + +// +// Small Item Descriptor Name +// +#define ACPI_SMALL_IRQ_DESCRIPTOR_NAME 0x04 +#define ACPI_SMALL_DMA_DESCRIPTOR_NAME 0x05 +#define ACPI_SMALL_START_DEPENDENT_DESCRIPTOR_NAME 0x06 +#define ACPI_SMALL_END_DEPENDENT_DESCRIPTOR_NAME 0x07 +#define ACPI_SMALL_IO_PORT_DESCRIPTOR_NAME 0x08 +#define ACPI_SMALL_FIXED_IO_PORT_DESCRIPTOR_NAME 0x09 +#define ACPI_SMALL_VENDOR_DEFINED_DESCRIPTOR_NAME 0x0E +#define ACPI_SMALL_END_TAG_DESCRIPTOR_NAME 0x0F + +// +// Large Item Descriptor Name +// +#define ACPI_LARGE_24_BIT_MEMORY_RANGE_DESCRIPTOR_NAME 0x01 +#define ACPI_LARGE_VENDOR_DEFINED_DESCRIPTOR_NAME 0x04 +#define ACPI_LARGE_32_BIT_MEMORY_RANGE_DESCRIPTOR_NAME 0x05 +#define ACPI_LARGE_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR_NAME 0x06 +#define ACPI_LARGE_DWORD_ADDRESS_SPACE_DESCRIPTOR_NAME 0x07 +#define ACPI_LARGE_WORD_ADDRESS_SPACE_DESCRIPTOR_NAME 0x08 +#define ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME 0x09 +#define ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME 0x0A + +// +// Small Item Descriptor Value +// +#define ACPI_IRQ_NOFLAG_DESCRIPTOR 0x22 +#define ACPI_IRQ_DESCRIPTOR 0x23 +#define ACPI_DMA_DESCRIPTOR 0x2A +#define ACPI_START_DEPENDENT_DESCRIPTOR 0x30 +#define ACPI_START_DEPENDENT_EX_DESCRIPTOR 0x31 +#define ACPI_END_DEPENDENT_DESCRIPTOR 0x38 +#define ACPI_IO_PORT_DESCRIPTOR 0x47 +#define ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR 0x4B +#define ACPI_END_TAG_DESCRIPTOR 0x79 + +// +// Large Item Descriptor Value +// +#define ACPI_24_BIT_MEMORY_RANGE_DESCRIPTOR 0x81 +#define ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR 0x85 +#define ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR 0x86 +#define ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR 0x87 +#define ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR 0x88 +#define ACPI_EXTENDED_INTERRUPT_DESCRIPTOR 0x89 +#define ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR 0x8A +#define ACPI_ADDRESS_SPACE_DESCRIPTOR 0x8A + +// +// Resource Type +// +#define ACPI_ADDRESS_SPACE_TYPE_MEM 0x00 +#define ACPI_ADDRESS_SPACE_TYPE_IO 0x01 +#define ACPI_ADDRESS_SPACE_TYPE_BUS 0x02 + +/// +/// Power Management Timer frequency is fixed at 3.579545MHz. +/// +#define ACPI_TIMER_FREQUENCY 3579545 + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// The common definition of QWORD, DWORD, and WORD +/// Address Space Descriptors. +/// +typedef PACKED struct { + UINT8 Desc; + UINT16 Len; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT64 AddrSpaceGranularity; + UINT64 AddrRangeMin; + UINT64 AddrRangeMax; + UINT64 AddrTranslationOffset; + UINT64 AddrLen; +} EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR; + +typedef PACKED union { + UINT8 Byte; + PACKED struct { + UINT8 Length : 3; + UINT8 Name : 4; + UINT8 Type : 1; + } Bits; +} ACPI_SMALL_RESOURCE_HEADER; + +typedef PACKED struct { + PACKED union { + UINT8 Byte; + PACKED struct { + UINT8 Name : 7; + UINT8 Type : 1; + } Bits; + } Header; + UINT16 Length; +} ACPI_LARGE_RESOURCE_HEADER; + +/// +/// IRQ Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 Mask; +} EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR; + +/// +/// IRQ Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 Mask; + UINT8 Information; +} EFI_ACPI_IRQ_DESCRIPTOR; + +/// +/// DMA Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT8 ChannelMask; + UINT8 Information; +} EFI_ACPI_DMA_DESCRIPTOR; + +/// +/// I/O Port Descriptor +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT8 Information; + UINT16 BaseAddressMin; + UINT16 BaseAddressMax; + UINT8 Alignment; + UINT8 Length; +} EFI_ACPI_IO_PORT_DESCRIPTOR; + +/// +/// Fixed Location I/O Port Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 BaseAddress; + UINT8 Length; +} EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR; + +/// +/// 24-Bit Memory Range Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 Information; + UINT16 BaseAddressMin; + UINT16 BaseAddressMax; + UINT16 Alignment; + UINT16 Length; +} EFI_ACPI_24_BIT_MEMORY_RANGE_DESCRIPTOR; + +/// +/// 32-Bit Memory Range Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 Information; + UINT32 BaseAddressMin; + UINT32 BaseAddressMax; + UINT32 Alignment; + UINT32 Length; +} EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR; + +/// +/// Fixed 32-Bit Fixed Memory Range Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 Information; + UINT32 BaseAddress; + UINT32 Length; +} EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR; + +/// +/// QWORD Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT64 AddrSpaceGranularity; + UINT64 AddrRangeMin; + UINT64 AddrRangeMax; + UINT64 AddrTranslationOffset; + UINT64 AddrLen; +} EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR; + +/// +/// DWORD Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT32 AddrSpaceGranularity; + UINT32 AddrRangeMin; + UINT32 AddrRangeMax; + UINT32 AddrTranslationOffset; + UINT32 AddrLen; +} EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR; + +/// +/// WORD Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT16 AddrSpaceGranularity; + UINT16 AddrRangeMin; + UINT16 AddrRangeMax; + UINT16 AddrTranslationOffset; + UINT16 AddrLen; +} EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR; + +/// +/// Extended Interrupt Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 InterruptVectorFlags; + UINT8 InterruptTableLength; + UINT32 InterruptNumber[1]; +} EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR; + +#pragma pack() + +/// +/// The End tag identifies an end of resource data. +/// +typedef struct { + UINT8 Desc; + UINT8 Checksum; +} EFI_ACPI_END_TAG_DESCRIPTOR; + +// +// General use definitions +// +#define EFI_ACPI_RESERVED_BYTE 0x00 +#define EFI_ACPI_RESERVED_WORD 0x0000 +#define EFI_ACPI_RESERVED_DWORD 0x00000000 +#define EFI_ACPI_RESERVED_QWORD 0x0000000000000000 + +// +// Resource Type Specific Flags +// Ref ACPI specification 6.4.3.5.5 +// +// Bit [0] : Write Status, _RW +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_READ_WRITE (1 << 0) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_READ_ONLY (0 << 0) +// +// Bit [2:1] : Memory Attributes, _MEM +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE (0 << 1) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE (1 << 1) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_WRITE_COMBINING (2 << 1) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE (3 << 1) +// +// Bit [4:3] : Memory Attributes, _MTP +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_MEMORY (0 << 3) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_RESERVED (1 << 3) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_ACPI (2 << 3) +#define EFI_APCI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_NVS (3 << 3) +// +// Bit [5] : Memory to I/O Translation, _TTP +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_TYPE_TRANSLATION (1 << 5) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_TYPE_STATIC (0 << 5) + +// +// IRQ Information +// Ref ACPI specification 6.4.2.1 +// +#define EFI_ACPI_IRQ_SHARABLE_MASK 0x10 +#define EFI_ACPI_IRQ_SHARABLE 0x10 + +#define EFI_ACPI_IRQ_POLARITY_MASK 0x08 +#define EFI_ACPI_IRQ_HIGH_TRUE 0x00 +#define EFI_ACPI_IRQ_LOW_FALSE 0x08 + +#define EFI_ACPI_IRQ_MODE 0x01 +#define EFI_ACPI_IRQ_LEVEL_TRIGGERED 0x00 +#define EFI_ACPI_IRQ_EDGE_TRIGGERED 0x01 + +// +// DMA Information +// Ref ACPI specification 6.4.2.2 +// +#define EFI_ACPI_DMA_SPEED_TYPE_MASK 0x60 +#define EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY 0x00 +#define EFI_ACPI_DMA_SPEED_TYPE_A 0x20 +#define EFI_ACPI_DMA_SPEED_TYPE_B 0x40 +#define EFI_ACPI_DMA_SPEED_TYPE_F 0x60 + +#define EFI_ACPI_DMA_BUS_MASTER_MASK 0x04 +#define EFI_ACPI_DMA_BUS_MASTER 0x04 + +#define EFI_ACPI_DMA_TRANSFER_TYPE_MASK 0x03 +#define EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT 0x00 +#define EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT_AND_16_BIT 0x01 +#define EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT 0x02 + +// +// IO Information +// Ref ACPI specification 6.4.2.5 +// +#define EFI_ACPI_IO_DECODE_MASK 0x01 +#define EFI_ACPI_IO_DECODE_16_BIT 0x01 +#define EFI_ACPI_IO_DECODE_10_BIT 0x00 + +// +// Memory Information +// Ref ACPI specification 6.4.3.4 +// +#define EFI_ACPI_MEMORY_WRITE_STATUS_MASK 0x01 +#define EFI_ACPI_MEMORY_WRITABLE 0x01 +#define EFI_ACPI_MEMORY_NON_WRITABLE 0x00 + +// +// Interrupt Vector Flags definitions for Extended Interrupt Descriptor +// Ref ACPI specification 6.4.3.6 +// +#define EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK BIT0 +#define EFI_ACPI_EXTENDED_INTERRUPT_FLAG_MODE_MASK BIT1 +#define EFI_ACPI_EXTENDED_INTERRUPT_FLAG_POLARITY_MASK BIT2 +#define EFI_ACPI_EXTENDED_INTERRUPT_FLAG_SHARABLE_MASK BIT3 +#define EFI_ACPI_EXTENDED_INTERRUPT_FLAG_WAKE_CAPABLITY_MASK BIT4 + +// +// Ensure proper structure formats +// +#pragma pack(1) +// +// ACPI 1.0b table structures +// + +/// +/// Root System Description Pointer Structure. +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Reserved; + UINT32 RsdtAddress; +} EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 1.0b specification). +/// +#define EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT). +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 IntModel; + UINT8 Reserved1; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 Reserved2; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 Reserved3; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT8 Reserved4; + UINT8 Reserved5; + UINT8 Reserved6; + UINT32 Flags; +} EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 1.0b specification). +/// +#define EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x01 + +#define EFI_ACPI_1_0_INT_MODE_DUAL_PIC 0 +#define EFI_ACPI_1_0_INT_MODE_MULTIPLE_APIC 1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_1_0_WBINVD BIT0 +#define EFI_ACPI_1_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_1_0_PROC_C1 BIT2 +#define EFI_ACPI_1_0_P_LVL2_UP BIT3 +#define EFI_ACPI_1_0_PWR_BUTTON BIT4 +#define EFI_ACPI_1_0_SLP_BUTTON BIT5 +#define EFI_ACPI_1_0_FIX_RTC BIT6 +#define EFI_ACPI_1_0_RTC_S4 BIT7 +#define EFI_ACPI_1_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_1_0_DCK_CAP BIT9 + +/// +/// Firmware ACPI Control Structure. +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT8 Reserved[40]; +} EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// Firmware Control Structure Feature Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_1_0_S4BIOS_F BIT0 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform-specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 1.0b specification). +/// +#define EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_1_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x05 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_1_0_IO_APIC 0x01 +#define EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_1_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_1_0_LOCAL_APIC_NMI 0x04 + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_1_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 SystemVectorBase; +} EFI_ACPI_1_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterruptVector; + UINT16 Flags; +} EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Non-Maskable Interrupt Source Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterruptVector; +} EFI_ACPI_1_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicInti; +} EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_1_0_SMART_BATTERY_DESCRIPTION_TABLE; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer. +/// +#define EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table. +/// +#define EFI_ACPI_1_0_APIC_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "DSDT" Differentiated System Description Table. +/// +#define EFI_ACPI_1_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "FACS" Firmware ACPI Control Structure. +/// +#define EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FACP" Fixed ACPI Description Table. +/// +#define EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "PSDT" Persistent System Description Table. +/// +#define EFI_ACPI_1_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RSDT" Root System Description Table. +/// +#define EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table. +/// +#define EFI_ACPI_1_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SSDT" Secondary System Description Table. +/// +#define EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi20.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi20.h new file mode 100644 index 0000000..4e39452 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi20.h @@ -0,0 +1,539 @@ +/** @file + ACPI 2.0 definitions from the ACPI Specification, revision 2.0 + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_2_0_H_ +#define _ACPI_2_0_H_ + +#include + +// +// Define for Descriptor +// +#define ACPI_LARGE_GENERIC_REGISTER_DESCRIPTOR_NAME 0x02 + +#define ACPI_GENERIC_REGISTER_DESCRIPTOR 0x82 + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// Generic Register Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AddressSize; + UINT64 RegisterAddress; +} EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR; + +#pragma pack() + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 2.0 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 Reserved; + UINT64 Address; +} EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_2_0_SYSTEM_MEMORY 0 +#define EFI_ACPI_2_0_SYSTEM_IO 1 +#define EFI_ACPI_2_0_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_2_0_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_2_0_SMBUS 4 +#define EFI_ACPI_2_0_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// ACPI 2.0 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_2_0_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT8 Reserved2[3]; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; +} EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x03 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_2_0_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_2_0_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_2_0_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_2_0_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_2_0_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_2_0_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_2_0_PM_PROFILE_APPLIANCE_PC 6 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_2_0_LEGACY_DEVICES BIT0 +#define EFI_ACPI_2_0_8042 BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_2_0_WBINVD BIT0 +#define EFI_ACPI_2_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_2_0_PROC_C1 BIT2 +#define EFI_ACPI_2_0_P_LVL2_UP BIT3 +#define EFI_ACPI_2_0_PWR_BUTTON BIT4 +#define EFI_ACPI_2_0_SLP_BUTTON BIT5 +#define EFI_ACPI_2_0_FIX_RTC BIT6 +#define EFI_ACPI_2_0_RTC_S4 BIT7 +#define EFI_ACPI_2_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_2_0_DCK_CAP BIT9 +#define EFI_ACPI_2_0_RESET_REG_SUP BIT10 +#define EFI_ACPI_2_0_SEALED_CASE BIT11 +#define EFI_ACPI_2_0_HEADLESS BIT12 +#define EFI_ACPI_2_0_CPU_SW_SLP BIT13 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved[31]; +} EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x01 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_2_0_S4BIOS_F BIT0 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_2_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x09 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_2_0_IO_APIC 0x01 +#define EFI_ACPI_2_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_2_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_2_0_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_2_0_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_2_0_IO_SAPIC 0x06 +#define EFI_ACPI_2_0_PROCESSOR_LOCAL_SAPIC 0x07 +#define EFI_ACPI_2_0_PLATFORM_INTERRUPT_SOURCES 0x08 + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_2_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_2_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_2_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_2_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_2_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_2_0_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_2_0_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; +} EFI_ACPI_2_0_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 Reserved; +} EFI_ACPI_2_0_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_2_0_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_2_0_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_2_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 2.0 spec.) +/// +#define EFI_ACPI_2_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "SPIC" Multiple SAPIC Description Table +/// +/// BUGBUG: Don't know where this came from except SR870BN4 uses it. +/// #define EFI_ACPI_2_0_MULTIPLE_SAPIC_DESCRIPTION_TABLE_SIGNATURE 0x43495053 +/// +#define EFI_ACPI_2_0_MULTIPLE_SAPIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_2_0_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "DBGP" MS Bebug Port Spec +/// +#define EFI_ACPI_2_0_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_2_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_2_0_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_2_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_2_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_2_0_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SRAT" Static Resource Affinity Table +/// +#define EFI_ACPI_2_0_STATIC_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_2_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_2_0_SERVER_PLATFORM_MANAGEMENT_INTERFACE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_2_0_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi30.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi30.h new file mode 100644 index 0000000..24c565a --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi30.h @@ -0,0 +1,723 @@ +/** @file + ACPI 3.0 definitions from the ACPI Specification Revision 3.0b October 10, 2006 + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_3_0_H_ +#define _ACPI_3_0_H_ + +#include + +// +// Define for Descriptor +// +#define ACPI_LARGE_EXTENDED_ADDRESS_SPACE_DESCRIPTOR_NAME 0x0B + +#define ACPI_EXTENDED_ADDRESS_SPACE_DESCRIPTOR 0x8B + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// Extended Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT8 RevisionId; + UINT8 Reserved; + UINT64 AddrSpaceGranularity; + UINT64 AddrRangeMin; + UINT64 AddrRangeMax; + UINT64 AddrTranslationOffset; + UINT64 AddrLen; + UINT64 TypeSpecificAttribute; +} EFI_ACPI_EXTENDED_ADDRESS_SPACE_DESCRIPTOR; + +#pragma pack() + +// +// Memory Type Specific Flags +// +#define EFI_ACPI_MEMORY_TYPE_SPECIFIC_ATTRIBUTES_UC 0x0000000000000001 +#define EFI_ACPI_MEMORY_TYPE_SPECIFIC_ATTRIBUTES_WC 0x0000000000000002 +#define EFI_ACPI_MEMORY_TYPE_SPECIFIC_ATTRIBUTES_WT 0x0000000000000004 +#define EFI_ACPI_MEMORY_TYPE_SPECIFIC_ATTRIBUTES_WB 0x0000000000000008 +#define EFI_ACPI_MEMORY_TYPE_SPECIFIC_ATTRIBUTES_UCE 0x0000000000000010 +#define EFI_ACPI_MEMORY_TYPE_SPECIFIC_ATTRIBUTES_NV 0x0000000000008000 + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 3.0 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_3_0_SYSTEM_MEMORY 0 +#define EFI_ACPI_3_0_SYSTEM_IO 1 +#define EFI_ACPI_3_0_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_3_0_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_3_0_SMBUS 4 +#define EFI_ACPI_3_0_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_3_0_UNDEFINED 0 +#define EFI_ACPI_3_0_BYTE 1 +#define EFI_ACPI_3_0_WORD 2 +#define EFI_ACPI_3_0_DWORD 3 +#define EFI_ACPI_3_0_QWORD 4 + +// +// ACPI 3.0 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 3.0b spec.) +/// +#define EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 3.0b) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_3_0_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT8 Reserved2[3]; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; +} EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x04 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_3_0_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_3_0_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_3_0_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_3_0_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_3_0_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_3_0_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_3_0_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_3_0_PM_PROFILE_PERFORMANCE_SERVER 7 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_3_0_LEGACY_DEVICES BIT0 +#define EFI_ACPI_3_0_8042 BIT1 +#define EFI_ACPI_3_0_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_3_0_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_3_0_PCIE_ASPM_CONTROLS BIT4 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_3_0_WBINVD BIT0 +#define EFI_ACPI_3_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_3_0_PROC_C1 BIT2 +#define EFI_ACPI_3_0_P_LVL2_UP BIT3 +#define EFI_ACPI_3_0_PWR_BUTTON BIT4 +#define EFI_ACPI_3_0_SLP_BUTTON BIT5 +#define EFI_ACPI_3_0_FIX_RTC BIT6 +#define EFI_ACPI_3_0_RTC_S4 BIT7 +#define EFI_ACPI_3_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_3_0_DCK_CAP BIT9 +#define EFI_ACPI_3_0_RESET_REG_SUP BIT10 +#define EFI_ACPI_3_0_SEALED_CASE BIT11 +#define EFI_ACPI_3_0_HEADLESS BIT12 +#define EFI_ACPI_3_0_CPU_SW_SLP BIT13 +#define EFI_ACPI_3_0_PCI_EXP_WAK BIT14 +#define EFI_ACPI_3_0_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_3_0_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_3_0_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_3_0_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_3_0_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved[31]; +} EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x01 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_3_0_S4BIOS_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_3_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_3_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x09 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_3_0_IO_APIC 0x01 +#define EFI_ACPI_3_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_3_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_3_0_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_3_0_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_3_0_IO_SAPIC 0x06 +#define EFI_ACPI_3_0_LOCAL_SAPIC 0x07 +#define EFI_ACPI_3_0_PLATFORM_INTERRUPT_SOURCES 0x08 + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_3_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_3_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_3_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_3_0_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_3_0_POLARITY (3 << 0) +#define EFI_ACPI_3_0_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_3_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_3_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_3_0_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_3_0_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_3_0_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_3_0_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_3_0_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_3_0_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_3_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_3_0_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x02 + +// +// SRAT structure types. +// All other values between 0x02 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_3_0_MEMORY_AFFINITY 0x01 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT8 Reserved[4]; +} EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_3_0_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_3_0_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_3_0_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_3_0_MEMORY_NONVOLATILE (1 << 2) + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_3_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 3.0 spec.) +/// +#define EFI_ACPI_3_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_3_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_3_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_3_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_3_0_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_3_0_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_3_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_3_0_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_3_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_3_0_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_3_0_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_3_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_3_0_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_3_0_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_3_0_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WSPT" Windows Specific Properties Table +/// +#define EFI_ACPI_3_0_WINDOWS_SPECIFIC_PROPERTIES_TABLE_SIGNATURE SIGNATURE_32('W', 'S', 'P', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi40.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi40.h new file mode 100644 index 0000000..5e3493a --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi40.h @@ -0,0 +1,1304 @@ +/** @file + ACPI 4.0 definitions from the ACPI Specification Revision 4.0a April 5, 2010 + + Copyright (c) 2010 - 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_4_0_H_ +#define _ACPI_4_0_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 4.0 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_4_0_SYSTEM_MEMORY 0 +#define EFI_ACPI_4_0_SYSTEM_IO 1 +#define EFI_ACPI_4_0_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_4_0_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_4_0_SMBUS 4 +#define EFI_ACPI_4_0_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_4_0_UNDEFINED 0 +#define EFI_ACPI_4_0_BYTE 1 +#define EFI_ACPI_4_0_WORD 2 +#define EFI_ACPI_4_0_DWORD 3 +#define EFI_ACPI_4_0_QWORD 4 + +// +// ACPI 4.0 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 4.0b spec.) +/// +#define EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 4.0a) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_4_0_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT8 Reserved2[3]; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; +} EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x04 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_4_0_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_4_0_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_4_0_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_4_0_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_4_0_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_4_0_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_4_0_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_4_0_PM_PROFILE_PERFORMANCE_SERVER 7 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_4_0_LEGACY_DEVICES BIT0 +#define EFI_ACPI_4_0_8042 BIT1 +#define EFI_ACPI_4_0_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_4_0_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_4_0_PCIE_ASPM_CONTROLS BIT4 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_4_0_WBINVD BIT0 +#define EFI_ACPI_4_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_4_0_PROC_C1 BIT2 +#define EFI_ACPI_4_0_P_LVL2_UP BIT3 +#define EFI_ACPI_4_0_PWR_BUTTON BIT4 +#define EFI_ACPI_4_0_SLP_BUTTON BIT5 +#define EFI_ACPI_4_0_FIX_RTC BIT6 +#define EFI_ACPI_4_0_RTC_S4 BIT7 +#define EFI_ACPI_4_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_4_0_DCK_CAP BIT9 +#define EFI_ACPI_4_0_RESET_REG_SUP BIT10 +#define EFI_ACPI_4_0_SEALED_CASE BIT11 +#define EFI_ACPI_4_0_HEADLESS BIT12 +#define EFI_ACPI_4_0_CPU_SW_SLP BIT13 +#define EFI_ACPI_4_0_PCI_EXP_WAK BIT14 +#define EFI_ACPI_4_0_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_4_0_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_4_0_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_4_0_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_4_0_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_4_0_S4BIOS_F BIT0 +#define EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_4_0_OSPM_64BIT_WAKE__F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_4_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x03 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_4_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0B an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_4_0_IO_APIC 0x01 +#define EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_4_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_4_0_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_4_0_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_4_0_IO_SAPIC 0x06 +#define EFI_ACPI_4_0_LOCAL_SAPIC 0x07 +#define EFI_ACPI_4_0_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_4_0_LOCAL_X2APIC_NMI 0x0A + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_4_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_4_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_4_0_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_4_0_POLARITY (3 << 0) +#define EFI_ACPI_4_0_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_4_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_4_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_4_0_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_4_0_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_4_0_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_4_0_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_4_0_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_4_0_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_4_0_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_4_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_4_0_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x03 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_4_0_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_4_0_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_4_0_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_4_0_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_4_0_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_4_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_4_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_4_0_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_4_0_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_4_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_4_0_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_4_0_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_4_0_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_4_0_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_4_0_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_4_0_ERROR_SEVERITY_CORRECTABLE 0x00 +#define EFI_ACPI_4_0_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_4_0_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_4_0_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_4_0_ERROR_SEVERITY_NONE 0x03 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; +} EFI_ACPI_4_0_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0201 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_4_0_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_4_0_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_4_0_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_4_0_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_4_0_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_4_0_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_4_0_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_4_0_GENERIC_HARDWARE_ERROR 0x09 + +// +// Error Source structure flags. +// +#define EFI_ACPI_4_0_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_4_0_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_4_0_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_4_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_4_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_4_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_4_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_4_0_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_4_0_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_4_0_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_4_0_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_4_0_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_4_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_4_0_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_4_0_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_4_0_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_4_0_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_4_0_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_4_0_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_4_0_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_4_0_ERST_END_OPERATION 0x03 +#define EFI_ACPI_4_0_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_4_0_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_4_0_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_4_0_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_4_0_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_4_0_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_4_0_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_4_0_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_4_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_4_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_4_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_4_0_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_4_0_EINJ_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_4_0_EINJ_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_4_0_EINJ_STATUS_FAILED 0x03 +#define EFI_ACPI_4_0_EINJ_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_4_0_EINJ_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_4_0_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_4_0_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_4_0_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_4_0_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_4_0_ERST_NOOP 0x04 +#define EFI_ACPI_4_0_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_4_0_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_4_0_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_4_0_ERST_ADD 0x08 +#define EFI_ACPI_4_0_ERST_SUBTRACT 0x09 +#define EFI_ACPI_4_0_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_4_0_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_4_0_ERST_STALL 0x0C +#define EFI_ACPI_4_0_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_4_0_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_4_0_ERST_GOTO 0x0F +#define EFI_ACPI_4_0_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_4_0_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_4_0_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_4_0_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_4_0_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_4_0_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 4.0 spec.) +/// +#define EFI_ACPI_4_0_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_4_0_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_4_0_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_4_0_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_4_0_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_4_0_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_4_0_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_4_0_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_4_0_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_4_0_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_4_0_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_4_0_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_4_0_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_4_0_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_4_0_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_4_0_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_4_0_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_4_0_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_4_0_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_4_0_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_4_0_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_4_0_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_4_0_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_4_0_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_4_0_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_4_0_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_4_0_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_4_0_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_4_0_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_4_0_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_4_0_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_4_0_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_4_0_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_4_0_EINJ_TRIGGER_ACTION_TABLE; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_4_0_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_4_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_4_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_4_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_4_0_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_4_0_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_4_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_4_0_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_4_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_4_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_4_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_4_0_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_4_0_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_4_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_4_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_4_0_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_4_0_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_4_0_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_4_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_4_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_4_0_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_4_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_4_0_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_4_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_4_0_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_4_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Enlightenment Table +/// +#define EFI_ACPI_4_0_WINDOWS_ACPI_ENLIGHTENMENT_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_4_0_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_4_0_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi50.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi50.h new file mode 100644 index 0000000..e02daf6 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi50.h @@ -0,0 +1,2120 @@ +/** @file + ACPI 5.0 definitions from the ACPI Specification Revision 5.0a November 13, 2013. + + Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2011 - 2022, Intel Corporation. All rights reserved.
+ Copyright (c) 2020, ARM Ltd. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_5_0_H_ +#define _ACPI_5_0_H_ + +#include + +// +// Define for Descriptor +// +#define ACPI_SMALL_FIXED_DMA_DESCRIPTOR_NAME 0x0A +#define ACPI_LARGE_GPIO_CONNECTION_DESCRIPTOR_NAME 0x0C +#define ACPI_LARGE_GENERIC_SERIAL_BUS_CONNECTION_DESCRIPTOR_NAME 0x0E + +#define ACPI_FIXED_DMA_DESCRIPTOR 0x55 +#define ACPI_GPIO_CONNECTION_DESCRIPTOR 0x8C +#define ACPI_GENERIC_SERIAL_BUS_CONNECTION_DESCRIPTOR 0x8E + +#pragma pack(1) + +/// +/// Generic DMA Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 DmaRequestLine; + UINT16 DmaChannel; + UINT8 DmaTransferWidth; +} EFI_ACPI_FIXED_DMA_DESCRIPTOR; + +/// +/// GPIO Connection Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT8 ConnectionType; + UINT16 GeneralFlags; + UINT16 InterruptFlags; + UINT8 PinConfiguration; + UINT16 OutputDriveStrength; + UINT16 DebounceTimeout; + UINT16 PinTableOffset; + UINT8 ResourceSourceIndex; + UINT16 ResourceSourceNameOffset; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; +} EFI_ACPI_GPIO_CONNECTION_DESCRIPTOR; + +#define EFI_ACPI_GPIO_CONNECTION_TYPE_INTERRUPT 0x0 +#define EFI_ACPI_GPIO_CONNECTION_TYPE_IO 0x1 + +/// +/// Serial Bus Resource Descriptor (Generic) +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT8 ResourceSourceIndex; + UINT8 SerialBusType; + UINT8 GeneralFlags; + UINT16 TypeSpecificFlags; + UINT8 TypeSpecificRevisionId; + UINT16 TypeDataLength; + // Type specific data +} EFI_ACPI_SERIAL_BUS_RESOURCE_DESCRIPTOR; + +#define EFI_ACPI_SERIAL_BUS_RESOURCE_TYPE_I2C 0x1 +#define EFI_ACPI_SERIAL_BUS_RESOURCE_TYPE_SPI 0x2 +#define EFI_ACPI_SERIAL_BUS_RESOURCE_TYPE_UART 0x3 + +/// +/// Serial Bus Resource Descriptor (I2C) +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT8 ResourceSourceIndex; + UINT8 SerialBusType; + UINT8 GeneralFlags; + UINT16 TypeSpecificFlags; + UINT8 TypeSpecificRevisionId; + UINT16 TypeDataLength; + UINT32 ConnectionSpeed; + UINT16 SlaveAddress; +} EFI_ACPI_SERIAL_BUS_RESOURCE_I2C_DESCRIPTOR; + +/// +/// Serial Bus Resource Descriptor (SPI) +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT8 ResourceSourceIndex; + UINT8 SerialBusType; + UINT8 GeneralFlags; + UINT16 TypeSpecificFlags; + UINT8 TypeSpecificRevisionId; + UINT16 TypeDataLength; + UINT32 ConnectionSpeed; + UINT8 DataBitLength; + UINT8 Phase; + UINT8 Polarity; + UINT16 DeviceSelection; +} EFI_ACPI_SERIAL_BUS_RESOURCE_SPI_DESCRIPTOR; + +/// +/// Serial Bus Resource Descriptor (UART) +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT8 ResourceSourceIndex; + UINT8 SerialBusType; + UINT8 GeneralFlags; + UINT16 TypeSpecificFlags; + UINT8 TypeSpecificRevisionId; + UINT16 TypeDataLength; + UINT32 DefaultBaudRate; + UINT16 RxFIFO; + UINT16 TxFIFO; + UINT8 Parity; + UINT8 SerialLinesEnabled; +} EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR; + +#pragma pack() + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 5.0 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_5_0_SYSTEM_MEMORY 0 +#define EFI_ACPI_5_0_SYSTEM_IO 1 +#define EFI_ACPI_5_0_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_5_0_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_5_0_SMBUS 4 +#define EFI_ACPI_5_0_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_5_0_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_5_0_UNDEFINED 0 +#define EFI_ACPI_5_0_BYTE 1 +#define EFI_ACPI_5_0_WORD 2 +#define EFI_ACPI_5_0_DWORD 3 +#define EFI_ACPI_5_0_QWORD 4 + +// +// ACPI 5.0 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 5.0) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_5_0_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT8 Reserved2[3]; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; +} EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x05 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_5_0_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_5_0_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_5_0_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_5_0_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_5_0_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_5_0_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_5_0_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_5_0_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_5_0_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_0_LEGACY_DEVICES BIT0 +#define EFI_ACPI_5_0_8042 BIT1 +#define EFI_ACPI_5_0_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_5_0_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_5_0_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_5_0_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_0_WBINVD BIT0 +#define EFI_ACPI_5_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_5_0_PROC_C1 BIT2 +#define EFI_ACPI_5_0_P_LVL2_UP BIT3 +#define EFI_ACPI_5_0_PWR_BUTTON BIT4 +#define EFI_ACPI_5_0_SLP_BUTTON BIT5 +#define EFI_ACPI_5_0_FIX_RTC BIT6 +#define EFI_ACPI_5_0_RTC_S4 BIT7 +#define EFI_ACPI_5_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_5_0_DCK_CAP BIT9 +#define EFI_ACPI_5_0_RESET_REG_SUP BIT10 +#define EFI_ACPI_5_0_SEALED_CASE BIT11 +#define EFI_ACPI_5_0_HEADLESS BIT12 +#define EFI_ACPI_5_0_CPU_SW_SLP BIT13 +#define EFI_ACPI_5_0_PCI_EXP_WAK BIT14 +#define EFI_ACPI_5_0_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_5_0_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_5_0_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_5_0_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_5_0_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_5_0_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_5_0_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_0_S4BIOS_F BIT0 +#define EFI_ACPI_5_0_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_0_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_5_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_5_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x03 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0D and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_5_0_IO_APIC 0x01 +#define EFI_ACPI_5_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_5_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_5_0_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_5_0_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_5_0_IO_SAPIC 0x06 +#define EFI_ACPI_5_0_LOCAL_SAPIC 0x07 +#define EFI_ACPI_5_0_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_5_0_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_5_0_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_5_0_GIC 0x0B +#define EFI_ACPI_5_0_GICD 0x0C + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_5_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_5_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_5_0_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_0_POLARITY (3 << 0) +#define EFI_ACPI_5_0_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_5_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_5_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_5_0_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_5_0_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_5_0_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_5_0_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_0_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_5_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_5_0_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicId; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; +} EFI_ACPI_5_0_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_0_GIC_ENABLED BIT0 +#define EFI_ACPI_5_0_PERFORMANCE_INTERRUPT_MODEL BIT1 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT32 Reserved2; +} EFI_ACPI_5_0_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_5_0_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_5_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_5_0_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x03 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_5_0_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_5_0_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_0_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_5_0_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_5_0_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_5_0_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_5_0_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_5_0_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_5_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_5_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_5_0_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_5_0_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_5_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_5_0_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_5_0_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_5_0_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_5_0_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_5_0_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED 0x01 +#define EFI_ACPI_5_0_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED_AND_EXPOSED_TO_SOFTWARE 0x02 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_5_0_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_5_0_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_5_0_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_5_0_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_5_0_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_5_0_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_5_0_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_5_0_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_5_0_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_5_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_5_0_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_MEMORY_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// Common Memory Aggregator Device Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; +} EFI_ACPI_5_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Memory Aggregator Device Type +/// +#define EFI_ACPI_5_0_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_5_0_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_5_0_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_DIMM 0x2 + +/// +/// Socket Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_5_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_5_0_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE MemoryController[]; +} EFI_ACPI_5_0_PMMT_SOCKET_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// MemoryController Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_5_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 OptimalAccessUnit; + UINT16 OptimalAccessAlignment; + UINT16 Reserved; + UINT16 NumberOfProximityDomains; + // UINT32 ProximityDomain[NumberOfProximityDomains]; + // EFI_ACPI_5_0_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE PhysicalComponent[]; +} EFI_ACPI_5_0_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// DIMM Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_5_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 PhysicalComponentIdentifier; + UINT16 Reserved; + UINT32 SizeOfDimm; + UINT32 SmbiosHandle; +} EFI_ACPI_5_0_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:1] = Reserved (must be zero) + /// Bit [0] = Valid. A one indicates the boot image graphic is valid. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_5_0_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_5_0_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_5_0_BGRT_STATUS_DISPLAYED 0x01 +#define EFI_ACPI_5_0_BGRT_STATUS_INVALID EFI_ACPI_5_0_BGRT_STATUS_NOT_DISPLAYED +#define EFI_ACPI_5_0_BGRT_STATUS_VALID EFI_ACPI_5_0_BGRT_STATUS_DISPLAYED + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_5_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_5_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_5_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_5_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior to when the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_5_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_5_0_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_5_0_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 PhysicalAddress; + UINT32 GlobalFlags; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; +} EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Global Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_0_GTDT_GLOBAL_FLAG_MEMORY_MAPPED_BLOCK_PRESENT BIT0 +#define EFI_ACPI_5_0_GTDT_GLOBAL_FLAG_INTERRUPT_MODE BIT1 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_5_0_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_5_0_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_5_0_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_5_0_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_5_0_ERROR_SEVERITY_CORRECTABLE 0x00 +#define EFI_ACPI_5_0_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_5_0_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_5_0_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_5_0_ERROR_SEVERITY_NONE 0x03 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; +} EFI_ACPI_5_0_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0201 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_5_0_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_5_0_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_5_0_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_5_0_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_5_0_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_5_0_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_5_0_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_5_0_GENERIC_HARDWARE_ERROR 0x09 + +// +// Error Source structure flags. +// +#define EFI_ACPI_5_0_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_5_0_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_5_0_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_5_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_5_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_5_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_5_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_5_0_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_5_0_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_5_0_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_5_0_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_5_0_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_5_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_5_0_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_5_0_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_5_0_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_5_0_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_5_0_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_5_0_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_5_0_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_5_0_ERST_END_OPERATION 0x03 +#define EFI_ACPI_5_0_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_5_0_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_5_0_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_5_0_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_5_0_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_5_0_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_5_0_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_5_0_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_5_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_5_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_5_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_5_0_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_5_0_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_5_0_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_5_0_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_5_0_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_5_0_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_5_0_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_5_0_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_5_0_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_5_0_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_5_0_ERST_NOOP 0x04 +#define EFI_ACPI_5_0_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_5_0_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_5_0_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_5_0_ERST_ADD 0x08 +#define EFI_ACPI_5_0_ERST_SUBTRACT 0x09 +#define EFI_ACPI_5_0_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_5_0_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_5_0_ERST_STALL 0x0C +#define EFI_ACPI_5_0_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_5_0_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_5_0_ERST_GOTO 0x0F +#define EFI_ACPI_5_0_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_5_0_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_5_0_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_5_0_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_5_0_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_5_0_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_5_0_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_5_0_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_5_0_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_5_0_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_5_0_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_5_0_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_5_0_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_5_0_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_5_0_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_5_0_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_5_0_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_5_0_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_5_0_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_5_0_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_5_0_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_5_0_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_5_0_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_5_0_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_5_0_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_5_0_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_5_0_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_5_0_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_5_0_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_5_0_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_5_0_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_5_0_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_5_0_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_5_0_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_5_0_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_5_0_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_5_0_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_5_0_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_5_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 5.0 spec.) +/// +#define EFI_ACPI_5_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x01 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_5_0_PCCT_FLAGS_SCI_DOORBELL BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_5_0_PCCT_SUBSPACE_TYPE_GENERIC 0x00 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_5_0_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_5_0_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 GenerateSci : 1; +} EFI_ACPI_5_0_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 SciDoorbell : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_5_0_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_5_0_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_5_0_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_5_0_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_5_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_5_0_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_5_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_5_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_5_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_5_0_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_5_0_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_5_0_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_5_0_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_5_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_5_0_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_5_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_5_0_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_5_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_5_0_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_5_0_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_5_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_5_0_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_5_0_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_5_0_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_5_0_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_5_0_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_5_0_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_5_0_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_5_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_5_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_5_0_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_5_0_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_5_0_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_5_0_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_5_0_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_5_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_5_0_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_5_0_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_5_0_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') +#define EFI_ACPI_5_0_WINDOWS_ACPI_ENLIGHTENMENT_TABLE_SIGNATURE EFI_ACPI_5_0_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_5_0_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_5_0_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_5_0_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi51.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi51.h new file mode 100644 index 0000000..d225989 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi51.h @@ -0,0 +1,2145 @@ +/** @file + ACPI 5.1 definitions from the ACPI Specification Revision 5.1 Errata B January, 2016. + + Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2014 - 2022, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2020, ARM Ltd. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_5_1_H_ +#define _ACPI_5_1_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 5.1 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_5_1_SYSTEM_MEMORY 0 +#define EFI_ACPI_5_1_SYSTEM_IO 1 +#define EFI_ACPI_5_1_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_5_1_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_5_1_SMBUS 4 +#define EFI_ACPI_5_1_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_5_1_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_5_1_UNDEFINED 0 +#define EFI_ACPI_5_1_BYTE 1 +#define EFI_ACPI_5_1_WORD 2 +#define EFI_ACPI_5_1_DWORD 3 +#define EFI_ACPI_5_1_QWORD 4 + +// +// ACPI 5.1 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_5_1_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 5.1) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_5_1_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; +} EFI_ACPI_5_1_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x05 +#define EFI_ACPI_5_1_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x01 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_5_1_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_5_1_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_5_1_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_5_1_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_5_1_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_5_1_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_5_1_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_5_1_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_5_1_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_1_LEGACY_DEVICES BIT0 +#define EFI_ACPI_5_1_8042 BIT1 +#define EFI_ACPI_5_1_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_5_1_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_5_1_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_5_1_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_1_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_5_1_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_1_WBINVD BIT0 +#define EFI_ACPI_5_1_WBINVD_FLUSH BIT1 +#define EFI_ACPI_5_1_PROC_C1 BIT2 +#define EFI_ACPI_5_1_P_LVL2_UP BIT3 +#define EFI_ACPI_5_1_PWR_BUTTON BIT4 +#define EFI_ACPI_5_1_SLP_BUTTON BIT5 +#define EFI_ACPI_5_1_FIX_RTC BIT6 +#define EFI_ACPI_5_1_RTC_S4 BIT7 +#define EFI_ACPI_5_1_TMR_VAL_EXT BIT8 +#define EFI_ACPI_5_1_DCK_CAP BIT9 +#define EFI_ACPI_5_1_RESET_REG_SUP BIT10 +#define EFI_ACPI_5_1_SEALED_CASE BIT11 +#define EFI_ACPI_5_1_HEADLESS BIT12 +#define EFI_ACPI_5_1_CPU_SW_SLP BIT13 +#define EFI_ACPI_5_1_PCI_EXP_WAK BIT14 +#define EFI_ACPI_5_1_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_5_1_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_5_1_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_5_1_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_5_1_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_5_1_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_5_1_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_5_1_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_1_S4BIOS_F BIT0 +#define EFI_ACPI_5_1_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_1_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_5_1_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_5_1_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x03 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_1_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0D and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_5_1_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_5_1_IO_APIC 0x01 +#define EFI_ACPI_5_1_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_5_1_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_5_1_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_5_1_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_5_1_IO_SAPIC 0x06 +#define EFI_ACPI_5_1_LOCAL_SAPIC 0x07 +#define EFI_ACPI_5_1_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_5_1_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_5_1_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_5_1_GIC 0x0B +#define EFI_ACPI_5_1_GICD 0x0C +#define EFI_ACPI_5_1_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_5_1_GICR 0x0E + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_5_1_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_5_1_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_5_1_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_5_1_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_5_1_POLARITY (3 << 0) +#define EFI_ACPI_5_1_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_5_1_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_5_1_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_5_1_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_5_1_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_5_1_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_5_1_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_5_1_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_5_1_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_5_1_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; +} EFI_ACPI_5_1_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_GIC_ENABLED BIT0 +#define EFI_ACPI_5_1_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_5_1_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_5_1_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_5_1_GIC_V1 0x01 +#define EFI_ACPI_5_1_GIC_V2 0x02 +#define EFI_ACPI_5_1_GIC_V3 0x03 +#define EFI_ACPI_5_1_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_5_1_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_5_1_GICR_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_5_1_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_5_1_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_5_1_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x04 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_5_1_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_5_1_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_5_1_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_5_1_GICC_AFFINITY 0x03 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_5_1_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_5_1_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_5_1_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_5_1_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_5_1_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_5_1_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_5_1_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_GICC_ENABLED (1 << 0) + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_5_1_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_5_1_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_5_1_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_5_1_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_5_1_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_5_1_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_5_1_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_5_1_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_5_1_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_5_1_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED 0x01 +#define EFI_ACPI_5_1_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED_AND_EXPOSED_TO_SOFTWARE 0x02 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_5_1_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_5_1_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_5_1_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_5_1_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_5_1_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_5_1_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_5_1_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_5_1_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_5_1_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_5_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_5_1_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_MEMORY_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// Common Memory Aggregator Device Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; +} EFI_ACPI_5_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Memory Aggregator Device Type +/// +#define EFI_ACPI_5_1_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_5_1_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_5_1_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_DIMM 0x2 + +/// +/// Socket Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_5_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_5_1_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE MemoryController[]; +} EFI_ACPI_5_1_PMMT_SOCKET_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// MemoryController Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_5_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 OptimalAccessUnit; + UINT16 OptimalAccessAlignment; + UINT16 Reserved; + UINT16 NumberOfProximityDomains; + // UINT32 ProximityDomain[NumberOfProximityDomains]; + // EFI_ACPI_5_1_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE PhysicalComponent[]; +} EFI_ACPI_5_1_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// DIMM Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_5_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 PhysicalComponentIdentifier; + UINT16 Reserved; + UINT32 SizeOfDimm; + UINT32 SmbiosHandle; +} EFI_ACPI_5_1_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:1] = Reserved (must be zero) + /// Bit [0] = Valid. A one indicates the boot image graphic is valid. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_5_1_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_5_1_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_5_1_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_5_1_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_5_1_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_5_1_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_5_1_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_5_1_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_5_1_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_5_1_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_5_1_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_5_1_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_5_1_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_5_1_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_5_1_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_5_1_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_5_1_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_5_1_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_5_1_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_5_1_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior to when the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_5_1_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_5_1_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_5_1_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_5_1_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_5_1_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_5_1_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_5_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_5_1_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_5_1_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; +} EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_5_1_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_5_1_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_5_1_GTDT_GT_BLOCK 0 +#define EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_5_1_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_5_1_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_5_1_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_5_1_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// SBSA Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// SBSA Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_5_1_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_5_1_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_5_1_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_5_1_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_5_1_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_5_1_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_5_1_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_5_1_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_5_1_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; +} EFI_ACPI_5_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0201 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_5_1_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_5_1_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_5_1_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_5_1_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_5_1_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_5_1_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_5_1_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_5_1_GENERIC_HARDWARE_ERROR 0x09 + +// +// Error Source structure flags. +// +#define EFI_ACPI_5_1_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_5_1_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_5_1_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_5_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_5_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_5_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_5_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_5_1_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_5_1_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_5_1_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_5_1_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_5_1_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_5_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_5_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_5_1_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_5_1_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_5_1_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_5_1_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_5_1_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_5_1_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_5_1_ERST_END_OPERATION 0x03 +#define EFI_ACPI_5_1_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_5_1_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_5_1_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_5_1_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_5_1_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_5_1_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_5_1_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_5_1_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_5_1_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_5_1_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_5_1_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_5_1_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_5_1_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_5_1_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_5_1_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_5_1_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_5_1_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_5_1_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_5_1_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_5_1_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_5_1_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_5_1_ERST_NOOP 0x04 +#define EFI_ACPI_5_1_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_5_1_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_5_1_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_5_1_ERST_ADD 0x08 +#define EFI_ACPI_5_1_ERST_SUBTRACT 0x09 +#define EFI_ACPI_5_1_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_5_1_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_5_1_ERST_STALL 0x0C +#define EFI_ACPI_5_1_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_5_1_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_5_1_ERST_GOTO 0x0F +#define EFI_ACPI_5_1_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_5_1_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_5_1_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_5_1_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_5_1_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_5_1_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_5_1_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_5_1_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_5_1_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_5_1_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_5_1_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_5_1_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_5_1_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_5_1_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_5_1_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_5_1_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_5_1_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_5_1_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_5_1_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_5_1_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_5_1_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_5_1_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_5_1_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_5_1_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_5_1_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_5_1_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_5_1_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_5_1_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_5_1_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_5_1_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_5_1_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_5_1_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_5_1_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_5_1_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_5_1_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_5_1_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_5_1_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_5_1_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_5_1_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 5.1 spec.) +/// +#define EFI_ACPI_5_1_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x01 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_5_1_PCCT_FLAGS_SCI_DOORBELL BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_5_1_PCCT_SUBSPACE_TYPE_GENERIC 0x00 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_5_1_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_5_1_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_5_1_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 GenerateSci : 1; +} EFI_ACPI_5_1_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 SciDoorbell : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_5_1_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_5_1_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_5_1_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_5_1_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_5_1_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_5_1_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_5_1_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_5_1_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_5_1_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_5_1_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_5_1_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_5_1_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_5_1_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_5_1_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_5_1_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_5_1_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_5_1_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_5_1_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_5_1_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_5_1_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_5_1_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_5_1_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_5_1_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_5_1_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_5_1_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_5_1_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_5_1_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_5_1_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_5_1_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_5_1_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_5_1_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_5_1_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_5_1_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_5_1_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_5_1_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_5_1_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_5_1_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_5_1_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_5_1_IO_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_5_1_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_5_1_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_5_1_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_5_1_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_5_1_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_5_1_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_5_1_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_5_1_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_5_1_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_5_1_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_5_1_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_5_1_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_5_1_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_5_1_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi60.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi60.h new file mode 100644 index 0000000..c3a5a22 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi60.h @@ -0,0 +1,2398 @@ +/** @file + ACPI 6.0 definitions from the ACPI Specification Revision 6.0 Errata A January, 2016. + + Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2020, ARM Ltd. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_6_0_H_ +#define _ACPI_6_0_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 6.0 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_6_0_SYSTEM_MEMORY 0 +#define EFI_ACPI_6_0_SYSTEM_IO 1 +#define EFI_ACPI_6_0_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_6_0_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_6_0_SMBUS 4 +#define EFI_ACPI_6_0_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_6_0_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_6_0_UNDEFINED 0 +#define EFI_ACPI_6_0_BYTE 1 +#define EFI_ACPI_6_0_WORD 2 +#define EFI_ACPI_6_0_DWORD 3 +#define EFI_ACPI_6_0_QWORD 4 + +// +// ACPI 6.0 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_6_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 6.0) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_0_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; + UINT64 HypervisorVendorIdentity; +} EFI_ACPI_6_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x06 +#define EFI_ACPI_6_0_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x00 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_6_0_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_6_0_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_6_0_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_6_0_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_6_0_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_6_0_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_6_0_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_6_0_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_6_0_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_0_LEGACY_DEVICES BIT0 +#define EFI_ACPI_6_0_8042 BIT1 +#define EFI_ACPI_6_0_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_6_0_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_6_0_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_6_0_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_0_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_6_0_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_0_WBINVD BIT0 +#define EFI_ACPI_6_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_6_0_PROC_C1 BIT2 +#define EFI_ACPI_6_0_P_LVL2_UP BIT3 +#define EFI_ACPI_6_0_PWR_BUTTON BIT4 +#define EFI_ACPI_6_0_SLP_BUTTON BIT5 +#define EFI_ACPI_6_0_FIX_RTC BIT6 +#define EFI_ACPI_6_0_RTC_S4 BIT7 +#define EFI_ACPI_6_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_6_0_DCK_CAP BIT9 +#define EFI_ACPI_6_0_RESET_REG_SUP BIT10 +#define EFI_ACPI_6_0_SEALED_CASE BIT11 +#define EFI_ACPI_6_0_HEADLESS BIT12 +#define EFI_ACPI_6_0_CPU_SW_SLP BIT13 +#define EFI_ACPI_6_0_PCI_EXP_WAK BIT14 +#define EFI_ACPI_6_0_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_6_0_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_6_0_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_6_0_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_6_0_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_6_0_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_6_0_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_6_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_0_S4BIOS_F BIT0 +#define EFI_ACPI_6_0_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_0_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_6_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_6_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 6.0 Errata A spec.) +/// +#define EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x04 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0D and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_6_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_6_0_IO_APIC 0x01 +#define EFI_ACPI_6_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_6_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_6_0_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_6_0_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_6_0_IO_SAPIC 0x06 +#define EFI_ACPI_6_0_LOCAL_SAPIC 0x07 +#define EFI_ACPI_6_0_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_6_0_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_6_0_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_6_0_GIC 0x0B +#define EFI_ACPI_6_0_GICD 0x0C +#define EFI_ACPI_6_0_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_6_0_GICR 0x0E +#define EFI_ACPI_6_0_GIC_ITS 0x0F + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_6_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_6_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_6_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_6_0_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_0_POLARITY (3 << 0) +#define EFI_ACPI_6_0_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_6_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_6_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_6_0_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_6_0_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_6_0_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_6_0_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_0_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_6_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_6_0_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; + UINT8 ProcessorPowerEfficiencyClass; + UINT8 Reserved2[3]; +} EFI_ACPI_6_0_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_GIC_ENABLED BIT0 +#define EFI_ACPI_6_0_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_6_0_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_6_0_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_6_0_GIC_V1 0x01 +#define EFI_ACPI_6_0_GIC_V2 0x02 +#define EFI_ACPI_6_0_GIC_V3 0x03 +#define EFI_ACPI_6_0_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_6_0_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_6_0_GICR_STRUCTURE; + +/// +/// GIC Interrupt Translation Service Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicItsId; + UINT64 PhysicalBaseAddress; + UINT32 Reserved2; +} EFI_ACPI_6_0_GIC_ITS_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_6_0_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_6_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_6_0_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x04 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_6_0_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_6_0_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_6_0_GICC_AFFINITY 0x03 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_6_0_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_6_0_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_6_0_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_6_0_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_6_0_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_6_0_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_6_0_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_GICC_ENABLED (1 << 0) + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_6_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_6_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_6_0_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_6_0_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_6_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_6_0_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_6_0_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_6_0_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_6_0_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_6_0_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED 0x01 +#define EFI_ACPI_6_0_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED_AND_EXPOSED_TO_SOFTWARE 0x02 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_6_0_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_6_0_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_6_0_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_6_0_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_6_0_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_6_0_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_6_0_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_6_0_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_0_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_0_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_0_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_MEMORY_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// Common Memory Aggregator Device Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; +} EFI_ACPI_6_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Memory Aggregator Device Type +/// +#define EFI_ACPI_6_0_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_6_0_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_6_0_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_DIMM 0x2 + +/// +/// Socket Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_0_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE MemoryController[]; +} EFI_ACPI_6_0_PMMT_SOCKET_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// MemoryController Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 OptimalAccessUnit; + UINT16 OptimalAccessAlignment; + UINT16 Reserved; + UINT16 NumberOfProximityDomains; + // UINT32 ProximityDomain[NumberOfProximityDomains]; + // EFI_ACPI_6_0_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE PhysicalComponent[]; +} EFI_ACPI_6_0_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// DIMM Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_0_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 PhysicalComponentIdentifier; + UINT16 Reserved; + UINT32 SizeOfDimm; + UINT32 SmbiosHandle; +} EFI_ACPI_6_0_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:1] = Reserved (must be zero) + /// Bit [0] = Valid. A one indicates the boot image graphic is valid. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_6_0_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_6_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_6_0_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_6_0_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_6_0_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_6_0_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_6_0_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_6_0_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_6_0_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_6_0_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_6_0_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_6_0_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_6_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_6_0_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_6_0_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_6_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_6_0_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_0_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_6_0_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_6_0_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior to when the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_6_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_6_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_0_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_6_0_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_0_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_6_0_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_6_0_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_6_0_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_0_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; +} EFI_ACPI_6_0_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_0_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_6_0_GTDT_GT_BLOCK 0 +#define EFI_ACPI_6_0_GTDT_SBSA_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_6_0_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_6_0_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_0_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_6_0_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// SBSA Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_6_0_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// SBSA Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_0_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_0_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_0_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +// +// NVDIMM Firmware Interface Table definition. +// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_0_NVDIMM_FIRMWARE_INTERFACE_TABLE; + +// +// NFIT Version (as defined in ACPI 6.0 spec.) +// +#define EFI_ACPI_6_0_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION 0x1 + +// +// Definition for NFIT Table Structure Types +// +#define EFI_ACPI_6_0_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE 0 +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_TO_SYSTEM_ADDRESS_RANGE_MAP_STRUCTURE_TYPE 1 +#define EFI_ACPI_6_0_NFIT_INTERLEAVE_STRUCTURE_TYPE 2 +#define EFI_ACPI_6_0_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE_TYPE 3 +#define EFI_ACPI_6_0_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE_TYPE 4 +#define EFI_ACPI_6_0_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE_TYPE 5 +#define EFI_ACPI_6_0_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE_TYPE 6 + +// +// Definition for NFIT Structure Header +// +typedef struct { + UINT16 Type; + UINT16 Length; +} EFI_ACPI_6_0_NFIT_STRUCTURE_HEADER; + +// +// Definition for System Physical Address Range Structure +// +#define EFI_ACPI_6_0_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_CONTROL_REGION_FOR_MANAGEMENT BIT0 +#define EFI_ACPI_6_0_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_PROXIMITY_DOMAIN_VALID BIT1 +#define EFI_ACPI_6_0_NFIT_GUID_VOLATILE_MEMORY_REGION { 0x7305944F, 0xFDDA, 0x44E3, { 0xB1, 0x6C, 0x3F, 0x22, 0xD2, 0x52, 0xE5, 0xD0 }} +#define EFI_ACPI_6_0_NFIT_GUID_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_REGION { 0x66F0D379, 0xB4F3, 0x4074, { 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB }} +#define EFI_ACPI_6_0_NFIT_GUID_NVDIMM_CONTROL_REGION { 0x92F701F6, 0x13B4, 0x405D, { 0x91, 0x0B, 0x29, 0x93, 0x67, 0xE8, 0x23, 0x4C }} +#define EFI_ACPI_6_0_NFIT_GUID_NVDIMM_BLOCK_DATA_WINDOW_REGION { 0x91AF0530, 0x5D86, 0x470E, { 0xA6, 0xB0, 0x0A, 0x2D, 0xB9, 0x40, 0x82, 0x49 }} +#define EFI_ACPI_6_0_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_VOLATILE { 0x77AB535A, 0x45FC, 0x624B, { 0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }} +#define EFI_ACPI_6_0_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_VOLATILE { 0x3D5ABD30, 0x4175, 0x87CE, { 0x6D, 0x64, 0xD2, 0xAD, 0xE5, 0x23, 0xC4, 0xBB }} +#define EFI_ACPI_6_0_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_PERSISTENT { 0x5CEA02C9, 0x4D07, 0x69D3, { 0x26, 0x9F ,0x44, 0x96, 0xFB, 0xE0, 0x96, 0xF9 }} +#define EFI_ACPI_6_0_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_PERSISTENT { 0x08018188, 0x42CD, 0xBB48, { 0x10, 0x0F, 0x53, 0x87, 0xD5, 0x3D, 0xED, 0x3D }} +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 SPARangeStructureIndex; + UINT16 Flags; + UINT32 Reserved_8; + UINT32 ProximityDomain; + GUID AddressRangeTypeGUID; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; + UINT64 AddressRangeMemoryMappingAttribute; +} EFI_ACPI_6_0_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE; + +// +// Definition for Memory Device to System Physical Address Range Mapping Structure +// +typedef struct { + UINT32 DIMMNumber : 4; + UINT32 MemoryChannelNumber : 4; + UINT32 MemoryControllerID : 4; + UINT32 SocketID : 4; + UINT32 NodeControllerID : 12; + UINT32 Reserved_28 : 4; +} EFI_ACPI_6_0_NFIT_DEVICE_HANDLE; + +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_STATE_FLAGS_PREVIOUS_SAVE_FAIL BIT0 +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_STATE_FLAGS_LAST_RESTORE_FAIL BIT1 +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_STATE_FLAGS_PLATFORM_FLUSH_FAIL BIT2 +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_STATE_FLAGS_NOT_ARMED_PRIOR_TO_OSPM_HAND_OFF BIT3 +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_STATE_FLAGS_SMART_HEALTH_EVENTS_PRIOR_OSPM_HAND_OFF BIT4 +#define EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_ENABLED_TO_NOTIFY_OSPM_ON_SMART_HEALTH_EVENTS BIT5 +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_0_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 MemoryDevicePhysicalID; + UINT16 MemoryDeviceRegionID; + UINT16 SPARangeStructureIndex; + UINT16 NVDIMMControlRegionStructureIndex; + UINT64 MemoryDeviceRegionSize; + UINT64 RegionOffset; + UINT64 MemoryDevicePhysicalAddressRegionBase; + UINT16 InterleaveStructureIndex; + UINT16 InterleaveWays; + UINT16 MemoryDeviceStateFlags; + UINT16 Reserved_46; +} EFI_ACPI_6_0_NFIT_MEMORY_DEVICE_TO_SYSTEM_ADDRESS_RANGE_MAP_STRUCTURE; + +// +// Definition for Interleave Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 InterleaveStructureIndex; + UINT16 Reserved_6; + UINT32 NumberOfLines; + UINT32 LineSize; + // UINT32 LineOffset[NumberOfLines]; +} EFI_ACPI_6_0_NFIT_INTERLEAVE_STRUCTURE; + +// +// Definition for SMBIOS Management Information Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT32 Reserved_4; + // UINT8 Data[]; +} EFI_ACPI_6_0_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE; + +// +// Definition for NVDIMM Control Region Structure +// +#define EFI_ACPI_6_0_NFIT_NVDIMM_CONTROL_REGION_FLAGS_BLOCK_DATA_WINDOWS_BUFFERED BIT0 +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT16 SubsystemVendorID; + UINT16 SubsystemDeviceID; + UINT16 SubsystemRevisionID; + UINT8 Reserved_18[6]; + UINT32 SerialNumber; + UINT16 RegionFormatInterfaceCode; + UINT16 NumberOfBlockControlWindows; + UINT64 SizeOfBlockControlWindow; + UINT64 CommandRegisterOffsetInBlockControlWindow; + UINT64 SizeOfCommandRegisterInBlockControlWindows; + UINT64 StatusRegisterOffsetInBlockControlWindow; + UINT64 SizeOfStatusRegisterInBlockControlWindows; + UINT16 NVDIMMControlRegionFlag; + UINT8 Reserved_74[6]; +} EFI_ACPI_6_0_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE; + +// +// Definition for NVDIMM Block Data Window Region Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 NumberOfBlockDataWindows; + UINT64 BlockDataWindowStartOffset; + UINT64 SizeOfBlockDataWindow; + UINT64 BlockAccessibleMemoryCapacity; + UINT64 BeginningAddressOfFirstBlockInBlockAccessibleMemory; +} EFI_ACPI_6_0_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE; + +// +// Definition for Flush Hint Address Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_0_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NumberOfFlushHintAddresses; + UINT8 Reserved_10[6]; + // UINT64 FlushHintAddress[NumberOfFlushHintAddresses]; +} EFI_ACPI_6_0_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_6_0_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_6_0_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_6_0_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_0_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_6_0_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_6_0_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_6_0_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_6_0_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_6_0_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; +} EFI_ACPI_6_0_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0201 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_6_0_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_6_0_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_6_0_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_6_0_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_6_0_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_6_0_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_6_0_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_6_0_GENERIC_HARDWARE_ERROR 0x09 + +// +// Error Source structure flags. +// +#define EFI_ACPI_6_0_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_6_0_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_6_0_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_6_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_6_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_6_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_6_0_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_CMCI 0x05 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_MCE 0x06 +#define EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_GPIO_SIGNAL 0x07 + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_0_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_6_0_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_6_0_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_0_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_0_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_0_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_6_0_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_6_0_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_0_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_6_0_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_6_0_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_6_0_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_6_0_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_6_0_ERST_END_OPERATION 0x03 +#define EFI_ACPI_6_0_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_6_0_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_0_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_0_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_0_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_6_0_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_6_0_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_6_0_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_6_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_6_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_6_0_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_6_0_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_0_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_6_0_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_6_0_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_6_0_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_6_0_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_6_0_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_6_0_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_0_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_0_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_0_ERST_NOOP 0x04 +#define EFI_ACPI_6_0_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_6_0_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_6_0_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_6_0_ERST_ADD 0x08 +#define EFI_ACPI_6_0_ERST_SUBTRACT 0x09 +#define EFI_ACPI_6_0_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_6_0_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_6_0_ERST_STALL 0x0C +#define EFI_ACPI_6_0_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_6_0_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_6_0_ERST_GOTO 0x0F +#define EFI_ACPI_6_0_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_6_0_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_6_0_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_6_0_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_0_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_6_0_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_6_0_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_6_0_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_6_0_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_6_0_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_6_0_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_6_0_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_0_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_0_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_0_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_6_0_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_0_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_6_0_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_6_0_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_6_0_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_6_0_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_6_0_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_6_0_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_6_0_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_6_0_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_6_0_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_6_0_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_6_0_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_6_0_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_6_0_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_6_0_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_6_0_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_0_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_0_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_0_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_6_0_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_0_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_6_0_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_6_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 6.0 spec.) +/// +#define EFI_ACPI_6_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x01 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_6_0_PCCT_FLAGS_SCI_DOORBELL BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_6_0_PCCT_SUBSPACE_TYPE_GENERIC 0x00 +#define EFI_ACPI_6_0_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS 0x01 +#define EFI_ACPI_6_0_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS 0x02 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_6_0_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_0_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 GenerateSci : 1; +} EFI_ACPI_6_0_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 SciDoorbell : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_6_0_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_6_0_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_6_0_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_6_0_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +#define EFI_ACPI_6_0_PCCT_SUBSPACE_DOORBELL_INTERRUPT_FLAGS_POLARITY BIT0 +#define EFI_ACPI_6_0_PCCT_SUBSPACE_DOORBELL_INTERRUPT_FLAGS_MODE BIT1 + +/// +/// Type 1 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 DoorbellInterrupt; + UINT8 DoorbellInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_0_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 2 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 DoorbellInterrupt; + UINT8 DoorbellInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; + EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE DoorbellAckRegister; + UINT64 DoorbellAckPreserve; + UINT64 DoorbellAckWrite; +} EFI_ACPI_6_0_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_6_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_6_0_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_6_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_6_0_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_6_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_6_0_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_6_0_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_6_0_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_6_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_6_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_6_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_6_0_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_6_0_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_6_0_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_6_0_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "NFIT" NVDIMM Firmware Interface Table +/// +#define EFI_ACPI_6_0_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('N', 'F', 'I', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_6_0_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_6_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_6_0_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_6_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_6_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_6_0_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_6_0_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_6_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_6_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_6_0_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_6_0_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_6_0_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_6_0_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_6_0_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_6_0_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_6_0_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_6_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_6_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IORT" I/O Remapping Table +/// +#define EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('I', 'O', 'R', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_6_0_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_6_0_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_6_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_6_0_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_6_0_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_6_0_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_6_0_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_6_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_6_0_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "STAO" _STA Override Table +/// +#define EFI_ACPI_6_0_STA_OVERRIDE_TABLE_SIGNATURE SIGNATURE_32('S', 'T', 'A', 'O') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_6_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_6_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_6_0_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_6_0_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_6_0_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_6_0_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_6_0_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +/// +/// "XENV" Xen Project Table +/// +#define EFI_ACPI_6_0_XEN_PROJECT_TABLE_SIGNATURE SIGNATURE_32('X', 'E', 'N', 'V') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi61.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi61.h new file mode 100644 index 0000000..94cfe8b --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi61.h @@ -0,0 +1,2430 @@ +/** @file + ACPI 6.1 definitions from the ACPI Specification Revision 6.1 January, 2016. + + Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright (c) 2020, ARM Ltd. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_6_1_H_ +#define _ACPI_6_1_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 6.1 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_6_1_SYSTEM_MEMORY 0 +#define EFI_ACPI_6_1_SYSTEM_IO 1 +#define EFI_ACPI_6_1_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_6_1_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_6_1_SMBUS 4 +#define EFI_ACPI_6_1_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_6_1_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_6_1_UNDEFINED 0 +#define EFI_ACPI_6_1_BYTE 1 +#define EFI_ACPI_6_1_WORD 2 +#define EFI_ACPI_6_1_DWORD 3 +#define EFI_ACPI_6_1_QWORD 4 + +// +// ACPI 6.1 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 6.1) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_1_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; + UINT64 HypervisorVendorIdentity; +} EFI_ACPI_6_1_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x06 +#define EFI_ACPI_6_1_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x01 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_6_1_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_6_1_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_6_1_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_6_1_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_6_1_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_6_1_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_6_1_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_6_1_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_6_1_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_1_LEGACY_DEVICES BIT0 +#define EFI_ACPI_6_1_8042 BIT1 +#define EFI_ACPI_6_1_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_6_1_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_6_1_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_6_1_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_1_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_6_1_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_1_WBINVD BIT0 +#define EFI_ACPI_6_1_WBINVD_FLUSH BIT1 +#define EFI_ACPI_6_1_PROC_C1 BIT2 +#define EFI_ACPI_6_1_P_LVL2_UP BIT3 +#define EFI_ACPI_6_1_PWR_BUTTON BIT4 +#define EFI_ACPI_6_1_SLP_BUTTON BIT5 +#define EFI_ACPI_6_1_FIX_RTC BIT6 +#define EFI_ACPI_6_1_RTC_S4 BIT7 +#define EFI_ACPI_6_1_TMR_VAL_EXT BIT8 +#define EFI_ACPI_6_1_DCK_CAP BIT9 +#define EFI_ACPI_6_1_RESET_REG_SUP BIT10 +#define EFI_ACPI_6_1_SEALED_CASE BIT11 +#define EFI_ACPI_6_1_HEADLESS BIT12 +#define EFI_ACPI_6_1_CPU_SW_SLP BIT13 +#define EFI_ACPI_6_1_PCI_EXP_WAK BIT14 +#define EFI_ACPI_6_1_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_6_1_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_6_1_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_6_1_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_6_1_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_6_1_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_6_1_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_6_1_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_1_S4BIOS_F BIT0 +#define EFI_ACPI_6_1_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_1_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_6_1_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_6_1_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x04 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_1_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0D and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_6_1_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_6_1_IO_APIC 0x01 +#define EFI_ACPI_6_1_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_6_1_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_6_1_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_6_1_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_6_1_IO_SAPIC 0x06 +#define EFI_ACPI_6_1_LOCAL_SAPIC 0x07 +#define EFI_ACPI_6_1_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_6_1_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_6_1_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_6_1_GIC 0x0B +#define EFI_ACPI_6_1_GICD 0x0C +#define EFI_ACPI_6_1_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_6_1_GICR 0x0E +#define EFI_ACPI_6_1_GIC_ITS 0x0F + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_6_1_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_6_1_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_6_1_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_6_1_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_1_POLARITY (3 << 0) +#define EFI_ACPI_6_1_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_6_1_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_6_1_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_6_1_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_6_1_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_6_1_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_6_1_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_1_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_6_1_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_6_1_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; + UINT8 ProcessorPowerEfficiencyClass; + UINT8 Reserved2[3]; +} EFI_ACPI_6_1_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_GIC_ENABLED BIT0 +#define EFI_ACPI_6_1_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_6_1_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_6_1_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_6_1_GIC_V1 0x01 +#define EFI_ACPI_6_1_GIC_V2 0x02 +#define EFI_ACPI_6_1_GIC_V3 0x03 +#define EFI_ACPI_6_1_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_6_1_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_6_1_GICR_STRUCTURE; + +/// +/// GIC Interrupt Translation Service Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicItsId; + UINT64 PhysicalBaseAddress; + UINT32 Reserved2; +} EFI_ACPI_6_1_GIC_ITS_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_6_1_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_6_1_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_6_1_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x04 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_1_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_6_1_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_6_1_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_6_1_GICC_AFFINITY 0x03 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_6_1_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_6_1_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_6_1_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_6_1_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_6_1_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_6_1_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_6_1_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_GICC_ENABLED (1 << 0) + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_6_1_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_6_1_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_6_1_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_6_1_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_6_1_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_6_1_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_6_1_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_6_1_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_6_1_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_6_1_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED 0x01 +#define EFI_ACPI_6_1_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPOTED_AND_EXPOSED_TO_SOFTWARE 0x02 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_6_1_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_6_1_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_6_1_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_6_1_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_6_1_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_6_1_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_6_1_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_6_1_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_1_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_1_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_1_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_MEMORY_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// Common Memory Aggregator Device Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; +} EFI_ACPI_6_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Memory Aggregator Device Type +/// +#define EFI_ACPI_6_1_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_6_1_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_6_1_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_DIMM 0x2 + +/// +/// Socket Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_1_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE MemoryController[]; +} EFI_ACPI_6_1_PMMT_SOCKET_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// MemoryController Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 OptimalAccessUnit; + UINT16 OptimalAccessAlignment; + UINT16 Reserved; + UINT16 NumberOfProximityDomains; + // UINT32 ProximityDomain[NumberOfProximityDomains]; + // EFI_ACPI_6_1_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE PhysicalComponent[]; +} EFI_ACPI_6_1_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// DIMM Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_1_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 PhysicalComponentIdentifier; + UINT16 Reserved; + UINT32 SizeOfDimm; + UINT32 SmbiosHandle; +} EFI_ACPI_6_1_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:1] = Reserved (must be zero) + /// Bit [0] = Valid. A one indicates the boot image graphic is valid. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_6_1_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_6_1_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_6_1_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_6_1_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_6_1_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_6_1_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_6_1_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_6_1_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_6_1_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_6_1_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_6_1_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_6_1_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_6_1_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_6_1_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_6_1_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_6_1_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_6_1_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_1_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_6_1_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_6_1_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior to when the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_6_1_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_6_1_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_1_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_6_1_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_1_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_6_1_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_6_1_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_6_1_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_1_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; +} EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_1_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_1_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_6_1_GTDT_GT_BLOCK 0 +#define EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_6_1_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_6_1_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_1_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_6_1_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// SBSA Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// SBSA Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_1_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +// +// NVDIMM Firmware Interface Table definition. +// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE; + +// +// NFIT Version (as defined in ACPI 6.1 spec.) +// +#define EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION 0x1 + +// +// Definition for NFIT Table Structure Types +// +#define EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE 0 +#define EFI_ACPI_6_1_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE_TYPE 1 +#define EFI_ACPI_6_1_NFIT_INTERLEAVE_STRUCTURE_TYPE 2 +#define EFI_ACPI_6_1_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE_TYPE 3 +#define EFI_ACPI_6_1_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE_TYPE 4 +#define EFI_ACPI_6_1_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE_TYPE 5 +#define EFI_ACPI_6_1_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE_TYPE 6 + +// +// Definition for NFIT Structure Header +// +typedef struct { + UINT16 Type; + UINT16 Length; +} EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER; + +// +// Definition for System Physical Address Range Structure +// +#define EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_CONTROL_REGION_FOR_MANAGEMENT BIT0 +#define EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_PROXIMITY_DOMAIN_VALID BIT1 +#define EFI_ACPI_6_1_NFIT_GUID_VOLATILE_MEMORY_REGION { 0x7305944F, 0xFDDA, 0x44E3, { 0xB1, 0x6C, 0x3F, 0x22, 0xD2, 0x52, 0xE5, 0xD0 }} +#define EFI_ACPI_6_1_NFIT_GUID_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_REGION { 0x66F0D379, 0xB4F3, 0x4074, { 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB }} +#define EFI_ACPI_6_1_NFIT_GUID_NVDIMM_CONTROL_REGION { 0x92F701F6, 0x13B4, 0x405D, { 0x91, 0x0B, 0x29, 0x93, 0x67, 0xE8, 0x23, 0x4C }} +#define EFI_ACPI_6_1_NFIT_GUID_NVDIMM_BLOCK_DATA_WINDOW_REGION { 0x91AF0530, 0x5D86, 0x470E, { 0xA6, 0xB0, 0x0A, 0x2D, 0xB9, 0x40, 0x82, 0x49 }} +#define EFI_ACPI_6_1_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_VOLATILE { 0x77AB535A, 0x45FC, 0x624B, { 0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }} +#define EFI_ACPI_6_1_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_VOLATILE { 0x3D5ABD30, 0x4175, 0x87CE, { 0x6D, 0x64, 0xD2, 0xAD, 0xE5, 0x23, 0xC4, 0xBB }} +#define EFI_ACPI_6_1_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_PERSISTENT { 0x5CEA02C9, 0x4D07, 0x69D3, { 0x26, 0x9F ,0x44, 0x96, 0xFB, 0xE0, 0x96, 0xF9 }} +#define EFI_ACPI_6_1_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_PERSISTENT { 0x08018188, 0x42CD, 0xBB48, { 0x10, 0x0F, 0x53, 0x87, 0xD5, 0x3D, 0xED, 0x3D }} +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 SPARangeStructureIndex; + UINT16 Flags; + UINT32 Reserved_8; + UINT32 ProximityDomain; + GUID AddressRangeTypeGUID; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; + UINT64 AddressRangeMemoryMappingAttribute; +} EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE; + +// +// Definition for Memory Device to System Physical Address Range Mapping Structure +// +typedef struct { + UINT32 DIMMNumber : 4; + UINT32 MemoryChannelNumber : 4; + UINT32 MemoryControllerID : 4; + UINT32 SocketID : 4; + UINT32 NodeControllerID : 12; + UINT32 Reserved_28 : 4; +} EFI_ACPI_6_1_NFIT_DEVICE_HANDLE; + +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_PREVIOUS_SAVE_FAIL BIT0 +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_LAST_RESTORE_FAIL BIT1 +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_PLATFORM_FLUSH_FAIL BIT2 +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_NOT_ARMED_PRIOR_TO_OSPM_HAND_OFF BIT3 +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_SMART_HEALTH_EVENTS_PRIOR_OSPM_HAND_OFF BIT4 +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_ENABLED_TO_NOTIFY_OSPM_ON_SMART_HEALTH_EVENTS BIT5 +#define EFI_ACPI_6_1_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_NOT_MAP_NVDIMM_TO_SPA BIT6 +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_1_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NVDIMMPhysicalID; + UINT16 NVDIMMRegionID; + UINT16 SPARangeStructureIndex; + UINT16 NVDIMMControlRegionStructureIndex; + UINT64 NVDIMMRegionSize; + UINT64 RegionOffset; + UINT64 NVDIMMPhysicalAddressRegionBase; + UINT16 InterleaveStructureIndex; + UINT16 InterleaveWays; + UINT16 NVDIMMStateFlags; + UINT16 Reserved_46; +} EFI_ACPI_6_1_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE; + +// +// Definition for Interleave Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 InterleaveStructureIndex; + UINT16 Reserved_6; + UINT32 NumberOfLines; + UINT32 LineSize; + // UINT32 LineOffset[NumberOfLines]; +} EFI_ACPI_6_1_NFIT_INTERLEAVE_STRUCTURE; + +// +// Definition for SMBIOS Management Information Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT32 Reserved_4; + // UINT8 Data[]; +} EFI_ACPI_6_1_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE; + +// +// Definition for NVDIMM Control Region Structure +// +#define EFI_ACPI_6_1_NFIT_NVDIMM_CONTROL_REGION_VALID_FIELDS_MANUFACTURING BIT0 + +#define EFI_ACPI_6_1_NFIT_NVDIMM_CONTROL_REGION_FLAGS_BLOCK_DATA_WINDOWS_BUFFERED BIT0 +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT16 SubsystemVendorID; + UINT16 SubsystemDeviceID; + UINT16 SubsystemRevisionID; + UINT8 ValidFields; + UINT8 ManufacturingLocation; + UINT16 ManufacturingDate; + UINT8 Reserved_22[2]; + UINT32 SerialNumber; + UINT16 RegionFormatInterfaceCode; + UINT16 NumberOfBlockControlWindows; + UINT64 SizeOfBlockControlWindow; + UINT64 CommandRegisterOffsetInBlockControlWindow; + UINT64 SizeOfCommandRegisterInBlockControlWindows; + UINT64 StatusRegisterOffsetInBlockControlWindow; + UINT64 SizeOfStatusRegisterInBlockControlWindows; + UINT16 NVDIMMControlRegionFlag; + UINT8 Reserved_74[6]; +} EFI_ACPI_6_1_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE; + +// +// Definition for NVDIMM Block Data Window Region Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 NumberOfBlockDataWindows; + UINT64 BlockDataWindowStartOffset; + UINT64 SizeOfBlockDataWindow; + UINT64 BlockAccessibleMemoryCapacity; + UINT64 BeginningAddressOfFirstBlockInBlockAccessibleMemory; +} EFI_ACPI_6_1_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE; + +// +// Definition for Flush Hint Address Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_1_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NumberOfFlushHintAddresses; + UINT8 Reserved_10[6]; + // UINT64 FlushHintAddress[NumberOfFlushHintAddresses]; +} EFI_ACPI_6_1_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_6_1_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_6_1_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_1_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_6_1_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_6_1_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_6_1_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_6_1_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_6_1_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + UINT8 Timestamp[8]; +} EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0300 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_6_1_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_6_1_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_6_1_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_6_1_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_6_1_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_6_1_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_6_1_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR 0x09 +#define EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_VERSION_2 0x0A + +// +// Error Source structure flags. +// +#define EFI_ACPI_6_1_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_6_1_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_6_1_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_6_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_6_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_6_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_6_1_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_CMCI 0x05 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_MCE 0x06 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_GPIO_SIGNAL 0x07 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEA 0x08 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEI 0x09 +#define EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_GSIV 0x0A + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_1_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_6_1_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_6_1_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_1_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_1_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Hardware Error Source Version 2 Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE ReadAckRegister; + UINT64 ReadAckPreserve; + UINT64 ReadAckWrite; +} EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_6_1_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_6_1_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_6_1_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_6_1_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_6_1_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_6_1_ERST_END_OPERATION 0x03 +#define EFI_ACPI_6_1_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_6_1_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_1_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_1_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_1_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_6_1_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_6_1_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_6_1_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_6_1_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_6_1_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_6_1_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F +#define EFI_ACPI_6_1_ERST_GET_EXECUTE_OPERATION_TIMINGS 0x10 + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_6_1_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_1_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_6_1_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_6_1_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_6_1_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_6_1_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_6_1_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_6_1_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_1_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_1_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_1_ERST_NOOP 0x04 +#define EFI_ACPI_6_1_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_6_1_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_6_1_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_6_1_ERST_ADD 0x08 +#define EFI_ACPI_6_1_ERST_SUBTRACT 0x09 +#define EFI_ACPI_6_1_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_6_1_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_6_1_ERST_STALL 0x0C +#define EFI_ACPI_6_1_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_6_1_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_6_1_ERST_GOTO 0x0F +#define EFI_ACPI_6_1_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_6_1_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_6_1_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_6_1_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_1_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_6_1_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_6_1_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_6_1_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_6_1_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_6_1_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_6_1_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_6_1_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_1_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_1_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_1_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_6_1_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_1_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_6_1_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_6_1_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_6_1_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_6_1_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_6_1_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_6_1_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_6_1_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_6_1_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_6_1_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_6_1_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_6_1_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_6_1_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_6_1_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_6_1_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_6_1_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_1_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_1_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_1_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_6_1_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_1_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_6_1_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_6_1_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 6.1 spec.) +/// +#define EFI_ACPI_6_1_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x01 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_6_1_PCCT_FLAGS_SCI_DOORBELL BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_6_1_PCCT_SUBSPACE_TYPE_GENERIC 0x00 +#define EFI_ACPI_6_1_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS 0x01 +#define EFI_ACPI_6_1_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS 0x02 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_6_1_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_1_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 GenerateSci : 1; +} EFI_ACPI_6_1_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 SciDoorbell : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_6_1_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_6_1_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_6_1_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_6_1_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +#define EFI_ACPI_6_1_PCCT_SUBSPACE_DOORBELL_INTERRUPT_FLAGS_POLARITY BIT0 +#define EFI_ACPI_6_1_PCCT_SUBSPACE_DOORBELL_INTERRUPT_FLAGS_MODE BIT1 + +/// +/// Type 1 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 DoorbellInterrupt; + UINT8 DoorbellInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_1_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 2 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 DoorbellInterrupt; + UINT8 DoorbellInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; + EFI_ACPI_6_1_GENERIC_ADDRESS_STRUCTURE DoorbellAckRegister; + UINT64 DoorbellAckPreserve; + UINT64 DoorbellAckWrite; +} EFI_ACPI_6_1_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_6_1_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_6_1_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_6_1_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_6_1_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_6_1_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_6_1_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_6_1_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_6_1_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_6_1_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_6_1_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_6_1_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_6_1_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_6_1_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_6_1_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "NFIT" NVDIMM Firmware Interface Table +/// +#define EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('N', 'F', 'I', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_6_1_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_6_1_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_6_1_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_6_1_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_6_1_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_6_1_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_6_1_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_6_1_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_6_1_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_6_1_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_6_1_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_6_1_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_6_1_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_6_1_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_6_1_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_6_1_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_6_1_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_6_1_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IORT" I/O Remapping Table +/// +#define EFI_ACPI_6_1_IO_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('I', 'O', 'R', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_6_1_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_6_1_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_6_1_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_6_1_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_6_1_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_6_1_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_6_1_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_6_1_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_6_1_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "STAO" _STA Override Table +/// +#define EFI_ACPI_6_1_STA_OVERRIDE_TABLE_SIGNATURE SIGNATURE_32('S', 'T', 'A', 'O') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_6_1_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_6_1_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_6_1_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_6_1_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_6_1_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_6_1_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_6_1_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +/// +/// "XENV" Xen Project Table +/// +#define EFI_ACPI_6_1_XEN_PROJECT_TABLE_SIGNATURE SIGNATURE_32('X', 'E', 'N', 'V') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi62.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi62.h new file mode 100644 index 0000000..c174e6d --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi62.h @@ -0,0 +1,2983 @@ +/** @file + ACPI 6.2 definitions from the ACPI Specification Revision 6.2 May, 2017. + + Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.
+ Copyright (c) 2020, ARM Ltd. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_6_2_H_ +#define _ACPI_6_2_H_ + +#include + +// +// Large Item Descriptor Name +// +#define ACPI_LARGE_PIN_FUNCTION_DESCRIPTOR_NAME 0x0D +#define ACPI_LARGE_PIN_CONFIGURATION_DESCRIPTOR_NAME 0x0F +#define ACPI_LARGE_PIN_GROUP_DESCRIPTOR_NAME 0x10 +#define ACPI_LARGE_PIN_GROUP_FUNCTION_DESCRIPTOR_NAME 0x11 +#define ACPI_LARGE_PIN_GROUP_CONFIGURATION_DESCRIPTOR_NAME 0x12 + +// +// Large Item Descriptor Value +// +#define ACPI_PIN_FUNCTION_DESCRIPTOR 0x8D +#define ACPI_PIN_CONFIGURATION_DESCRIPTOR 0x8F +#define ACPI_PIN_GROUP_DESCRIPTOR 0x90 +#define ACPI_PIN_GROUP_FUNCTION_DESCRIPTOR 0x91 +#define ACPI_PIN_GROUP_CONFIGURATION_DESCRIPTOR 0x92 + +#pragma pack(1) + +/// +/// Pin Function Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT16 Flags; + UINT8 PinPullConfiguration; + UINT16 FunctionNumber; + UINT16 PinTableOffset; + UINT8 ResourceSourceIndex; + UINT16 ResourceSourceNameOffset; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; +} EFI_ACPI_PIN_FUNCTION_DESCRIPTOR; + +/// +/// Pin Configuration Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT16 Flags; + UINT8 PinConfigurationType; + UINT32 PinConfigurationValue; + UINT16 PinTableOffset; + UINT8 ResourceSourceIndex; + UINT16 ResourceSourceNameOffset; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; +} EFI_ACPI_PIN_CONFIGURATION_DESCRIPTOR; + +/// +/// Pin Group Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT16 Flags; + UINT16 PinTableOffset; + UINT16 ResourceLabelOffset; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; +} EFI_ACPI_PIN_GROUP_DESCRIPTOR; + +/// +/// Pin Group Function Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT16 Flags; + UINT16 FunctionNumber; + UINT8 ResourceSourceIndex; + UINT16 ResourceSourceNameOffset; + UINT16 ResourceSourceLabelOffset; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; +} EFI_ACPI_PIN_GROUP_FUNCTION_DESCRIPTOR; + +/// +/// Pin Group Configuration Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 RevisionId; + UINT16 Flags; + UINT8 PinConfigurationType; + UINT32 PinConfigurationValue; + UINT8 ResourceSourceIndex; + UINT16 ResourceSourceNameOffset; + UINT16 ResourceSourceLabelOffset; + UINT16 VendorDataOffset; + UINT16 VendorDataLength; +} EFI_ACPI_PIN_GROUP_CONFIGURATION_DESCRIPTOR; + +#pragma pack() + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 6.2 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_6_2_SYSTEM_MEMORY 0 +#define EFI_ACPI_6_2_SYSTEM_IO 1 +#define EFI_ACPI_6_2_PCI_CONFIGURATION_SPACE 2 +#define EFI_ACPI_6_2_EMBEDDED_CONTROLLER 3 +#define EFI_ACPI_6_2_SMBUS 4 +#define EFI_ACPI_6_2_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_6_2_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_6_2_UNDEFINED 0 +#define EFI_ACPI_6_2_BYTE 1 +#define EFI_ACPI_6_2_WORD 2 +#define EFI_ACPI_6_2_DWORD 3 +#define EFI_ACPI_6_2_QWORD 4 + +// +// ACPI 6.2 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_6_2_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 6.2) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_2_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; + UINT64 HypervisorVendorIdentity; +} EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x06 +#define EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x02 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_6_2_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_6_2_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_6_2_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_6_2_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_6_2_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_6_2_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_6_2_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_6_2_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_6_2_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_2_LEGACY_DEVICES BIT0 +#define EFI_ACPI_6_2_8042 BIT1 +#define EFI_ACPI_6_2_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_6_2_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_6_2_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_6_2_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_2_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_6_2_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_2_WBINVD BIT0 +#define EFI_ACPI_6_2_WBINVD_FLUSH BIT1 +#define EFI_ACPI_6_2_PROC_C1 BIT2 +#define EFI_ACPI_6_2_P_LVL2_UP BIT3 +#define EFI_ACPI_6_2_PWR_BUTTON BIT4 +#define EFI_ACPI_6_2_SLP_BUTTON BIT5 +#define EFI_ACPI_6_2_FIX_RTC BIT6 +#define EFI_ACPI_6_2_RTC_S4 BIT7 +#define EFI_ACPI_6_2_TMR_VAL_EXT BIT8 +#define EFI_ACPI_6_2_DCK_CAP BIT9 +#define EFI_ACPI_6_2_RESET_REG_SUP BIT10 +#define EFI_ACPI_6_2_SEALED_CASE BIT11 +#define EFI_ACPI_6_2_HEADLESS BIT12 +#define EFI_ACPI_6_2_CPU_SW_SLP BIT13 +#define EFI_ACPI_6_2_PCI_EXP_WAK BIT14 +#define EFI_ACPI_6_2_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_6_2_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_6_2_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_6_2_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_6_2_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_6_2_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_6_2_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_2_S4BIOS_F BIT0 +#define EFI_ACPI_6_2_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_2_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x04 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_2_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0D and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_6_2_IO_APIC 0x01 +#define EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_6_2_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_6_2_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_6_2_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_6_2_IO_SAPIC 0x06 +#define EFI_ACPI_6_2_LOCAL_SAPIC 0x07 +#define EFI_ACPI_6_2_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_6_2_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_6_2_GIC 0x0B +#define EFI_ACPI_6_2_GICD 0x0C +#define EFI_ACPI_6_2_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_6_2_GICR 0x0E +#define EFI_ACPI_6_2_GIC_ITS 0x0F + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_6_2_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_6_2_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_2_POLARITY (3 << 0) +#define EFI_ACPI_6_2_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_6_2_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_6_2_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_6_2_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_6_2_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_6_2_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_6_2_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_2_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_6_2_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; + UINT8 ProcessorPowerEfficiencyClass; + UINT8 Reserved2[3]; +} EFI_ACPI_6_2_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_GIC_ENABLED BIT0 +#define EFI_ACPI_6_2_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_6_2_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_6_2_GIC_V1 0x01 +#define EFI_ACPI_6_2_GIC_V2 0x02 +#define EFI_ACPI_6_2_GIC_V3 0x03 +#define EFI_ACPI_6_2_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_6_2_GICR_STRUCTURE; + +/// +/// GIC Interrupt Translation Service Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicItsId; + UINT64 PhysicalBaseAddress; + UINT32 Reserved2; +} EFI_ACPI_6_2_GIC_ITS_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_6_2_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_6_2_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x05 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_6_2_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_6_2_GICC_AFFINITY 0x03 +#define EFI_ACPI_6_2_GIC_ITS_AFFINITY 0x04 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_6_2_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_6_2_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_6_2_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_6_2_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_GICC_ENABLED (1 << 0) + +/// +/// GIC Interrupt Translation Service (ITS) Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT8 Reserved[2]; + UINT32 ItsId; +} EFI_ACPI_6_2_GIC_ITS_AFFINITY_STRUCTURE; + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_6_2_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_6_2_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_6_2_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_6_2_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_6_2_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_6_2_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_6_2_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_6_2_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED BIT0 +#define EFI_ACPI_6_2_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED_AND_EXPOSED_TO_SOFTWARE BIT1 +#define EFI_ACPI_6_2_RASF_PLATFORM_RAS_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT2 +#define EFI_ACPI_6_2_RASF_PLATFORM_RAS_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT3 +#define EFI_ACPI_6_2_RASF_PLATFORM_RAS_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT4 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_6_2_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_6_2_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_6_2_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_6_2_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_6_2_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_6_2_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_6_2_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_6_2_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_2_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_2_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_2_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_MEMORY_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// Common Memory Aggregator Device Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; +} EFI_ACPI_6_2_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Memory Aggregator Device Type +/// +#define EFI_ACPI_6_2_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_6_2_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_6_2_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_DIMM 0x2 + +/// +/// Socket Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_2_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_2_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE MemoryController[]; +} EFI_ACPI_6_2_PMMT_SOCKET_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// MemoryController Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_2_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 OptimalAccessUnit; + UINT16 OptimalAccessAlignment; + UINT16 Reserved; + UINT16 NumberOfProximityDomains; + // UINT32 ProximityDomain[NumberOfProximityDomains]; + // EFI_ACPI_6_2_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE PhysicalComponent[]; +} EFI_ACPI_6_2_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// DIMM Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_2_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 PhysicalComponentIdentifier; + UINT16 Reserved; + UINT32 SizeOfDimm; + UINT32 SmbiosHandle; +} EFI_ACPI_6_2_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:1] = Reserved (must be zero) + /// Bit [0] = Valid. A one indicates the boot image graphic is valid. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_6_2_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_6_2_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_6_2_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_6_2_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_6_2_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_6_2_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_6_2_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_6_2_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_6_2_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_6_2_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_6_2_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_6_2_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_6_2_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_6_2_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_6_2_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_2_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_6_2_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_6_2_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior to when the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_6_2_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_6_2_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_2_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_6_2_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_2_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_6_2_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_6_2_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_6_2_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_2_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; +} EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_2_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_2_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_6_2_GTDT_GT_BLOCK 0 +#define EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_6_2_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// SBSA Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// SBSA Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +// +// NVDIMM Firmware Interface Table definition. +// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_2_NVDIMM_FIRMWARE_INTERFACE_TABLE; + +// +// NFIT Version (as defined in ACPI 6.2 spec.) +// +#define EFI_ACPI_6_2_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION 0x1 + +// +// Definition for NFIT Table Structure Types +// +#define EFI_ACPI_6_2_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE 0 +#define EFI_ACPI_6_2_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE_TYPE 1 +#define EFI_ACPI_6_2_NFIT_INTERLEAVE_STRUCTURE_TYPE 2 +#define EFI_ACPI_6_2_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE_TYPE 3 +#define EFI_ACPI_6_2_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE_TYPE 4 +#define EFI_ACPI_6_2_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE_TYPE 5 +#define EFI_ACPI_6_2_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE_TYPE 6 +#define EFI_ACPI_6_2_NFIT_PLATFORM_CAPABILITIES_STRUCTURE_TYPE 7 + +// +// Definition for NFIT Structure Header +// +typedef struct { + UINT16 Type; + UINT16 Length; +} EFI_ACPI_6_2_NFIT_STRUCTURE_HEADER; + +// +// Definition for System Physical Address Range Structure +// +#define EFI_ACPI_6_2_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_CONTROL_REGION_FOR_MANAGEMENT BIT0 +#define EFI_ACPI_6_2_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_PROXIMITY_DOMAIN_VALID BIT1 +#define EFI_ACPI_6_2_NFIT_GUID_VOLATILE_MEMORY_REGION { 0x7305944F, 0xFDDA, 0x44E3, { 0xB1, 0x6C, 0x3F, 0x22, 0xD2, 0x52, 0xE5, 0xD0 }} +#define EFI_ACPI_6_2_NFIT_GUID_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_REGION { 0x66F0D379, 0xB4F3, 0x4074, { 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB }} +#define EFI_ACPI_6_2_NFIT_GUID_NVDIMM_CONTROL_REGION { 0x92F701F6, 0x13B4, 0x405D, { 0x91, 0x0B, 0x29, 0x93, 0x67, 0xE8, 0x23, 0x4C }} +#define EFI_ACPI_6_2_NFIT_GUID_NVDIMM_BLOCK_DATA_WINDOW_REGION { 0x91AF0530, 0x5D86, 0x470E, { 0xA6, 0xB0, 0x0A, 0x2D, 0xB9, 0x40, 0x82, 0x49 }} +#define EFI_ACPI_6_2_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_VOLATILE { 0x77AB535A, 0x45FC, 0x624B, { 0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }} +#define EFI_ACPI_6_2_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_VOLATILE { 0x3D5ABD30, 0x4175, 0x87CE, { 0x6D, 0x64, 0xD2, 0xAD, 0xE5, 0x23, 0xC4, 0xBB }} +#define EFI_ACPI_6_2_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_PERSISTENT { 0x5CEA02C9, 0x4D07, 0x69D3, { 0x26, 0x9F ,0x44, 0x96, 0xFB, 0xE0, 0x96, 0xF9 }} +#define EFI_ACPI_6_2_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_PERSISTENT { 0x08018188, 0x42CD, 0xBB48, { 0x10, 0x0F, 0x53, 0x87, 0xD5, 0x3D, 0xED, 0x3D }} +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 SPARangeStructureIndex; + UINT16 Flags; + UINT32 Reserved_8; + UINT32 ProximityDomain; + GUID AddressRangeTypeGUID; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; + UINT64 AddressRangeMemoryMappingAttribute; +} EFI_ACPI_6_2_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE; + +// +// Definition for Memory Device to System Physical Address Range Mapping Structure +// +typedef struct { + UINT32 DIMMNumber : 4; + UINT32 MemoryChannelNumber : 4; + UINT32 MemoryControllerID : 4; + UINT32 SocketID : 4; + UINT32 NodeControllerID : 12; + UINT32 Reserved_28 : 4; +} EFI_ACPI_6_2_NFIT_DEVICE_HANDLE; + +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_PREVIOUS_SAVE_FAIL BIT0 +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_LAST_RESTORE_FAIL BIT1 +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_PLATFORM_FLUSH_FAIL BIT2 +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_NOT_ARMED_PRIOR_TO_OSPM_HAND_OFF BIT3 +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_SMART_HEALTH_EVENTS_PRIOR_OSPM_HAND_OFF BIT4 +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_ENABLED_TO_NOTIFY_OSPM_ON_SMART_HEALTH_EVENTS BIT5 +#define EFI_ACPI_6_2_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_NOT_MAP_NVDIMM_TO_SPA BIT6 +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_2_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NVDIMMPhysicalID; + UINT16 NVDIMMRegionID; + UINT16 SPARangeStructureIndex; + UINT16 NVDIMMControlRegionStructureIndex; + UINT64 NVDIMMRegionSize; + UINT64 RegionOffset; + UINT64 NVDIMMPhysicalAddressRegionBase; + UINT16 InterleaveStructureIndex; + UINT16 InterleaveWays; + UINT16 NVDIMMStateFlags; + UINT16 Reserved_46; +} EFI_ACPI_6_2_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE; + +// +// Definition for Interleave Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 InterleaveStructureIndex; + UINT16 Reserved_6; + UINT32 NumberOfLines; + UINT32 LineSize; + // UINT32 LineOffset[NumberOfLines]; +} EFI_ACPI_6_2_NFIT_INTERLEAVE_STRUCTURE; + +// +// Definition for SMBIOS Management Information Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT32 Reserved_4; + // UINT8 Data[]; +} EFI_ACPI_6_2_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE; + +// +// Definition for NVDIMM Control Region Structure +// +#define EFI_ACPI_6_2_NFIT_NVDIMM_CONTROL_REGION_VALID_FIELDS_MANUFACTURING BIT0 + +#define EFI_ACPI_6_2_NFIT_NVDIMM_CONTROL_REGION_FLAGS_BLOCK_DATA_WINDOWS_BUFFERED BIT0 +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT16 SubsystemVendorID; + UINT16 SubsystemDeviceID; + UINT16 SubsystemRevisionID; + UINT8 ValidFields; + UINT8 ManufacturingLocation; + UINT16 ManufacturingDate; + UINT8 Reserved_22[2]; + UINT32 SerialNumber; + UINT16 RegionFormatInterfaceCode; + UINT16 NumberOfBlockControlWindows; + UINT64 SizeOfBlockControlWindow; + UINT64 CommandRegisterOffsetInBlockControlWindow; + UINT64 SizeOfCommandRegisterInBlockControlWindows; + UINT64 StatusRegisterOffsetInBlockControlWindow; + UINT64 SizeOfStatusRegisterInBlockControlWindows; + UINT16 NVDIMMControlRegionFlag; + UINT8 Reserved_74[6]; +} EFI_ACPI_6_2_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE; + +// +// Definition for NVDIMM Block Data Window Region Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 NumberOfBlockDataWindows; + UINT64 BlockDataWindowStartOffset; + UINT64 SizeOfBlockDataWindow; + UINT64 BlockAccessibleMemoryCapacity; + UINT64 BeginningAddressOfFirstBlockInBlockAccessibleMemory; +} EFI_ACPI_6_2_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE; + +// +// Definition for Flush Hint Address Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_2_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NumberOfFlushHintAddresses; + UINT8 Reserved_10[6]; + // UINT64 FlushHintAddress[NumberOfFlushHintAddresses]; +} EFI_ACPI_6_2_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE; + +// +// Definition for Platform Capabilities Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT8 HighestValidCapability; + UINT8 Reserved_5[3]; + UINT32 Capabilities; + UINT8 Reserved_12[4]; +} EFI_ACPI_6_2_NFIT_PLATFORM_CAPABILITIES_STRUCTURE; + +#define EFI_ACPI_6_2_NFIT_PLATFORM_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT0 +#define EFI_ACPI_6_2_NFIT_PLATFORM_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT1 +#define EFI_ACPI_6_2_NFIT_PLATFORM_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT2 + +/// +/// Secure DEVices Table (SDEV) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_2_SECURE_DEVICES_TABLE_HEADER; + +/// +/// SDEV Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_SECURE_DEVICES_TABLE_REVISION 0x01 + +/// +/// Secure Device types +/// +#define EFI_ACPI_6_2_SDEV_TYPE_PCIE_ENDPOINT_DEVICE 0x01 +#define EFI_ACPI_6_2_SDEV_TYPE_ACPI_NAMESPACE_DEVICE 0x00 + +/// +/// Secure Device flags +/// +#define EFI_ACPI_6_2_SDEV_FLAG_ALLOW_HANDOFF BIT0 + +/// +/// SDEV Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; +} EFI_ACPI_6_2_SDEV_STRUCTURE_HEADER; + +/// +/// PCIe Endpoint Device based Secure Device Structure +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; + UINT16 PciSegmentNumber; + UINT16 StartBusNumber; + UINT16 PciPathOffset; + UINT16 PciPathLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; +} EFI_ACPI_6_2_SDEV_STRUCTURE_PCIE_ENDPOINT_DEVICE; + +/// +/// ACPI_NAMESPACE_DEVICE based Secure Device Structure +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; + UINT16 DeviceIdentifierOffset; + UINT16 DeviceIdentifierLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; +} EFI_ACPI_6_2_SDEV_STRUCTURE_ACPI_NAMESPACE_DEVICE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_6_2_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_6_2_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_6_2_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_2_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_6_2_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_6_2_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_6_2_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_6_2_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_6_2_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + UINT8 Timestamp[8]; +} EFI_ACPI_6_2_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0300 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_6_2_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_6_2_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_6_2_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_6_2_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_6_2_GENERIC_HARDWARE_ERROR 0x09 +#define EFI_ACPI_6_2_GENERIC_HARDWARE_ERROR_VERSION_2 0x0A +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK 0x0B + +// +// Error Source structure flags. +// +#define EFI_ACPI_6_2_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_6_2_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) +#define EFI_ACPI_6_2_ERROR_SOURCE_FLAG_GHES_ASSIST (1 << 2) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_6_2_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_6_2_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_6_2_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_CMCI 0x05 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_MCE 0x06 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_GPIO_SIGNAL 0x07 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEA 0x08 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEI 0x09 +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_GSIV 0x0A +#define EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_SOFTWARE_DELEGATED_EXCEPTION 0x0B + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_2_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_6_2_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_6_2_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_2_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_2_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_6_2_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Hardware Error Source Version 2 Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE ReadAckRegister; + UINT64 ReadAckPreserve; + UINT64 ReadAckWrite; +} EFI_ACPI_6_2_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_6_2_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_2_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// IA-32 Architecture Deferred Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_2_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_2_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK_STRUCTURE; + +/// +/// HMAT - Heterogeneous Memory Attribute Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[4]; +} EFI_ACPI_6_2_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER; + +/// +/// HMAT Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_REVISION 0x01 + +/// +/// HMAT types +/// +#define EFI_ACPI_6_2_HMAT_TYPE_MEMORY_SUBSYSTEM_ADDRESS_RANGE 0x00 +#define EFI_ACPI_6_2_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO 0x01 +#define EFI_ACPI_6_2_HMAT_TYPE_MEMORY_SIDE_CACHE_INFO 0x02 + +/// +/// HMAT Structure Header +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; +} EFI_ACPI_6_2_HMAT_STRUCTURE_HEADER; + +/// +/// Memory Subsystem Address Range Structure flags +/// +typedef struct { + UINT16 ProcessorProximityDomainValid : 1; + UINT16 MemoryProximityDomainValid : 1; + UINT16 ReservationHint : 1; + UINT16 Reserved : 13; +} EFI_ACPI_6_2_HMAT_STRUCTURE_MEMORY_SUBSYSTEM_ADDRESS_RANGE_FLAGS; + +/// +/// Memory Subsystem Address Range Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_2_HMAT_STRUCTURE_MEMORY_SUBSYSTEM_ADDRESS_RANGE_FLAGS Flags; + UINT8 Reserved1[2]; + UINT32 ProcessorProximityDomain; + UINT32 MemoryProximityDomain; + UINT8 Reserved2[4]; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; +} EFI_ACPI_6_2_HMAT_STRUCTURE_MEMORY_SUBSYSTEM_ADDRESS_RANGE; + +/// +/// System Locality Latency and Bandwidth Information Structure flags +/// +typedef struct { + UINT8 MemoryHierarchy : 5; + UINT8 Reserved : 3; +} EFI_ACPI_6_2_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS; + +/// +/// System Locality Latency and Bandwidth Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_2_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS Flags; + UINT8 DataType; + UINT8 Reserved1[2]; + UINT32 NumberOfInitiatorProximityDomains; + UINT32 NumberOfTargetProximityDomains; + UINT8 Reserved2[4]; + UINT64 EntryBaseUnit; +} EFI_ACPI_6_2_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO; + +/// +/// Memory Side Cache Information Structure cache attributes +/// +typedef struct { + UINT32 TotalCacheLevels : 4; + UINT32 CacheLevel : 4; + UINT32 CacheAssociativity : 4; + UINT32 WritePolicy : 4; + UINT32 CacheLineSize : 16; +} EFI_ACPI_6_2_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES; + +/// +/// Memory Side Cache Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + UINT32 MemoryProximityDomain; + UINT8 Reserved1[4]; + UINT64 MemorySideCacheSize; + EFI_ACPI_6_2_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES CacheAttributes; + UINT8 Reserved2[2]; + UINT16 NumberOfSmbiosHandles; +} EFI_ACPI_6_2_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_6_2_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_6_2_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_6_2_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_6_2_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_6_2_ERST_END_OPERATION 0x03 +#define EFI_ACPI_6_2_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_6_2_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_2_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_2_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_2_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_6_2_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_6_2_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_6_2_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_6_2_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_6_2_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_6_2_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F +#define EFI_ACPI_6_2_ERST_GET_EXECUTE_OPERATION_TIMINGS 0x10 + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_6_2_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_2_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_6_2_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_6_2_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_6_2_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_6_2_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_6_2_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_6_2_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_2_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_2_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_2_ERST_NOOP 0x04 +#define EFI_ACPI_6_2_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_6_2_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_6_2_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_6_2_ERST_ADD 0x08 +#define EFI_ACPI_6_2_ERST_SUBTRACT 0x09 +#define EFI_ACPI_6_2_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_6_2_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_6_2_ERST_STALL 0x0C +#define EFI_ACPI_6_2_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_6_2_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_6_2_ERST_GOTO 0x0F +#define EFI_ACPI_6_2_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_6_2_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_6_2_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_6_2_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_2_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_6_2_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_6_2_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_6_2_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_6_2_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_6_2_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_6_2_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_6_2_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_2_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_2_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_2_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_6_2_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_2_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_6_2_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_6_2_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_6_2_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_6_2_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_6_2_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_6_2_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_6_2_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_6_2_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_6_2_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_6_2_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_6_2_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_6_2_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_6_2_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_6_2_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_6_2_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_2_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_2_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_2_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_6_2_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_2_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_6_2_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_6_2_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x02 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_6_2_PCCT_FLAGS_PLATFORM_INTERRUPT BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_6_2_PCCT_SUBSPACE_TYPE_GENERIC 0x00 +#define EFI_ACPI_6_2_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS 0x01 +#define EFI_ACPI_6_2_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS 0x02 +#define EFI_ACPI_6_2_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC 0x03 +#define EFI_ACPI_6_2_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC 0x04 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_6_2_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_2_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 NotifyOnCompletion : 1; +} EFI_ACPI_6_2_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 PlatformInterrupt : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_6_2_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_6_2_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_6_2_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_6_2_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +#define EFI_ACPI_6_2_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_POLARITY BIT0 +#define EFI_ACPI_6_2_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE BIT1 + +/// +/// Type 1 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_2_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 2 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckWrite; +} EFI_ACPI_6_2_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 3 Extended PCC Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT32 AddressLength; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT32 MinimumRequestTurnaroundTime; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckSet; + UINT8 Reserved1[8]; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE CommandCompleteCheckRegister; + UINT64 CommandCompleteCheckMask; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE CommandCompleteUpdateRegister; + UINT64 CommandCompleteUpdatePreserve; + UINT64 CommandCompleteUpdateSet; + EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE ErrorStatusRegister; + UINT64 ErrorStatusMask; +} EFI_ACPI_6_2_PCCT_SUBSPACE_3_EXTENDED_PCC; + +/// +/// Type 4 Extended PCC Subspace Structure +/// +typedef EFI_ACPI_6_2_PCCT_SUBSPACE_3_EXTENDED_PCC EFI_ACPI_6_2_PCCT_SUBSPACE_4_EXTENDED_PCC; + +#define EFI_ACPI_6_2_PCCT_MASTER_SLAVE_COMMUNICATIONS_CHANNEL_FLAGS_NOTIFY_ON_COMPLETION BIT0 + +typedef struct { + UINT32 Signature; + UINT32 Flags; + UINT32 Length; + UINT32 Command; +} EFI_ACPI_6_2_PCCT_EXTENDED_PCC_SHARED_MEMORY_REGION_HEADER; + +/// +/// Platform Debug Trigger Table (PDTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 TriggerCount; + UINT8 Reserved[3]; + UINT32 TriggerIdentifierArrayOffset; +} EFI_ACPI_6_2_PLATFORM_DEBUG_TRIGGER_TABLE_HEADER; + +/// +/// PDTT Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_PLATFORM_DEBUG_TRIGGER_TABLE_REVISION 0x00 + +/// +/// PDTT Platform Communication Channel Identifier Structure +/// +typedef struct { + UINT16 SubChannelIdentifer : 8; + UINT16 Runtime : 1; + UINT16 WaitForCompletion : 1; + UINT16 Reserved : 6; +} EFI_ACPI_6_2_PDTT_PCC_IDENTIFIER; + +/// +/// PCC Commands Codes used by Platform Debug Trigger Table +/// +#define EFI_ACPI_6_2_PDTT_PCC_COMMAND_DOORBELL_ONLY 0x00 +#define EFI_ACPI_6_2_PDTT_PCC_COMMAND_VENDOR_SPECIFIC 0x01 + +/// +/// PPTT Platform Communication Channel +/// +typedef EFI_ACPI_6_2_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER EFI_ACPI_6_2_PDTT_PCC; + +/// +/// Processor Properties Topology Table (PPTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER; + +/// +/// PPTT Revision (as defined in ACPI 6.2 spec.) +/// +#define EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// PPTT types +/// +#define EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR 0x00 +#define EFI_ACPI_6_2_PPTT_TYPE_CACHE 0x01 +#define EFI_ACPI_6_2_PPTT_TYPE_ID 0x02 + +/// +/// PPTT Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; +} EFI_ACPI_6_2_PPTT_STRUCTURE_HEADER; + +/// +/// For PPTT struct processor flags +/// +#define EFI_ACPI_6_2_PPTT_PROCESSOR_ID_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID 0x1 + +/// +/// Processor hierarchy node structure flags +/// +typedef struct { + UINT32 PhysicalPackage : 1; + UINT32 AcpiProcessorIdValid : 1; + UINT32 Reserved : 30; +} EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR_FLAGS; + +/// +/// Processor hierarchy node structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR_FLAGS Flags; + UINT32 Parent; + UINT32 AcpiProcessorId; + UINT32 NumberOfPrivateResources; +} EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR; + +/// +/// Cache Type Structure flags +/// +typedef struct { + UINT32 SizePropertyValid : 1; + UINT32 NumberOfSetsValid : 1; + UINT32 AssociativityValid : 1; + UINT32 AllocationTypeValid : 1; + UINT32 CacheTypeValid : 1; + UINT32 WritePolicyValid : 1; + UINT32 LineSizeValid : 1; + UINT32 Reserved : 25; +} EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE_FLAGS; + +/// +/// For cache attributes +/// +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ 0x0 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_WRITE 0x1 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE 0x2 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_DATA 0x0 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_INSTRUCTION 0x1 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_UNIFIED 0x2 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK 0x0 +#define EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_THROUGH 0x1 + +/// +/// Cache Type Structure cache attributes +/// +typedef struct { + UINT8 AllocationType : 2; + UINT8 CacheType : 2; + UINT8 WritePolicy : 1; + UINT8 Reserved : 3; +} EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE_ATTRIBUTES; + +/// +/// Cache Type Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE_FLAGS Flags; + UINT32 NextLevelOfCache; + UINT32 Size; + UINT32 NumberOfSets; + UINT8 Associativity; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE_ATTRIBUTES Attributes; + UINT16 LineSize; +} EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE; + +/// +/// ID structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 VendorId; + UINT64 Level1Id; + UINT64 Level2Id; + UINT16 MajorRev; + UINT16 MinorRev; + UINT16 SpinRev; +} EFI_ACPI_6_2_PPTT_STRUCTURE_ID; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_6_2_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_6_2_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_6_2_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_6_2_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_6_2_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_6_2_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_6_2_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_6_2_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "HMAT" Heterogeneous Memory Attribute Table +/// +#define EFI_ACPI_6_2_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('H', 'M', 'A', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_6_2_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "NFIT" NVDIMM Firmware Interface Table +/// +#define EFI_ACPI_6_2_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('N', 'F', 'I', 'T') + +/// +/// "PDTT" Platform Debug Trigger Table +/// +#define EFI_ACPI_6_2_PLATFORM_DEBUG_TRIGGER_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'D', 'T', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_6_2_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PPTT" Processor Properties Topology Table +/// +#define EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'P', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_6_2_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_6_2_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_6_2_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_6_2_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SDEV" Secure DEVices Table +/// +#define EFI_ACPI_6_2_SECURE_DEVICES_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'V') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_6_2_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_6_2_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_6_2_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_6_2_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_6_2_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DPPT" DMA Protection Policy Table +/// +#define EFI_ACPI_6_2_DMA_PROTECTION_POLICY_TABLE_SIGNATURE SIGNATURE_32('D', 'P', 'P', 'T') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_6_2_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_6_2_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_6_2_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_6_2_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IORT" I/O Remapping Table +/// +#define EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('I', 'O', 'R', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_6_2_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_6_2_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_6_2_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_6_2_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_6_2_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "SDEI" Software Delegated Exceptions Interface Table +/// +#define EFI_ACPI_6_2_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'I') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_6_2_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Console Redirection Table +/// +#define EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_6_2_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "STAO" _STA Override Table +/// +#define EFI_ACPI_6_2_STA_OVERRIDE_TABLE_SIGNATURE SIGNATURE_32('S', 'T', 'A', 'O') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_6_2_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_6_2_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_6_2_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_6_2_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_6_2_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_6_2_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_6_2_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +/// +/// "WSMT" Windows SMM Security Mitigation Table +/// +#define EFI_ACPI_6_2_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE SIGNATURE_32('W', 'S', 'M', 'T') + +/// +/// "XENV" Xen Project Table +/// +#define EFI_ACPI_6_2_XEN_PROJECT_TABLE_SIGNATURE SIGNATURE_32('X', 'E', 'N', 'V') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi63.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi63.h new file mode 100644 index 0000000..75f6ccb --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi63.h @@ -0,0 +1,2983 @@ +/** @file + ACPI 6.3 definitions from the ACPI Specification Revision 6.3 Jan, 2019. + + Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2020, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_6_3_H_ +#define _ACPI_6_3_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 6.3 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_6_3_SYSTEM_MEMORY 0x00 +#define EFI_ACPI_6_3_SYSTEM_IO 0x01 +#define EFI_ACPI_6_3_PCI_CONFIGURATION_SPACE 0x02 +#define EFI_ACPI_6_3_EMBEDDED_CONTROLLER 0x03 +#define EFI_ACPI_6_3_SMBUS 0x04 +#define EFI_ACPI_6_3_SYSTEM_CMOS 0x05 +#define EFI_ACPI_6_3_PCI_BAR_TARGET 0x06 +#define EFI_ACPI_6_3_IPMI 0x07 +#define EFI_ACPI_6_3_GENERAL_PURPOSE_IO 0x08 +#define EFI_ACPI_6_3_GENERIC_SERIAL_BUS 0x09 +#define EFI_ACPI_6_3_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_6_3_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_6_3_UNDEFINED 0 +#define EFI_ACPI_6_3_BYTE 1 +#define EFI_ACPI_6_3_WORD 2 +#define EFI_ACPI_6_3_DWORD 3 +#define EFI_ACPI_6_3_QWORD 4 + +// +// ACPI 6.3 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 6.3) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_3_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; + UINT64 HypervisorVendorIdentity; +} EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x06 +#define EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x03 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_6_3_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_6_3_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_6_3_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_6_3_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_6_3_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_6_3_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_6_3_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_6_3_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_6_3_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_3_LEGACY_DEVICES BIT0 +#define EFI_ACPI_6_3_8042 BIT1 +#define EFI_ACPI_6_3_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_6_3_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_6_3_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_6_3_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_3_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_6_3_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_3_WBINVD BIT0 +#define EFI_ACPI_6_3_WBINVD_FLUSH BIT1 +#define EFI_ACPI_6_3_PROC_C1 BIT2 +#define EFI_ACPI_6_3_P_LVL2_UP BIT3 +#define EFI_ACPI_6_3_PWR_BUTTON BIT4 +#define EFI_ACPI_6_3_SLP_BUTTON BIT5 +#define EFI_ACPI_6_3_FIX_RTC BIT6 +#define EFI_ACPI_6_3_RTC_S4 BIT7 +#define EFI_ACPI_6_3_TMR_VAL_EXT BIT8 +#define EFI_ACPI_6_3_DCK_CAP BIT9 +#define EFI_ACPI_6_3_RESET_REG_SUP BIT10 +#define EFI_ACPI_6_3_SEALED_CASE BIT11 +#define EFI_ACPI_6_3_HEADLESS BIT12 +#define EFI_ACPI_6_3_CPU_SW_SLP BIT13 +#define EFI_ACPI_6_3_PCI_EXP_WAK BIT14 +#define EFI_ACPI_6_3_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_6_3_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_6_3_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_6_3_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_6_3_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_6_3_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_6_3_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_3_S4BIOS_F BIT0 +#define EFI_ACPI_6_3_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_3_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x05 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_3_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x0D and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_6_3_IO_APIC 0x01 +#define EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_6_3_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_6_3_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_6_3_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_6_3_IO_SAPIC 0x06 +#define EFI_ACPI_6_3_LOCAL_SAPIC 0x07 +#define EFI_ACPI_6_3_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_6_3_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_6_3_GIC 0x0B +#define EFI_ACPI_6_3_GICD 0x0C +#define EFI_ACPI_6_3_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_6_3_GICR 0x0E +#define EFI_ACPI_6_3_GIC_ITS 0x0F + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_LOCAL_APIC_ENABLED BIT0 +#define EFI_ACPI_6_3_LOCAL_APIC_ONLINE_CAPABLE BIT1 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_6_3_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_6_3_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_3_POLARITY (3 << 0) +#define EFI_ACPI_6_3_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_6_3_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_6_3_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_6_3_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_6_3_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_6_3_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_6_3_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_3_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_6_3_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; + UINT8 ProcessorPowerEfficiencyClass; + UINT8 Reserved2; + UINT16 SpeOverflowInterrupt; +} EFI_ACPI_6_3_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_GIC_ENABLED BIT0 +#define EFI_ACPI_6_3_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_6_3_GIC_V1 0x01 +#define EFI_ACPI_6_3_GIC_V2 0x02 +#define EFI_ACPI_6_3_GIC_V3 0x03 +#define EFI_ACPI_6_3_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_6_3_GICR_STRUCTURE; + +/// +/// GIC Interrupt Translation Service Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicItsId; + UINT64 PhysicalBaseAddress; + UINT32 Reserved2; +} EFI_ACPI_6_3_GIC_ITS_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_6_3_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_6_3_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x06 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_6_3_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_6_3_GICC_AFFINITY 0x03 +#define EFI_ACPI_6_3_GIC_ITS_AFFINITY 0x04 +#define EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY 0x05 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_6_3_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_6_3_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_6_3_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_GICC_ENABLED (1 << 0) + +/// +/// GIC Interrupt Translation Service (ITS) Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT8 Reserved[2]; + UINT32 ItsId; +} EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE; + +// +// Generic Initiator Affinity Structure Device Handle Types +// All other values between 0x02 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_3_ACPI_DEVICE_HANDLE 0x00 +#define EFI_ACPI_6_3_PCI_DEVICE_HANDLE 0x01 + +/// +/// Device Handle - ACPI +/// +typedef struct { + UINT64 AcpiHid; + UINT32 AcpiUid; + UINT8 Reserved[4]; +} EFI_ACPI_6_3_DEVICE_HANDLE_ACPI; + +/// +/// Device Handle - PCI +/// +typedef struct { + UINT16 PciSegment; + UINT16 PciBdfNumber; + UINT8 Reserved[12]; +} EFI_ACPI_6_3_DEVICE_HANDLE_PCI; + +/// +/// Generic Initiator Affinity Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1; + UINT8 DeviceHandleType; + UINT32 ProximityDomain; + + union { + EFI_ACPI_6_3_DEVICE_HANDLE_ACPI Acpi; + EFI_ACPI_6_3_DEVICE_HANDLE_PCI Pci; + } DeviceHandle; + + UINT32 Flags; + UINT8 Reserved2[4]; +} EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE; + +/// +/// Generic Initiator Affinity Structure Flags. All other bits are reserved +/// and must be 0. +/// +#define EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE_ENABLED (1 << 0) + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_6_3_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_6_3_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_6_3_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_6_3_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_6_3_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_6_3_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_6_3_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_6_3_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_6_3_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED BIT0 +#define EFI_ACPI_6_3_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED_AND_EXPOSED_TO_SOFTWARE BIT1 +#define EFI_ACPI_6_3_RASF_PLATFORM_RAS_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT2 +#define EFI_ACPI_6_3_RASF_PLATFORM_RAS_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT3 +#define EFI_ACPI_6_3_RASF_PLATFORM_RAS_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT4 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_6_3_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_6_3_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_6_3_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_6_3_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_6_3_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_6_3_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_6_3_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_6_3_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_3_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_3_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_3_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_MEMORY_TOPOLOGY_TABLE_REVISION 0x01 + +/// +/// Common Memory Aggregator Device Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; +} EFI_ACPI_6_3_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Memory Aggregator Device Type +/// +#define EFI_ACPI_6_3_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_6_3_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_6_3_PMMT_MEMORY_AGGREGATOR_DEVICE_TYPE_DIMM 0x2 + +/// +/// Socket Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_3_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_3_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE MemoryController[]; +} EFI_ACPI_6_3_PMMT_SOCKET_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// MemoryController Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_3_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT32 ReadLatency; + UINT32 WriteLatency; + UINT32 ReadBandwidth; + UINT32 WriteBandwidth; + UINT16 OptimalAccessUnit; + UINT16 OptimalAccessAlignment; + UINT16 Reserved; + UINT16 NumberOfProximityDomains; + // UINT32 ProximityDomain[NumberOfProximityDomains]; + // EFI_ACPI_6_3_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE PhysicalComponent[]; +} EFI_ACPI_6_3_PMMT_MEMORY_CONTROLLER_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// DIMM Memory Aggregator Device Structure. +/// +typedef struct { + EFI_ACPI_6_3_PMMT_COMMON_MEMORY_AGGREGATOR_DEVICE_STRUCTURE Header; + UINT16 PhysicalComponentIdentifier; + UINT16 Reserved; + UINT32 SizeOfDimm; + UINT32 SmbiosHandle; +} EFI_ACPI_6_3_PMMT_DIMM_MEMORY_AGGREGATOR_DEVICE_STRUCTURE; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:1] = Reserved (must be zero) + /// Bit [0] = Valid. A one indicates the boot image graphic is valid. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_6_3_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_6_3_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_6_3_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_6_3_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_6_3_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_6_3_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_6_3_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_6_3_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_6_3_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_6_3_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_6_3_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_6_3_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_6_3_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_6_3_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_6_3_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_3_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_6_3_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_6_3_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior towhen the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_6_3_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_6_3_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_3_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_6_3_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_3_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_6_3_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_6_3_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_6_3_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_3_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; + UINT32 VirtualPL2TimerGSIV; + UINT32 VirtualPL2TimerFlags; +} EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x03 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_3_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_3_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_6_3_GTDT_GT_BLOCK 0 +#define EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_6_3_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// SBSA Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// SBSA Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +// +// NVDIMM Firmware Interface Table definition. +// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_3_NVDIMM_FIRMWARE_INTERFACE_TABLE; + +// +// NFIT Version (as defined in ACPI 6.3 spec.) +// +#define EFI_ACPI_6_3_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION 0x1 + +// +// Definition for NFIT Table Structure Types +// +#define EFI_ACPI_6_3_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE 0 +#define EFI_ACPI_6_3_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE_TYPE 1 +#define EFI_ACPI_6_3_NFIT_INTERLEAVE_STRUCTURE_TYPE 2 +#define EFI_ACPI_6_3_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE_TYPE 3 +#define EFI_ACPI_6_3_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE_TYPE 4 +#define EFI_ACPI_6_3_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE_TYPE 5 +#define EFI_ACPI_6_3_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE_TYPE 6 +#define EFI_ACPI_6_3_NFIT_PLATFORM_CAPABILITIES_STRUCTURE_TYPE 7 + +// +// Definition for NFIT Structure Header +// +typedef struct { + UINT16 Type; + UINT16 Length; +} EFI_ACPI_6_3_NFIT_STRUCTURE_HEADER; + +// +// Definition for System Physical Address Range Structure +// +#define EFI_ACPI_6_3_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_CONTROL_REGION_FOR_MANAGEMENT BIT0 +#define EFI_ACPI_6_3_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_PROXIMITY_DOMAIN_VALID BIT1 +#define EFI_ACPI_6_3_NFIT_GUID_VOLATILE_MEMORY_REGION { 0x7305944F, 0xFDDA, 0x44E3, { 0xB1, 0x6C, 0x3F, 0x22, 0xD2, 0x52, 0xE5, 0xD0 }} +#define EFI_ACPI_6_3_NFIT_GUID_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_REGION { 0x66F0D379, 0xB4F3, 0x4074, { 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB }} +#define EFI_ACPI_6_3_NFIT_GUID_NVDIMM_CONTROL_REGION { 0x92F701F6, 0x13B4, 0x405D, { 0x91, 0x0B, 0x29, 0x93, 0x67, 0xE8, 0x23, 0x4C }} +#define EFI_ACPI_6_3_NFIT_GUID_NVDIMM_BLOCK_DATA_WINDOW_REGION { 0x91AF0530, 0x5D86, 0x470E, { 0xA6, 0xB0, 0x0A, 0x2D, 0xB9, 0x40, 0x82, 0x49 }} +#define EFI_ACPI_6_3_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_VOLATILE { 0x77AB535A, 0x45FC, 0x624B, { 0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }} +#define EFI_ACPI_6_3_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_VOLATILE { 0x3D5ABD30, 0x4175, 0x87CE, { 0x6D, 0x64, 0xD2, 0xAD, 0xE5, 0x23, 0xC4, 0xBB }} +#define EFI_ACPI_6_3_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_PERSISTENT { 0x5CEA02C9, 0x4D07, 0x69D3, { 0x26, 0x9F ,0x44, 0x96, 0xFB, 0xE0, 0x96, 0xF9 }} +#define EFI_ACPI_6_3_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_PERSISTENT { 0x08018188, 0x42CD, 0xBB48, { 0x10, 0x0F, 0x53, 0x87, 0xD5, 0x3D, 0xED, 0x3D }} +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 SPARangeStructureIndex; + UINT16 Flags; + UINT32 Reserved_8; + UINT32 ProximityDomain; + GUID AddressRangeTypeGUID; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; + UINT64 AddressRangeMemoryMappingAttribute; +} EFI_ACPI_6_3_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE; + +// +// Definition for Memory Device to System Physical Address Range Mapping Structure +// +typedef struct { + UINT32 DIMMNumber : 4; + UINT32 MemoryChannelNumber : 4; + UINT32 MemoryControllerID : 4; + UINT32 SocketID : 4; + UINT32 NodeControllerID : 12; + UINT32 Reserved_28 : 4; +} EFI_ACPI_6_3_NFIT_DEVICE_HANDLE; + +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_PREVIOUS_SAVE_FAIL BIT0 +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_LAST_RESTORE_FAIL BIT1 +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_PLATFORM_FLUSH_FAIL BIT2 +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_NOT_ARMED_PRIOR_TO_OSPM_HAND_OFF BIT3 +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_SMART_HEALTH_EVENTS_PRIOR_OSPM_HAND_OFF BIT4 +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_ENABLED_TO_NOTIFY_OSPM_ON_SMART_HEALTH_EVENTS BIT5 +#define EFI_ACPI_6_3_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_NOT_MAP_NVDIMM_TO_SPA BIT6 +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_3_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NVDIMMPhysicalID; + UINT16 NVDIMMRegionID; + UINT16 SPARangeStructureIndex; + UINT16 NVDIMMControlRegionStructureIndex; + UINT64 NVDIMMRegionSize; + UINT64 RegionOffset; + UINT64 NVDIMMPhysicalAddressRegionBase; + UINT16 InterleaveStructureIndex; + UINT16 InterleaveWays; + UINT16 NVDIMMStateFlags; + UINT16 Reserved_46; +} EFI_ACPI_6_3_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE; + +// +// Definition for Interleave Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 InterleaveStructureIndex; + UINT16 Reserved_6; + UINT32 NumberOfLines; + UINT32 LineSize; + // UINT32 LineOffset[NumberOfLines]; +} EFI_ACPI_6_3_NFIT_INTERLEAVE_STRUCTURE; + +// +// Definition for SMBIOS Management Information Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT32 Reserved_4; + // UINT8 Data[]; +} EFI_ACPI_6_3_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE; + +// +// Definition for NVDIMM Control Region Structure +// +#define EFI_ACPI_6_3_NFIT_NVDIMM_CONTROL_REGION_VALID_FIELDS_MANUFACTURING BIT0 + +#define EFI_ACPI_6_3_NFIT_NVDIMM_CONTROL_REGION_FLAGS_BLOCK_DATA_WINDOWS_BUFFERED BIT0 +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT16 SubsystemVendorID; + UINT16 SubsystemDeviceID; + UINT16 SubsystemRevisionID; + UINT8 ValidFields; + UINT8 ManufacturingLocation; + UINT16 ManufacturingDate; + UINT8 Reserved_22[2]; + UINT32 SerialNumber; + UINT16 RegionFormatInterfaceCode; + UINT16 NumberOfBlockControlWindows; + UINT64 SizeOfBlockControlWindow; + UINT64 CommandRegisterOffsetInBlockControlWindow; + UINT64 SizeOfCommandRegisterInBlockControlWindows; + UINT64 StatusRegisterOffsetInBlockControlWindow; + UINT64 SizeOfStatusRegisterInBlockControlWindows; + UINT16 NVDIMMControlRegionFlag; + UINT8 Reserved_74[6]; +} EFI_ACPI_6_3_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE; + +// +// Definition for NVDIMM Block Data Window Region Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 NumberOfBlockDataWindows; + UINT64 BlockDataWindowStartOffset; + UINT64 SizeOfBlockDataWindow; + UINT64 BlockAccessibleMemoryCapacity; + UINT64 BeginningAddressOfFirstBlockInBlockAccessibleMemory; +} EFI_ACPI_6_3_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE; + +// +// Definition for Flush Hint Address Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_3_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NumberOfFlushHintAddresses; + UINT8 Reserved_10[6]; + // UINT64 FlushHintAddress[NumberOfFlushHintAddresses]; +} EFI_ACPI_6_3_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE; + +// +// Definition for Platform Capabilities Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT8 HighestValidCapability; + UINT8 Reserved_5[3]; + UINT32 Capabilities; + UINT8 Reserved_12[4]; +} EFI_ACPI_6_3_NFIT_PLATFORM_CAPABILITIES_STRUCTURE; + +#define EFI_ACPI_6_3_NFIT_PLATFORM_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT0 +#define EFI_ACPI_6_3_NFIT_PLATFORM_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT1 +#define EFI_ACPI_6_3_NFIT_PLATFORM_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT2 + +/// +/// Secure DEVices Table (SDEV) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_3_SECURE_DEVICES_TABLE_HEADER; + +/// +/// SDEV Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_SECURE_DEVICES_TABLE_REVISION 0x01 + +/// +/// Secure Devcice types +/// +#define EFI_ACPI_6_3_SDEV_TYPE_PCIE_ENDPOINT_DEVICE 0x01 +#define EFI_ACPI_6_3_SDEV_TYPE_ACPI_NAMESPACE_DEVICE 0x00 + +/// +/// Secure Devcice flags +/// +#define EFI_ACPI_6_3_SDEV_FLAG_ALLOW_HANDOFF BIT0 + +/// +/// SDEV Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; +} EFI_ACPI_6_3_SDEV_STRUCTURE_HEADER; + +/// +/// PCIe Endpoint Device based Secure Device Structure +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; + UINT16 PciSegmentNumber; + UINT16 StartBusNumber; + UINT16 PciPathOffset; + UINT16 PciPathLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; +} EFI_ACPI_6_3_SDEV_STRUCTURE_PCIE_ENDPOINT_DEVICE; + +/// +/// ACPI_NAMESPACE_DEVICE based Secure Device Structure +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; + UINT16 DeviceIdentifierOffset; + UINT16 DeviceIdentifierLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; +} EFI_ACPI_6_3_SDEV_STRUCTURE_ACPI_NAMESPACE_DEVICE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_6_3_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_6_3_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_3_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_6_3_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_6_3_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_6_3_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_6_3_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_6_3_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + UINT8 Timestamp[8]; +} EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0300 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_6_3_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_6_3_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_6_3_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR 0x09 +#define EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_VERSION_2 0x0A +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK 0x0B + +// +// Error Source structure flags. +// +#define EFI_ACPI_6_3_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_6_3_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) +#define EFI_ACPI_6_3_ERROR_SOURCE_FLAG_GHES_ASSIST (1 << 2) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_6_3_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_6_3_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_6_3_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_CMCI 0x05 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_MCE 0x06 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_GPIO_SIGNAL 0x07 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEA 0x08 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEI 0x09 +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_GSIV 0x0A +#define EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_SOFTWARE_DELEGATED_EXCEPTION 0x0B + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_3_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_6_3_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_6_3_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_3_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_3_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Hardware Error Source Version 2 Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE ReadAckRegister; + UINT64 ReadAckPreserve; + UINT64 ReadAckWrite; +} EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_6_3_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_3_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// IA-32 Architecture Deferred Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_3_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_3_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK_STRUCTURE; + +/// +/// HMAT - Heterogeneous Memory Attribute Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[4]; +} EFI_ACPI_6_3_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER; + +/// +/// HMAT Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_REVISION 0x02 + +/// +/// HMAT types +/// +#define EFI_ACPI_6_3_HMAT_TYPE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES 0x00 +#define EFI_ACPI_6_3_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO 0x01 +#define EFI_ACPI_6_3_HMAT_TYPE_MEMORY_SIDE_CACHE_INFO 0x02 + +/// +/// HMAT Structure Header +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; +} EFI_ACPI_6_3_HMAT_STRUCTURE_HEADER; + +/// +/// Memory Proximity Domain Attributes Structure flags +/// +typedef struct { + UINT16 InitiatorProximityDomainValid : 1; + UINT16 Reserved : 15; +} EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES_FLAGS; + +/// +/// Memory Proximity Domain Attributes Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES_FLAGS Flags; + UINT8 Reserved1[2]; + UINT32 InitiatorProximityDomain; + UINT32 MemoryProximityDomain; + UINT8 Reserved2[20]; +} EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES; + +/// +/// System Locality Latency and Bandwidth Information Structure flags +/// +typedef struct { + UINT8 MemoryHierarchy : 4; + UINT8 Reserved : 4; +} EFI_ACPI_6_3_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS; + +/// +/// System Locality Latency and Bandwidth Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_3_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS Flags; + UINT8 DataType; + UINT8 Reserved1[2]; + UINT32 NumberOfInitiatorProximityDomains; + UINT32 NumberOfTargetProximityDomains; + UINT8 Reserved2[4]; + UINT64 EntryBaseUnit; +} EFI_ACPI_6_3_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO; + +/// +/// Memory Side Cache Information Structure cache attributes +/// +typedef struct { + UINT32 TotalCacheLevels : 4; + UINT32 CacheLevel : 4; + UINT32 CacheAssociativity : 4; + UINT32 WritePolicy : 4; + UINT32 CacheLineSize : 16; +} EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES; + +/// +/// Memory Side Cache Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + UINT32 MemoryProximityDomain; + UINT8 Reserved1[4]; + UINT64 MemorySideCacheSize; + EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES CacheAttributes; + UINT8 Reserved2[2]; + UINT16 NumberOfSmbiosHandles; +} EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_6_3_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_6_3_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_6_3_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_6_3_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_6_3_ERST_END_OPERATION 0x03 +#define EFI_ACPI_6_3_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_6_3_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_3_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_3_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_3_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_6_3_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_6_3_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_6_3_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_6_3_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_6_3_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_6_3_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F +#define EFI_ACPI_6_3_ERST_GET_EXECUTE_OPERATION_TIMINGS 0x10 + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_6_3_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_3_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_6_3_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_6_3_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_6_3_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_6_3_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_6_3_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_6_3_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_3_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_3_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_3_ERST_NOOP 0x04 +#define EFI_ACPI_6_3_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_6_3_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_6_3_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_6_3_ERST_ADD 0x08 +#define EFI_ACPI_6_3_ERST_SUBTRACT 0x09 +#define EFI_ACPI_6_3_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_6_3_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_6_3_ERST_STALL 0x0C +#define EFI_ACPI_6_3_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_6_3_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_6_3_ERST_GOTO 0x0F +#define EFI_ACPI_6_3_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_6_3_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_6_3_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_6_3_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_3_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_6_3_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_6_3_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_6_3_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_6_3_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_6_3_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_6_3_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_6_3_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_3_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_3_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_3_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_6_3_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_3_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_6_3_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_6_3_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_6_3_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_6_3_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_6_3_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_6_3_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_6_3_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_6_3_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_6_3_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_6_3_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_6_3_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_6_3_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_6_3_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_6_3_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_6_3_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_3_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_3_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_3_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_6_3_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_3_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_6_3_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_6_3_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x02 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_6_3_PCCT_FLAGS_PLATFORM_INTERRUPT BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_GENERIC 0x00 +#define EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS 0x01 +#define EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS 0x02 +#define EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC 0x03 +#define EFI_ACPI_6_3_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC 0x04 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_6_3_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_3_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 NotifyOnCompletion : 1; +} EFI_ACPI_6_3_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 PlatformInterrupt : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_6_3_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_6_3_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_6_3_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_6_3_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +#define EFI_ACPI_6_3_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_POLARITY BIT0 +#define EFI_ACPI_6_3_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE BIT1 + +/// +/// Type 1 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_3_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 2 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckWrite; +} EFI_ACPI_6_3_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 3 Extended PCC Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT32 AddressLength; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT32 MinimumRequestTurnaroundTime; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckSet; + UINT8 Reserved1[8]; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE CommandCompleteCheckRegister; + UINT64 CommandCompleteCheckMask; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE CommandCompleteUpdateRegister; + UINT64 CommandCompleteUpdatePreserve; + UINT64 CommandCompleteUpdateSet; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE ErrorStatusRegister; + UINT64 ErrorStatusMask; +} EFI_ACPI_6_3_PCCT_SUBSPACE_3_EXTENDED_PCC; + +/// +/// Type 4 Extended PCC Subspace Structure +/// +typedef EFI_ACPI_6_3_PCCT_SUBSPACE_3_EXTENDED_PCC EFI_ACPI_6_3_PCCT_SUBSPACE_4_EXTENDED_PCC; + +#define EFI_ACPI_6_3_PCCT_MASTER_SLAVE_COMMUNICATIONS_CHANNEL_FLAGS_NOTIFY_ON_COMPLETION BIT0 + +typedef struct { + UINT32 Signature; + UINT32 Flags; + UINT32 Length; + UINT32 Command; +} EFI_ACPI_6_3_PCCT_EXTENDED_PCC_SHARED_MEMORY_REGION_HEADER; + +/// +/// Platform Debug Trigger Table (PDTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 TriggerCount; + UINT8 Reserved[3]; + UINT32 TriggerIdentifierArrayOffset; +} EFI_ACPI_6_3_PLATFORM_DEBUG_TRIGGER_TABLE_HEADER; + +/// +/// PDTT Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_PLATFORM_DEBUG_TRIGGER_TABLE_REVISION 0x00 + +/// +/// PDTT Platform Communication Channel Identifier Structure +/// +typedef struct { + UINT16 SubChannelIdentifer : 8; + UINT16 Runtime : 1; + UINT16 WaitForCompletion : 1; + UINT16 TriggerOrder : 1; + UINT16 Reserved : 5; +} EFI_ACPI_6_3_PDTT_PCC_IDENTIFIER; + +/// +/// PCC Commands Codes used by Platform Debug Trigger Table +/// +#define EFI_ACPI_6_3_PDTT_PCC_COMMAND_DOORBELL_ONLY 0x00 +#define EFI_ACPI_6_3_PDTT_PCC_COMMAND_VENDOR_SPECIFIC 0x01 + +/// +/// PPTT Platform Communication Channel +/// +typedef EFI_ACPI_6_3_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER EFI_ACPI_6_3_PDTT_PCC; + +/// +/// Processor Properties Topology Table (PPTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER; + +/// +/// PPTT Revision (as defined in ACPI 6.3 spec.) +/// +#define EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION 0x02 + +/// +/// PPTT types +/// +#define EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR 0x00 +#define EFI_ACPI_6_3_PPTT_TYPE_CACHE 0x01 +#define EFI_ACPI_6_3_PPTT_TYPE_ID 0x02 + +/// +/// PPTT Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; +} EFI_ACPI_6_3_PPTT_STRUCTURE_HEADER; + +/// +/// For PPTT struct processor flags +/// +#define EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL 0x0 +#define EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL 0x1 +#define EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_PROCESSOR_ID_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_PROCESSOR_IS_NOT_THREAD 0x0 +#define EFI_ACPI_6_3_PPTT_PROCESSOR_IS_THREAD 0x1 +#define EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF 0x0 +#define EFI_ACPI_6_3_PPTT_NODE_IS_LEAF 0x1 +#define EFI_ACPI_6_3_PPTT_IMPLEMENTATION_NOT_IDENTICAL 0x0 +#define EFI_ACPI_6_3_PPTT_IMPLEMENTATION_IDENTICAL 0x1 + +/// +/// Processor hierarchy node structure flags +/// +typedef struct { + UINT32 PhysicalPackage : 1; + UINT32 AcpiProcessorIdValid : 1; + UINT32 ProcessorIsAThread : 1; + UINT32 NodeIsALeaf : 1; + UINT32 IdenticalImplementation : 1; + UINT32 Reserved : 27; +} EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR_FLAGS; + +/// +/// Processor hierarchy node structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR_FLAGS Flags; + UINT32 Parent; + UINT32 AcpiProcessorId; + UINT32 NumberOfPrivateResources; +} EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR; + +/// +/// For PPTT struct cache flags +/// +#define EFI_ACPI_6_3_PPTT_CACHE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_CACHE_SIZE_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_NUMBER_OF_SETS_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_NUMBER_OF_SETS_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_ASSOCIATIVITY_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_ASSOCIATIVITY_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_ALLOCATION_TYPE_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_ALLOCATION_TYPE_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_CACHE_TYPE_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_CACHE_TYPE_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_WRITE_POLICY_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_WRITE_POLICY_VALID 0x1 +#define EFI_ACPI_6_3_PPTT_LINE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_3_PPTT_LINE_SIZE_VALID 0x1 + +/// +/// Cache Type Structure flags +/// +typedef struct { + UINT32 SizePropertyValid : 1; + UINT32 NumberOfSetsValid : 1; + UINT32 AssociativityValid : 1; + UINT32 AllocationTypeValid : 1; + UINT32 CacheTypeValid : 1; + UINT32 WritePolicyValid : 1; + UINT32 LineSizeValid : 1; + UINT32 Reserved : 25; +} EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE_FLAGS; + +/// +/// For cache attributes +/// +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_ALLOCATION_READ 0x0 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_ALLOCATION_WRITE 0x1 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE 0x2 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_CACHE_TYPE_DATA 0x0 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_CACHE_TYPE_INSTRUCTION 0x1 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_CACHE_TYPE_UNIFIED 0x2 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK 0x0 +#define EFI_ACPI_6_3_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_THROUGH 0x1 + +/// +/// Cache Type Structure cache attributes +/// +typedef struct { + UINT8 AllocationType : 2; + UINT8 CacheType : 2; + UINT8 WritePolicy : 1; + UINT8 Reserved : 3; +} EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE_ATTRIBUTES; + +/// +/// Cache Type Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE_FLAGS Flags; + UINT32 NextLevelOfCache; + UINT32 Size; + UINT32 NumberOfSets; + UINT8 Associativity; + EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE_ATTRIBUTES Attributes; + UINT16 LineSize; +} EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE; + +/// +/// ID structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 VendorId; + UINT64 Level1Id; + UINT64 Level2Id; + UINT16 MajorRev; + UINT16 MinorRev; + UINT16 SpinRev; +} EFI_ACPI_6_3_PPTT_STRUCTURE_ID; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CDIT" Component Distance Information Table +/// +#define EFI_ACPI_6_3_COMPONENT_DISTANCE_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('C', 'D', 'I', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_6_3_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "CRAT" Component Resource Attribute Table +/// +#define EFI_ACPI_6_3_COMPONENT_RESOURCE_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('C', 'R', 'A', 'T') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_6_3_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_6_3_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_6_3_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_6_3_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "HMAT" Heterogeneous Memory Attribute Table +/// +#define EFI_ACPI_6_3_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('H', 'M', 'A', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_6_3_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_6_3_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "NFIT" NVDIMM Firmware Interface Table +/// +#define EFI_ACPI_6_3_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('N', 'F', 'I', 'T') + +/// +/// "PDTT" Platform Debug Trigger Table +/// +#define EFI_ACPI_6_3_PLATFORM_DEBUG_TRIGGER_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'D', 'T', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_6_3_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PPTT" Processor Properties Topology Table +/// +#define EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'P', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_6_3_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_6_3_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_6_3_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SDEV" Secure DEVices Table +/// +#define EFI_ACPI_6_3_SECURE_DEVICES_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'V') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_6_3_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_6_3_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_6_3_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_6_3_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_6_3_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DPPT" DMA Protection Policy Table +/// +#define EFI_ACPI_6_3_DMA_PROTECTION_POLICY_TABLE_SIGNATURE SIGNATURE_32('D', 'P', 'P', 'T') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_6_3_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_6_3_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_6_3_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_6_3_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IORT" I/O Remapping Table +/// +#define EFI_ACPI_6_3_IO_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('I', 'O', 'R', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_6_3_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_6_3_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_6_3_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_6_3_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_6_3_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_6_3_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "SDEI" Software Delegated Exceptions Interface Table +/// +#define EFI_ACPI_6_3_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'I') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_6_3_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Concole Redirection Table +/// +#define EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_6_3_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "STAO" _STA Override Table +/// +#define EFI_ACPI_6_3_STA_OVERRIDE_TABLE_SIGNATURE SIGNATURE_32('S', 'T', 'A', 'O') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_6_3_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_6_3_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_6_3_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_6_3_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_6_3_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_6_3_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_6_3_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +/// +/// "WSMT" Windows SMM Security Mitigation Table +/// +#define EFI_ACPI_6_3_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE SIGNATURE_32('W', 'S', 'M', 'T') + +/// +/// "XENV" Xen Project Table +/// +#define EFI_ACPI_6_3_XEN_PROJECT_TABLE_SIGNATURE SIGNATURE_32('X', 'E', 'N', 'V') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi64.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi64.h new file mode 100644 index 0000000..16ea03e --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi64.h @@ -0,0 +1,3162 @@ +/** @file + ACPI 6.4 definitions from the ACPI Specification Revision 6.4 Jan, 2021. + + Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2021, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPI_6_4_H_ +#define ACPI_6_4_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 6.4 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_6_4_SYSTEM_MEMORY 0x00 +#define EFI_ACPI_6_4_SYSTEM_IO 0x01 +#define EFI_ACPI_6_4_PCI_CONFIGURATION_SPACE 0x02 +#define EFI_ACPI_6_4_EMBEDDED_CONTROLLER 0x03 +#define EFI_ACPI_6_4_SMBUS 0x04 +#define EFI_ACPI_6_4_SYSTEM_CMOS 0x05 +#define EFI_ACPI_6_4_PCI_BAR_TARGET 0x06 +#define EFI_ACPI_6_4_IPMI 0x07 +#define EFI_ACPI_6_4_GENERAL_PURPOSE_IO 0x08 +#define EFI_ACPI_6_4_GENERIC_SERIAL_BUS 0x09 +#define EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_6_4_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_6_4_UNDEFINED 0 +#define EFI_ACPI_6_4_BYTE 1 +#define EFI_ACPI_6_4_WORD 2 +#define EFI_ACPI_6_4_DWORD 3 +#define EFI_ACPI_6_4_QWORD 4 + +// +// ACPI 6.4 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_6_4_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 6.4) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_4_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; + UINT64 HypervisorVendorIdentity; +} EFI_ACPI_6_4_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x06 +#define EFI_ACPI_6_4_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x04 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_6_4_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_6_4_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_6_4_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_6_4_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_6_4_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_6_4_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_6_4_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_6_4_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_6_4_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_4_LEGACY_DEVICES BIT0 +#define EFI_ACPI_6_4_8042 BIT1 +#define EFI_ACPI_6_4_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_6_4_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_6_4_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_6_4_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_4_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_6_4_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_4_WBINVD BIT0 +#define EFI_ACPI_6_4_WBINVD_FLUSH BIT1 +#define EFI_ACPI_6_4_PROC_C1 BIT2 +#define EFI_ACPI_6_4_P_LVL2_UP BIT3 +#define EFI_ACPI_6_4_PWR_BUTTON BIT4 +#define EFI_ACPI_6_4_SLP_BUTTON BIT5 +#define EFI_ACPI_6_4_FIX_RTC BIT6 +#define EFI_ACPI_6_4_RTC_S4 BIT7 +#define EFI_ACPI_6_4_TMR_VAL_EXT BIT8 +#define EFI_ACPI_6_4_DCK_CAP BIT9 +#define EFI_ACPI_6_4_RESET_REG_SUP BIT10 +#define EFI_ACPI_6_4_SEALED_CASE BIT11 +#define EFI_ACPI_6_4_HEADLESS BIT12 +#define EFI_ACPI_6_4_CPU_SW_SLP BIT13 +#define EFI_ACPI_6_4_PCI_EXP_WAK BIT14 +#define EFI_ACPI_6_4_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_6_4_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_6_4_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_6_4_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_6_4_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_6_4_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_6_4_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_6_4_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_4_S4BIOS_F BIT0 +#define EFI_ACPI_6_4_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_4_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_6_4_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_6_4_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_6_4_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x05 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_4_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x10 and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_6_4_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_6_4_IO_APIC 0x01 +#define EFI_ACPI_6_4_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_6_4_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_6_4_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_6_4_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_6_4_IO_SAPIC 0x06 +#define EFI_ACPI_6_4_LOCAL_SAPIC 0x07 +#define EFI_ACPI_6_4_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_6_4_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_6_4_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_6_4_GIC 0x0B +#define EFI_ACPI_6_4_GICD 0x0C +#define EFI_ACPI_6_4_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_6_4_GICR 0x0E +#define EFI_ACPI_6_4_GIC_ITS 0x0F +#define EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP 0x10 + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_6_4_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_LOCAL_APIC_ENABLED BIT0 +#define EFI_ACPI_6_4_LOCAL_APIC_ONLINE_CAPABLE BIT1 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_6_4_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_6_4_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_6_4_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_4_POLARITY (3 << 0) +#define EFI_ACPI_6_4_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_6_4_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_6_4_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_6_4_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_6_4_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_6_4_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_6_4_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_4_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_6_4_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_6_4_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; + UINT8 ProcessorPowerEfficiencyClass; + UINT8 Reserved2; + UINT16 SpeOverflowInterrupt; +} EFI_ACPI_6_4_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_GIC_ENABLED BIT0 +#define EFI_ACPI_6_4_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_6_4_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_6_4_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_6_4_GIC_V1 0x01 +#define EFI_ACPI_6_4_GIC_V2 0x02 +#define EFI_ACPI_6_4_GIC_V3 0x03 +#define EFI_ACPI_6_4_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_6_4_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_6_4_GICR_STRUCTURE; + +/// +/// GIC Interrupt Translation Service Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicItsId; + UINT64 PhysicalBaseAddress; + UINT32 Reserved2; +} EFI_ACPI_6_4_GIC_ITS_STRUCTURE; + +/// +/// Multiprocessor Wakeup Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 MailBoxVersion; + UINT32 Reserved; + UINT64 MailBoxAddress; +} EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE; + +/// +/// Multiprocessor Wakeup Mailbox Structure +/// +typedef struct { + UINT16 Command; + UINT16 Reserved; + UINT32 AcpiId; + UINT64 WakeupVector; + UINT8 ReservedForOs[2032]; + UINT8 ReservedForFirmware[2048]; +} EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_MAILBOX_STRUCTURE; + +#define EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_NOOP 0x0000 +#define EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_WAKEUP 0x0001 + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_6_4_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_6_4_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x06 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_4_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_6_4_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_6_4_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_6_4_GICC_AFFINITY 0x03 +#define EFI_ACPI_6_4_GIC_ITS_AFFINITY 0x04 +#define EFI_ACPI_6_4_GENERIC_INITIATOR_AFFINITY 0x05 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_6_4_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_6_4_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_6_4_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_6_4_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_6_4_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_6_4_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_6_4_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_GICC_ENABLED (1 << 0) + +/// +/// GIC Interrupt Translation Service (ITS) Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT8 Reserved[2]; + UINT32 ItsId; +} EFI_ACPI_6_4_GIC_ITS_AFFINITY_STRUCTURE; + +// +// Generic Initiator Affinity Structure Device Handle Types +// All other values between 0x02 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_4_ACPI_DEVICE_HANDLE 0x00 +#define EFI_ACPI_6_4_PCI_DEVICE_HANDLE 0x01 + +/// +/// Device Handle - ACPI +/// +typedef struct { + UINT64 AcpiHid; + UINT32 AcpiUid; + UINT8 Reserved[4]; +} EFI_ACPI_6_4_DEVICE_HANDLE_ACPI; + +/// +/// Device Handle - PCI +/// +typedef struct { + UINT16 PciSegment; + UINT16 PciBdfNumber; + UINT8 Reserved[12]; +} EFI_ACPI_6_4_DEVICE_HANDLE_PCI; + +/// +/// Device Handle +/// +typedef union { + EFI_ACPI_6_4_DEVICE_HANDLE_ACPI Acpi; + EFI_ACPI_6_4_DEVICE_HANDLE_PCI Pci; +} EFI_ACPI_6_4_DEVICE_HANDLE; + +/// +/// Generic Initiator Affinity Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1; + UINT8 DeviceHandleType; + UINT32 ProximityDomain; + EFI_ACPI_6_4_DEVICE_HANDLE DeviceHandle; + UINT32 Flags; + UINT8 Reserved2[4]; +} EFI_ACPI_6_4_GENERIC_INITIATOR_AFFINITY_STRUCTURE; + +/// +/// Generic Initiator Affinity Structure Flags. All other bits are reserved +/// and must be 0. +/// +#define EFI_ACPI_6_4_GENERIC_INITIATOR_AFFINITY_STRUCTURE_ENABLED BIT0 +#define EFI_ACPI_6_4_GENERIC_INITIATOR_AFFINITY_STRUCTURE_ARCHITECTURAL_TRANSACTIONS BIT1 + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_6_4_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_6_4_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_6_4_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_6_4_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_6_4_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_6_4_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_6_4_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_6_4_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_6_4_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_6_4_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED BIT0 +#define EFI_ACPI_6_4_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED_AND_EXPOSED_TO_SOFTWARE BIT1 +#define EFI_ACPI_6_4_RASF_PLATFORM_RAS_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT2 +#define EFI_ACPI_6_4_RASF_PLATFORM_RAS_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT3 +#define EFI_ACPI_6_4_RASF_PLATFORM_RAS_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT4 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_6_4_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_6_4_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_6_4_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_6_4_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_6_4_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_6_4_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_6_4_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_6_4_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_4_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_4_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Platform Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 NumberOfMemoryDevices; + // EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[NumberOfMemoryDevices]; +} EFI_ACPI_6_4_PLATFORM_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_MEMORY_TOPOLOGY_TABLE_REVISION 0x02 + +/// +/// Common Memory Device. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; + UINT32 NumberOfMemoryDevices; + // UINT8 TypeSpecificData[]; + // EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[NumberOfMemoryDevices]; +} EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE; + +/// +/// Memory Device Type. +/// +#define EFI_ACPI_6_4_PMTT_MEMORY_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_6_4_PMTT_MEMORY_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_6_4_PMTT_MEMORY_DEVICE_TYPE_DIMM 0x2 +#define EFI_ACPI_6_4_PMTT_MEMORY_DEVICE_TYPE_VENDOR_SPECIFIC_TYPE 0xFF + +/// +/// Socket Type Data. +/// +typedef struct { + EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[]; +} EFI_ACPI_6_4_PMTT_SOCKET_TYPE_DATA; + +/// +/// Memory Controller Type Data. +/// +typedef struct { + EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT16 MemoryControllerIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[]; +} EFI_ACPI_6_4_PMTT_MEMORY_CONTROLLER_TYPE_DATA; + +/// +/// DIMM Type Specific Data. +/// +typedef struct { + EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT32 SmbiosHandle; +} EFI_ACPI_6_4_PMTT_DIMM_TYPE_SPECIFIC_DATA; + +/// +/// Vendor Specific Type Data. +/// +typedef struct { + EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT8 TypeUuid[16]; + // EFI_ACPI_6_4_PMTT_VENDOR_SPECIFIC_TYPE_DATA VendorSpecificData[]; + // EFI_ACPI_6_4_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[]; +} EFI_ACPI_6_4_PMTT_VENDOR_SPECIFIC_TYPE_DATA; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:3] = Reserved (must be zero) + /// Bits[2:1] = Orientation Offset. These bits describe the clockwise + /// degree offset from the image's default orientation. + /// [00] = 0, no offset + /// [01] = 90 + /// [10] = 180 + /// [11] = 270 + /// Bit [0] = Displayed. A one indicates the boot image graphic is + /// displayed. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_6_4_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_6_4_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_6_4_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_6_4_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_6_4_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_6_4_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_6_4_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_6_4_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_6_4_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_6_4_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_6_4_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_6_4_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_6_4_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_6_4_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_6_4_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_6_4_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_6_4_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_4_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_6_4_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_6_4_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior towhen the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_6_4_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_6_4_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_4_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_6_4_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_4_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_6_4_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_6_4_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_6_4_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_4_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; + UINT32 VirtualPL2TimerGSIV; + UINT32 VirtualPL2TimerFlags; +} EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x03 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_4_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_4_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_6_4_GTDT_GT_BLOCK 0 +#define EFI_ACPI_6_4_GTDT_ARM_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_6_4_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_4_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_6_4_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// Arm Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_6_4_GTDT_ARM_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// Arm Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_4_GTDT_ARM_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_4_GTDT_ARM_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_4_GTDT_ARM_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +// +// NVDIMM Firmware Interface Table definition. +// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_4_NVDIMM_FIRMWARE_INTERFACE_TABLE; + +// +// NFIT Version (as defined in ACPI 6.4 spec.) +// +#define EFI_ACPI_6_4_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION 0x1 + +// +// Definition for NFIT Table Structure Types +// +#define EFI_ACPI_6_4_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE 0 +#define EFI_ACPI_6_4_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE_TYPE 1 +#define EFI_ACPI_6_4_NFIT_INTERLEAVE_STRUCTURE_TYPE 2 +#define EFI_ACPI_6_4_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE_TYPE 3 +#define EFI_ACPI_6_4_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE_TYPE 4 +#define EFI_ACPI_6_4_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE_TYPE 5 +#define EFI_ACPI_6_4_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE_TYPE 6 +#define EFI_ACPI_6_4_NFIT_PLATFORM_CAPABILITIES_STRUCTURE_TYPE 7 + +// +// Definition for NFIT Structure Header +// +typedef struct { + UINT16 Type; + UINT16 Length; +} EFI_ACPI_6_4_NFIT_STRUCTURE_HEADER; + +// +// Definition for System Physical Address Range Structure +// +#define EFI_ACPI_6_4_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_CONTROL_REGION_FOR_MANAGEMENT BIT0 +#define EFI_ACPI_6_4_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_PROXIMITY_DOMAIN_VALID BIT1 +#define EFI_ACPI_6_4_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_SPA_LOCATION_COOKIE_VALID BIT2 + +#define EFI_ACPI_6_4_NFIT_GUID_VOLATILE_MEMORY_REGION { 0x7305944F, 0xFDDA, 0x44E3, { 0xB1, 0x6C, 0x3F, 0x22, 0xD2, 0x52, 0xE5, 0xD0 }} +#define EFI_ACPI_6_4_NFIT_GUID_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_REGION { 0x66F0D379, 0xB4F3, 0x4074, { 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB }} +#define EFI_ACPI_6_4_NFIT_GUID_NVDIMM_CONTROL_REGION { 0x92F701F6, 0x13B4, 0x405D, { 0x91, 0x0B, 0x29, 0x93, 0x67, 0xE8, 0x23, 0x4C }} +#define EFI_ACPI_6_4_NFIT_GUID_NVDIMM_BLOCK_DATA_WINDOW_REGION { 0x91AF0530, 0x5D86, 0x470E, { 0xA6, 0xB0, 0x0A, 0x2D, 0xB9, 0x40, 0x82, 0x49 }} +#define EFI_ACPI_6_4_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_VOLATILE { 0x77AB535A, 0x45FC, 0x624B, { 0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }} +#define EFI_ACPI_6_4_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_VOLATILE { 0x3D5ABD30, 0x4175, 0x87CE, { 0x6D, 0x64, 0xD2, 0xAD, 0xE5, 0x23, 0xC4, 0xBB }} +#define EFI_ACPI_6_4_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_PERSISTENT { 0x5CEA02C9, 0x4D07, 0x69D3, { 0x26, 0x9F ,0x44, 0x96, 0xFB, 0xE0, 0x96, 0xF9 }} +#define EFI_ACPI_6_4_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_PERSISTENT { 0x08018188, 0x42CD, 0xBB48, { 0x10, 0x0F, 0x53, 0x87, 0xD5, 0x3D, 0xED, 0x3D }} + +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 SPARangeStructureIndex; + UINT16 Flags; + UINT32 Reserved_8; + UINT32 ProximityDomain; + GUID AddressRangeTypeGUID; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; + UINT64 AddressRangeMemoryMappingAttribute; + UINT64 SPALocationCookie; +} EFI_ACPI_6_4_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE; + +// +// Definition for Memory Device to System Physical Address Range Mapping Structure +// +typedef struct { + UINT32 DIMMNumber : 4; + UINT32 MemoryChannelNumber : 4; + UINT32 MemoryControllerID : 4; + UINT32 SocketID : 4; + UINT32 NodeControllerID : 12; + UINT32 Reserved_28 : 4; +} EFI_ACPI_6_4_NFIT_DEVICE_HANDLE; + +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_PREVIOUS_SAVE_FAIL BIT0 +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_LAST_RESTORE_FAIL BIT1 +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_PLATFORM_FLUSH_FAIL BIT2 +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_NOT_ARMED_PRIOR_TO_OSPM_HAND_OFF BIT3 +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_SMART_HEALTH_EVENTS_PRIOR_OSPM_HAND_OFF BIT4 +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_ENABLED_TO_NOTIFY_OSPM_ON_SMART_HEALTH_EVENTS BIT5 +#define EFI_ACPI_6_4_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_NOT_MAP_NVDIMM_TO_SPA BIT6 + +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_4_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NVDIMMPhysicalID; + UINT16 NVDIMMRegionID; + UINT16 SPARangeStructureIndex; + UINT16 NVDIMMControlRegionStructureIndex; + UINT64 NVDIMMRegionSize; + UINT64 RegionOffset; + UINT64 NVDIMMPhysicalAddressRegionBase; + UINT16 InterleaveStructureIndex; + UINT16 InterleaveWays; + UINT16 NVDIMMStateFlags; + UINT16 Reserved_46; +} EFI_ACPI_6_4_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE; + +// +// Definition for Interleave Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 InterleaveStructureIndex; + UINT16 Reserved_6; + UINT32 NumberOfLines; + UINT32 LineSize; + // UINT32 LineOffset[NumberOfLines]; +} EFI_ACPI_6_4_NFIT_INTERLEAVE_STRUCTURE; + +// +// Definition for SMBIOS Management Information Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT32 Reserved_4; + // UINT8 Data[]; +} EFI_ACPI_6_4_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE; + +// +// Definition for NVDIMM Control Region Structure +// +#define EFI_ACPI_6_4_NFIT_NVDIMM_CONTROL_REGION_VALID_FIELDS_MANUFACTURING BIT0 + +#define EFI_ACPI_6_4_NFIT_NVDIMM_CONTROL_REGION_FLAGS_BLOCK_DATA_WINDOWS_BUFFERED BIT0 + +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT16 SubsystemVendorID; + UINT16 SubsystemDeviceID; + UINT16 SubsystemRevisionID; + UINT8 ValidFields; + UINT8 ManufacturingLocation; + UINT16 ManufacturingDate; + UINT8 Reserved_22[2]; + UINT32 SerialNumber; + UINT16 RegionFormatInterfaceCode; + UINT16 NumberOfBlockControlWindows; + UINT64 SizeOfBlockControlWindow; + UINT64 CommandRegisterOffsetInBlockControlWindow; + UINT64 SizeOfCommandRegisterInBlockControlWindows; + UINT64 StatusRegisterOffsetInBlockControlWindow; + UINT64 SizeOfStatusRegisterInBlockControlWindows; + UINT16 NVDIMMControlRegionFlag; + UINT8 Reserved_74[6]; +} EFI_ACPI_6_4_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE; + +// +// Definition for NVDIMM Block Data Window Region Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 NumberOfBlockDataWindows; + UINT64 BlockDataWindowStartOffset; + UINT64 SizeOfBlockDataWindow; + UINT64 BlockAccessibleMemoryCapacity; + UINT64 BeginningAddressOfFirstBlockInBlockAccessibleMemory; +} EFI_ACPI_6_4_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE; + +// +// Definition for Flush Hint Address Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_4_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NumberOfFlushHintAddresses; + UINT8 Reserved_10[6]; + // UINT64 FlushHintAddress[NumberOfFlushHintAddresses]; +} EFI_ACPI_6_4_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE; + +// +// Definition for Platform Capabilities Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT8 HighestValidCapability; + UINT8 Reserved_5[3]; + UINT32 Capabilities; + UINT8 Reserved_12[4]; +} EFI_ACPI_6_4_NFIT_PLATFORM_CAPABILITIES_STRUCTURE; + +#define EFI_ACPI_6_4_NFIT_PLATFORM_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT0 +#define EFI_ACPI_6_4_NFIT_PLATFORM_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT1 +#define EFI_ACPI_6_4_NFIT_PLATFORM_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT2 + +/// +/// Secure DEVices Table (SDEV) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_4_SECURE_DEVICES_TABLE_HEADER; + +/// +/// SDEV Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_SECURE_DEVICES_TABLE_REVISION 0x01 + +/// +/// Secure Device types +/// +#define EFI_ACPI_6_4_SDEV_TYPE_ACPI_NAMESPACE_DEVICE 0x00 +#define EFI_ACPI_6_4_SDEV_TYPE_PCIE_ENDPOINT_DEVICE 0x01 + +/// +/// Secure Device flags +/// +#define EFI_ACPI_6_4_SDEV_FLAG_ALLOW_HANDOFF BIT0 +#define EFI_ACPI_6_4_SDEV_FLAG_SECURE_ACCESS_COMPONENTS_PRESENT BIT1 + +/// +/// SDEV Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; +} EFI_ACPI_6_4_SDEV_STRUCTURE_HEADER; + +/// +/// ACPI_NAMESPACE_DEVICE based Secure Device Structure +/// +typedef struct { + EFI_ACPI_6_4_SDEV_STRUCTURE_HEADER Header; + UINT16 DeviceIdentifierOffset; + UINT16 DeviceIdentifierLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; + UINT16 SecureAccessComponentsOffset; + UINT16 SecureAccessComponentsLength; +} EFI_ACPI_6_4_SDEV_STRUCTURE_ACPI_NAMESPACE_DEVICE; + +/// +/// Secure Access Component Types +/// +#define EFI_ACPI_6_4_SDEV_SECURE_ACCESS_COMPONENT_TYPE_IDENTIFICATION 0x00 +#define EFI_ACPI_6_4_SDEV_SECURE_ACCESS_COMPONENT_TYPE_MEMORY 0x01 + +/// +/// Identification Based Secure Access Component +/// +typedef struct { + EFI_ACPI_6_4_SDEV_STRUCTURE_HEADER Header; + UINT16 HardwareIdentifierOffset; + UINT16 HardwareIdentifierLength; + UINT16 SubsystemIdentifierOffset; + UINT16 SubsystemIdentifierLength; + UINT16 HardwareRevision; + UINT8 HardwareRevisionPresent; + UINT8 ClassCodePresent; + UINT8 PciCompatibleBaseClass; + UINT8 PciCompatibleSubClass; + UINT8 PciCompatibleProgrammingInterface; +} EFI_ACPI_6_4_SDEV_SECURE_ACCESS_COMPONENT_IDENTIFICATION_STRUCTURE; + +/// +/// Memory-based Secure Access Component +/// +typedef struct { + EFI_ACPI_6_4_SDEV_STRUCTURE_HEADER Header; + UINT32 Reserved; + UINT64 MemoryAddressBase; + UINT64 MemoryLength; +} EFI_ACPI_6_4_SDEV_SECURE_ACCESS_COMPONENT_MEMORY_STRUCTURE; + +/// +/// PCIe Endpoint Device based Secure Device Structure +/// +typedef struct { + EFI_ACPI_6_4_SDEV_STRUCTURE_HEADER Header; + UINT16 PciSegmentNumber; + UINT16 StartBusNumber; + UINT16 PciPathOffset; + UINT16 PciPathLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; +} EFI_ACPI_6_4_SDEV_STRUCTURE_PCIE_ENDPOINT_DEVICE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_6_4_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_6_4_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_6_4_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_4_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_6_4_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_6_4_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_6_4_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_6_4_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_6_4_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + UINT8 Timestamp[8]; +} EFI_ACPI_6_4_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0300 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_6_4_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_6_4_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_6_4_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_6_4_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_6_4_GENERIC_HARDWARE_ERROR 0x09 +#define EFI_ACPI_6_4_GENERIC_HARDWARE_ERROR_VERSION_2 0x0A +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK 0x0B + +// +// Error Source structure flags. +// +#define EFI_ACPI_6_4_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_6_4_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) +#define EFI_ACPI_6_4_ERROR_SOURCE_FLAG_GHES_ASSIST (1 << 2) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_6_4_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_6_4_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_6_4_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_CMCI 0x05 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_MCE 0x06 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_GPIO_SIGNAL 0x07 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEA 0x08 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEI 0x09 +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_GSIV 0x0A +#define EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_SOFTWARE_DELEGATED_EXCEPTION 0x0B + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_4_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_6_4_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_6_4_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_4_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_4_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_6_4_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Hardware Error Source Version 2 Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE ReadAckRegister; + UINT64 ReadAckPreserve; + UINT64 ReadAckWrite; +} EFI_ACPI_6_4_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_6_4_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_4_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// IA-32 Architecture Deferred Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_4_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_4_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK_STRUCTURE; + +/// +/// HMAT - Heterogeneous Memory Attribute Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[4]; +} EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER; + +/// +/// HMAT Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_REVISION 0x02 + +/// +/// HMAT types +/// +#define EFI_ACPI_6_4_HMAT_TYPE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES 0x00 +#define EFI_ACPI_6_4_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO 0x01 +#define EFI_ACPI_6_4_HMAT_TYPE_MEMORY_SIDE_CACHE_INFO 0x02 + +/// +/// HMAT Structure Header +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; +} EFI_ACPI_6_4_HMAT_STRUCTURE_HEADER; + +/// +/// Memory Proximity Domain Attributes Structure flags +/// +typedef struct { + UINT16 InitiatorProximityDomainValid : 1; + UINT16 Reserved : 15; +} EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES_FLAGS; + +/// +/// Memory Proximity Domain Attributes Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES_FLAGS Flags; + UINT8 Reserved1[2]; + UINT32 InitiatorProximityDomain; + UINT32 MemoryProximityDomain; + UINT8 Reserved2[20]; +} EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES; + +/// +/// System Locality Latency and Bandwidth Information Structure flags +/// +typedef struct { + UINT8 MemoryHierarchy : 4; + UINT8 AccessAttributes : 2; + UINT8 Reserved : 2; +} EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS; + +/// +/// System Locality Latency and Bandwidth Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS Flags; + UINT8 DataType; + UINT8 MinTransferSize; + UINT8 Reserved1; + UINT32 NumberOfInitiatorProximityDomains; + UINT32 NumberOfTargetProximityDomains; + UINT8 Reserved2[4]; + UINT64 EntryBaseUnit; +} EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO; + +/// +/// Memory Side Cache Information Structure cache attributes +/// +typedef struct { + UINT32 TotalCacheLevels : 4; + UINT32 CacheLevel : 4; + UINT32 CacheAssociativity : 4; + UINT32 WritePolicy : 4; + UINT32 CacheLineSize : 16; +} EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES; + +/// +/// Memory Side Cache Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + UINT32 MemoryProximityDomain; + UINT8 Reserved1[4]; + UINT64 MemorySideCacheSize; + EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES CacheAttributes; + UINT8 Reserved2[2]; + UINT16 NumberOfSmbiosHandles; +} EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_6_4_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_6_4_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_6_4_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_6_4_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_6_4_ERST_END_OPERATION 0x03 +#define EFI_ACPI_6_4_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_6_4_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_4_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_4_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_4_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_6_4_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_6_4_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_6_4_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_6_4_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_6_4_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_6_4_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F +#define EFI_ACPI_6_4_ERST_GET_EXECUTE_OPERATION_TIMINGS 0x10 + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_6_4_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_4_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_6_4_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_6_4_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_6_4_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_6_4_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_6_4_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_6_4_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_4_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_4_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_4_ERST_NOOP 0x04 +#define EFI_ACPI_6_4_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_6_4_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_6_4_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_6_4_ERST_ADD 0x08 +#define EFI_ACPI_6_4_ERST_SUBTRACT 0x09 +#define EFI_ACPI_6_4_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_6_4_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_6_4_ERST_STALL 0x0C +#define EFI_ACPI_6_4_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_6_4_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_6_4_ERST_GOTO 0x0F +#define EFI_ACPI_6_4_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_6_4_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_6_4_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_6_4_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_4_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_6_4_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_6_4_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_6_4_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_6_4_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_6_4_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_6_4_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_6_4_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_4_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_4_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_4_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_6_4_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_4_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_6_4_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_6_4_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_6_4_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_6_4_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_6_4_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_6_4_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_6_4_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_6_4_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_6_4_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_6_4_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_6_4_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_6_4_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_6_4_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_6_4_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_6_4_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_4_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_4_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_4_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_6_4_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_4_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_6_4_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x02 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_GENERIC 0x00 +#define EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS 0x01 +#define EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS 0x02 +#define EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC 0x03 +#define EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC 0x04 +#define EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS 0x05 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_6_4_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_4_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 NotifyOnCompletion : 1; +} EFI_ACPI_6_4_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 PlatformInterrupt : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_6_4_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_6_4_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_6_4_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_6_4_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +#define EFI_ACPI_6_4_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_POLARITY BIT0 +#define EFI_ACPI_6_4_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE BIT1 + +/// +/// Type 1 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_4_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 2 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckWrite; +} EFI_ACPI_6_4_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 3 Extended PCC Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT32 AddressLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT32 MinimumRequestTurnaroundTime; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckSet; + UINT8 Reserved1[8]; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE CommandCompleteCheckRegister; + UINT64 CommandCompleteCheckMask; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE CommandCompleteUpdateRegister; + UINT64 CommandCompleteUpdatePreserve; + UINT64 CommandCompleteUpdateSet; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE ErrorStatusRegister; + UINT64 ErrorStatusMask; +} EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC; + +/// +/// Type 4 Extended PCC Subspace Structure +/// +typedef EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC EFI_ACPI_6_4_PCCT_SUBSPACE_4_EXTENDED_PCC; + +#define EFI_ACPI_6_4_PCCT_MASTER_SLAVE_COMMUNICATIONS_CHANNEL_FLAGS_NOTIFY_ON_COMPLETION BIT0 + +typedef struct { + UINT32 Signature; + UINT32 Flags; + UINT32 Length; + UINT32 Command; +} EFI_ACPI_6_4_PCCT_EXTENDED_PCC_SHARED_MEMORY_REGION_HEADER; + +/// +/// Type 5 HW Registers based Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Version; + UINT64 BaseAddress; + UINT64 SharedMemoryRangeLength; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE CommandCompleteCheckRegister; + UINT64 CommandCompleteCheckMask; + EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE ErrorStatusRegister; + UINT64 ErrorStatusMask; + UINT32 NominalLatency; + UINT32 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_4_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS; + +/// +/// Reduced PCC Subspace Shared Memory Region +/// +typedef struct { + UINT32 Signature; + // UINT8 CommunicationSubspace[]; +} EFI_6_4_PCCT_REDUCED_PCC_SUBSPACE_SHARED_MEMORY_REGION; + +/// +/// Platform Debug Trigger Table (PDTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 TriggerCount; + UINT8 Reserved[3]; + UINT32 TriggerIdentifierArrayOffset; +} EFI_ACPI_6_4_PLATFORM_DEBUG_TRIGGER_TABLE_HEADER; + +/// +/// PDTT Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_PLATFORM_DEBUG_TRIGGER_TABLE_REVISION 0x00 + +/// +/// PDTT Platform Communication Channel Identifier Structure +/// +typedef struct { + UINT16 SubChannelIdentifer : 8; + UINT16 Runtime : 1; + UINT16 WaitForCompletion : 1; + UINT16 TriggerOrder : 1; + UINT16 Reserved : 5; +} EFI_ACPI_6_4_PDTT_PCC_IDENTIFIER; + +/// +/// PCC Commands Codes used by Platform Debug Trigger Table +/// +#define EFI_ACPI_6_4_PDTT_PCC_COMMAND_DOORBELL_ONLY 0x00 +#define EFI_ACPI_6_4_PDTT_PCC_COMMAND_VENDOR_SPECIFIC 0x01 + +/// +/// PDTT Platform Communication Channel +/// +typedef EFI_ACPI_6_4_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER EFI_ACPI_6_4_PDTT_PCC; + +/// +/// Processor Properties Topology Table (PPTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER; + +/// +/// PPTT Revision (as defined in ACPI 6.4 spec.) +/// +#define EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION 0x03 + +/// +/// PPTT types +/// +#define EFI_ACPI_6_4_PPTT_TYPE_PROCESSOR 0x00 +#define EFI_ACPI_6_4_PPTT_TYPE_CACHE 0x01 + +/// +/// PPTT Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; +} EFI_ACPI_6_4_PPTT_STRUCTURE_HEADER; + +/// +/// For PPTT struct processor flags +/// +#define EFI_ACPI_6_4_PPTT_PACKAGE_NOT_PHYSICAL 0x0 +#define EFI_ACPI_6_4_PPTT_PACKAGE_PHYSICAL 0x1 +#define EFI_ACPI_6_4_PPTT_PROCESSOR_ID_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_PROCESSOR_ID_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_PROCESSOR_IS_NOT_THREAD 0x0 +#define EFI_ACPI_6_4_PPTT_PROCESSOR_IS_THREAD 0x1 +#define EFI_ACPI_6_4_PPTT_NODE_IS_NOT_LEAF 0x0 +#define EFI_ACPI_6_4_PPTT_NODE_IS_LEAF 0x1 +#define EFI_ACPI_6_4_PPTT_IMPLEMENTATION_NOT_IDENTICAL 0x0 +#define EFI_ACPI_6_4_PPTT_IMPLEMENTATION_IDENTICAL 0x1 + +/// +/// Processor hierarchy node structure flags +/// +typedef struct { + UINT32 PhysicalPackage : 1; + UINT32 AcpiProcessorIdValid : 1; + UINT32 ProcessorIsAThread : 1; + UINT32 NodeIsALeaf : 1; + UINT32 IdenticalImplementation : 1; + UINT32 Reserved : 27; +} EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR_FLAGS; + +/// +/// Processor hierarchy node structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR_FLAGS Flags; + UINT32 Parent; + UINT32 AcpiProcessorId; + UINT32 NumberOfPrivateResources; +} EFI_ACPI_6_4_PPTT_STRUCTURE_PROCESSOR; + +/// +/// For PPTT struct cache flags +/// +#define EFI_ACPI_6_4_PPTT_CACHE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_CACHE_SIZE_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_NUMBER_OF_SETS_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_NUMBER_OF_SETS_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_ASSOCIATIVITY_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_ASSOCIATIVITY_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_ALLOCATION_TYPE_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_ALLOCATION_TYPE_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_CACHE_TYPE_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_CACHE_TYPE_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_WRITE_POLICY_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_WRITE_POLICY_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_LINE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_LINE_SIZE_VALID 0x1 +#define EFI_ACPI_6_4_PPTT_CACHE_ID_INVALID 0x0 +#define EFI_ACPI_6_4_PPTT_CACHE_ID_VALID 0x1 + +/// +/// Cache Type Structure flags +/// +typedef struct { + UINT32 SizePropertyValid : 1; + UINT32 NumberOfSetsValid : 1; + UINT32 AssociativityValid : 1; + UINT32 AllocationTypeValid : 1; + UINT32 CacheTypeValid : 1; + UINT32 WritePolicyValid : 1; + UINT32 LineSizeValid : 1; + UINT32 CacheIdValid : 1; + UINT32 Reserved : 24; +} EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE_FLAGS; + +/// +/// For cache attributes +/// +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_ALLOCATION_READ 0x0 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_ALLOCATION_WRITE 0x1 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE 0x2 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_CACHE_TYPE_DATA 0x0 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_CACHE_TYPE_INSTRUCTION 0x1 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_CACHE_TYPE_UNIFIED 0x2 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK 0x0 +#define EFI_ACPI_6_4_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_THROUGH 0x1 + +/// +/// Cache Type Structure cache attributes +/// +typedef struct { + UINT8 AllocationType : 2; + UINT8 CacheType : 2; + UINT8 WritePolicy : 1; + UINT8 Reserved : 3; +} EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE_ATTRIBUTES; + +/// +/// Cache Type Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE_FLAGS Flags; + UINT32 NextLevelOfCache; + UINT32 Size; + UINT32 NumberOfSets; + UINT8 Associativity; + EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE_ATTRIBUTES Attributes; + UINT16 LineSize; + UINT32 CacheId; +} EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE; + +/// +/// Platform Health Assessment Table (PHAT) Format +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + // UINT8 PlatformTelemetryRecords[]; +} EFI_ACPI_6_4_PLATFORM_HEALTH_ASSESSMENT_TABLE; + +#define EFI_ACPI_6_4_PLATFORM_HEALTH_ASSESSMENT_TABLE_REVISION 0x01 + +/// +/// PHAT Record Format +/// +typedef struct { + UINT16 PlatformHealthAssessmentRecordType; + UINT16 RecordLength; + UINT8 Revision; + // UINT8 Data[]; +} EFI_ACPI_6_4_PHAT_RECORD; + +/// +/// PHAT Record Type Format +/// +#define EFI_ACPI_6_4_PHAT_RECORD_TYPE_FIRMWARE_VERSION_DATA_RECORD 0x0000 +#define EFI_ACPI_6_4_PHAT_RECORD_TYPE_FIRMWARE_HEALTH_DATA_RECORD 0x0001 + +/// +/// PHAT Version Element +/// +typedef struct { + GUID ComponentId; + UINT64 VersionValue; + UINT32 ProducerId; +} EFI_ACPI_6_4_PHAT_VERSION_ELEMENT; + +/// +/// PHAT Firmware Version Data Record +/// +typedef struct { + UINT16 PlatformRecordType; + UINT16 RecordLength; + UINT8 Revision; + UINT8 Reserved[3]; + UINT32 RecordCount; + // UINT8 PhatVersionElement[]; +} EFI_ACPI_6_4_PHAT_FIRMWARE_VERISON_DATA_RECORD; + +#define EFI_ACPI_6_4_PHAT_FIRMWARE_VERSION_DATA_RECORD_REVISION 0x01 + +/// +/// Firmware Health Data Record Structure +/// +typedef struct { + UINT16 PlatformRecordType; + UINT16 RecordLength; + UINT8 Revision; + UINT16 Reserved; + UINT8 AmHealthy; + GUID DeviceSignature; + UINT32 DeviceSpecificDataOffset; + // UINT8 DevicePath[]; + // UINT8 DeviceSpecificData[]; +} EFI_ACPI_6_4_PHAT_FIRMWARE_HEALTH_DATA_RECORD_STRUCTURE; + +#define EFI_ACPI_6_4_PHAT_FIRMWARE_HEALTH_DATA_RECORD_REVISION 0x01 + +/// +/// Firmware Health Data Record device health state +/// +#define EFI_ACPI_6_4_PHAT_FIRMWARE_HEALTH_DATA_RECORD_ERRORS_FOUND 0x00 +#define EFI_ACPI_6_4_PHAT_FIRMWARE_HEALTH_DATA_RECORD_NO_ERRORS_FOUND 0x01 +#define EFI_ACPI_6_4_PHAT_FIRMWARE_HEALTH_DATA_RECORD_UNKNOWN 0x02 +#define EFI_ACPI_6_4_PHAT_FIRMWARE_HEALTH_DATA_RECORD_ADVISORY 0x03 + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_6_4_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_6_4_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "APMT" Arm Performance Monitoring Unit Table +/// +#define EFI_ACPI_6_4_ARM_PERFORMANCE_MONITORING_UNIT_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'M', 'T') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_6_4_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_6_4_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CDIT" Component Distance Information Table +/// +#define EFI_ACPI_6_4_COMPONENT_DISTANCE_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('C', 'D', 'I', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_6_4_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "CRAT" Component Resource Attribute Table +/// +#define EFI_ACPI_6_4_COMPONENT_RESOURCE_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('C', 'R', 'A', 'T') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_6_4_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_6_4_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_6_4_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_6_4_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_6_4_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_6_4_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_6_4_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_6_4_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_6_4_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "HMAT" Heterogeneous Memory Attribute Table +/// +#define EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('H', 'M', 'A', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_6_4_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_6_4_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "NFIT" NVDIMM Firmware Interface Table +/// +#define EFI_ACPI_6_4_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('N', 'F', 'I', 'T') + +/// +/// "PDTT" Platform Debug Trigger Table +/// +#define EFI_ACPI_6_4_PLATFORM_DEBUG_TRIGGER_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'D', 'T', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_6_4_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PPTT" Processor Properties Topology Table +/// +#define EFI_ACPI_6_4_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'P', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_6_4_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_6_4_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_6_4_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_6_4_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SDEV" Secure DEVices Table +/// +#define EFI_ACPI_6_4_SECURE_DEVICES_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'V') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_6_4_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_6_4_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_6_4_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_6_4_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_6_4_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_6_4_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_6_4_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_6_4_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_6_4_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_6_4_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_6_4_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_6_4_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_6_4_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IORT" I/O Remapping Table +/// +#define EFI_ACPI_6_4_IO_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('I', 'O', 'R', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_6_4_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_6_4_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_6_4_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_6_4_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_6_4_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_6_4_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "PHAT" Platform Health Assessment Table +/// +#define EFI_ACPI_6_4_PLATFORM_HEALTH_ASSESSMENT_TABLE_SIGNATURE SIGNATURE_32('P', 'H', 'A', 'T') + +/// +/// "SDEI" Software Delegated Exceptions Interface Table +/// +#define EFI_ACPI_6_4_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'I') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_6_4_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Concole Redirection Table +/// +#define EFI_ACPI_6_4_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_6_4_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "STAO" _STA Override Table +/// +#define EFI_ACPI_6_4_STA_OVERRIDE_TABLE_SIGNATURE SIGNATURE_32('S', 'T', 'A', 'O') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_6_4_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_6_4_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_6_4_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_6_4_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_6_4_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_6_4_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_6_4_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +/// +/// "WSMT" Windows SMM Security Mitigation Table +/// +#define EFI_ACPI_6_4_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE SIGNATURE_32('W', 'S', 'M', 'T') + +/// +/// "XENV" Xen Project Table +/// +#define EFI_ACPI_6_4_XEN_PROJECT_TABLE_SIGNATURE SIGNATURE_32('X', 'E', 'N', 'V') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi65.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi65.h new file mode 100644 index 0000000..f714727 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/Acpi65.h @@ -0,0 +1,3256 @@ +/** @file + ACPI 6.5 definitions from the ACPI Specification Revision 6.5 Aug, 2022. + + Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2021, ARM Ltd. All rights reserved.
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ACPI_6_5_H_ +#define ACPI_6_5_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// ACPI 6.5 Generic Address Space definition +/// +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE; + +// +// Generic Address Space Address IDs +// +#define EFI_ACPI_6_5_SYSTEM_MEMORY 0x00 +#define EFI_ACPI_6_5_SYSTEM_IO 0x01 +#define EFI_ACPI_6_5_PCI_CONFIGURATION_SPACE 0x02 +#define EFI_ACPI_6_5_EMBEDDED_CONTROLLER 0x03 +#define EFI_ACPI_6_5_SMBUS 0x04 +#define EFI_ACPI_6_5_SYSTEM_CMOS 0x05 +#define EFI_ACPI_6_5_PCI_BAR_TARGET 0x06 +#define EFI_ACPI_6_5_IPMI 0x07 +#define EFI_ACPI_6_5_GENERAL_PURPOSE_IO 0x08 +#define EFI_ACPI_6_5_GENERIC_SERIAL_BUS 0x09 +#define EFI_ACPI_6_5_PLATFORM_COMMUNICATION_CHANNEL 0x0A +#define EFI_ACPI_6_5_FUNCTIONAL_FIXED_HARDWARE 0x7F + +// +// Generic Address Space Access Sizes +// +#define EFI_ACPI_6_5_UNDEFINED 0 +#define EFI_ACPI_6_5_BYTE 1 +#define EFI_ACPI_6_5_WORD 2 +#define EFI_ACPI_6_5_DWORD 3 +#define EFI_ACPI_6_5_QWORD 4 + +// +// ACPI 6.5 table structures +// + +/// +/// Root System Description Pointer Structure +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Revision; + UINT32 RsdtAddress; + UINT32 Length; + UINT64 XsdtAddress; + UINT8 ExtendedChecksum; + UINT8 Reserved[3]; +} EFI_ACPI_6_5_ROOT_SYSTEM_DESCRIPTION_POINTER; + +/// +/// RSD_PTR Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02 ///< ACPISpec (Revision 6.5) says current value is 2 + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_5_COMMON_HEADER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// + +/// +/// XSDT Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 Reserved0; + UINT8 PreferredPmProfile; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 PstateCnt; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmrLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 CstCnt; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT16 IaPcBootArch; + UINT8 Reserved1; + UINT32 Flags; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE ResetReg; + UINT8 ResetValue; + UINT16 ArmBootArch; + UINT8 MinorVersion; + UINT64 XFirmwareCtrl; + UINT64 XDsdt; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XGpe0Blk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE XGpe1Blk; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE SleepControlReg; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE SleepStatusReg; + UINT64 HypervisorVendorIdentity; +} EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x06 +#define EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION 0x05 + +// +// Fixed ACPI Description Table Preferred Power Management Profile +// +#define EFI_ACPI_6_5_PM_PROFILE_UNSPECIFIED 0 +#define EFI_ACPI_6_5_PM_PROFILE_DESKTOP 1 +#define EFI_ACPI_6_5_PM_PROFILE_MOBILE 2 +#define EFI_ACPI_6_5_PM_PROFILE_WORKSTATION 3 +#define EFI_ACPI_6_5_PM_PROFILE_ENTERPRISE_SERVER 4 +#define EFI_ACPI_6_5_PM_PROFILE_SOHO_SERVER 5 +#define EFI_ACPI_6_5_PM_PROFILE_APPLIANCE_PC 6 +#define EFI_ACPI_6_5_PM_PROFILE_PERFORMANCE_SERVER 7 +#define EFI_ACPI_6_5_PM_PROFILE_TABLET 8 + +// +// Fixed ACPI Description Table Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_5_LEGACY_DEVICES BIT0 +#define EFI_ACPI_6_5_8042 BIT1 +#define EFI_ACPI_6_5_VGA_NOT_PRESENT BIT2 +#define EFI_ACPI_6_5_MSI_NOT_SUPPORTED BIT3 +#define EFI_ACPI_6_5_PCIE_ASPM_CONTROLS BIT4 +#define EFI_ACPI_6_5_CMOS_RTC_NOT_PRESENT BIT5 + +// +// Fixed ACPI Description Table Arm Boot Architecture Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_5_ARM_PSCI_COMPLIANT BIT0 +#define EFI_ACPI_6_5_ARM_PSCI_USE_HVC BIT1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_5_WBINVD BIT0 +#define EFI_ACPI_6_5_WBINVD_FLUSH BIT1 +#define EFI_ACPI_6_5_PROC_C1 BIT2 +#define EFI_ACPI_6_5_P_LVL2_UP BIT3 +#define EFI_ACPI_6_5_PWR_BUTTON BIT4 +#define EFI_ACPI_6_5_SLP_BUTTON BIT5 +#define EFI_ACPI_6_5_FIX_RTC BIT6 +#define EFI_ACPI_6_5_RTC_S4 BIT7 +#define EFI_ACPI_6_5_TMR_VAL_EXT BIT8 +#define EFI_ACPI_6_5_DCK_CAP BIT9 +#define EFI_ACPI_6_5_RESET_REG_SUP BIT10 +#define EFI_ACPI_6_5_SEALED_CASE BIT11 +#define EFI_ACPI_6_5_HEADLESS BIT12 +#define EFI_ACPI_6_5_CPU_SW_SLP BIT13 +#define EFI_ACPI_6_5_PCI_EXP_WAK BIT14 +#define EFI_ACPI_6_5_USE_PLATFORM_CLOCK BIT15 +#define EFI_ACPI_6_5_S4_RTC_STS_VALID BIT16 +#define EFI_ACPI_6_5_REMOTE_POWER_ON_CAPABLE BIT17 +#define EFI_ACPI_6_5_FORCE_APIC_CLUSTER_MODEL BIT18 +#define EFI_ACPI_6_5_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19 +#define EFI_ACPI_6_5_HW_REDUCED_ACPI BIT20 +#define EFI_ACPI_6_5_LOW_POWER_S0_IDLE_CAPABLE BIT21 + +/// +/// Firmware ACPI Control Structure +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT64 XFirmwareWakingVector; + UINT8 Version; + UINT8 Reserved0[3]; + UINT32 OspmFlags; + UINT8 Reserved1[24]; +} EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// FACS Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x02 + +/// +/// Firmware Control Structure Feature Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_5_S4BIOS_F BIT0 +#define EFI_ACPI_6_5_64BIT_WAKE_SUPPORTED_F BIT1 + +/// +/// OSPM Enabled Firmware Control Structure Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_5_OSPM_64BIT_WAKE_F BIT0 + +// +// Differentiated System Description Table, +// Secondary System Description Table +// and Persistent System Description Table, +// no definition needed as they are common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a definition block. +// +#define EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 +#define EFI_ACPI_6_5_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION 0x02 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x06 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_5_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x18 and 0x7F are reserved and +// will be ignored by OSPM. 0x80 ~ 0xFF are reserved for OEM. +// +#define EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_6_5_IO_APIC 0x01 +#define EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_6_5_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_6_5_LOCAL_APIC_NMI 0x04 +#define EFI_ACPI_6_5_LOCAL_APIC_ADDRESS_OVERRIDE 0x05 +#define EFI_ACPI_6_5_IO_SAPIC 0x06 +#define EFI_ACPI_6_5_LOCAL_SAPIC 0x07 +#define EFI_ACPI_6_5_PLATFORM_INTERRUPT_SOURCES 0x08 +#define EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC 0x09 +#define EFI_ACPI_6_5_LOCAL_X2APIC_NMI 0x0A +#define EFI_ACPI_6_5_GIC 0x0B +#define EFI_ACPI_6_5_GICD 0x0C +#define EFI_ACPI_6_5_GIC_MSI_FRAME 0x0D +#define EFI_ACPI_6_5_GICR 0x0E +#define EFI_ACPI_6_5_GIC_ITS 0x0F +#define EFI_ACPI_6_5_MULTIPROCESSOR_WAKEUP 0x10 +#define EFI_ACPI_6_5_CORE_PIC 0x11 +#define EFI_ACPI_6_5_LIO_PIC 0x12 +#define EFI_ACPI_6_5_HT_PIC 0x13 +#define EFI_ACPI_6_5_EIO_PIC 0x14 +#define EFI_ACPI_6_5_MSI_PIC 0x15 +#define EFI_ACPI_6_5_BIO_PIC 0x16 +#define EFI_ACPI_6_5_LPC_PIC 0x17 + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_LOCAL_APIC_ENABLED BIT0 +#define EFI_ACPI_6_5_LOCAL_APIC_ONLINE_CAPABLE BIT1 + +/// +/// IO APIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} EFI_ACPI_6_5_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; + UINT8 CpeiProcessorOverride; + UINT8 Reserved[31]; +} EFI_ACPI_6_5_PLATFORM_INTERRUPT_APIC_STRUCTURE; + +// +// MPS INTI flags. +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_6_5_POLARITY (3 << 0) +#define EFI_ACPI_6_5_TRIGGER_MODE (3 << 2) + +/// +/// Non-Maskable Interrupt Source Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterrupt; +} EFI_ACPI_6_5_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorUid; + UINT16 Flags; + UINT8 LocalApicLint; +} EFI_ACPI_6_5_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Local APIC Address Override Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 LocalApicAddress; +} EFI_ACPI_6_5_LOCAL_APIC_ADDRESS_OVERRIDE_STRUCTURE; + +/// +/// IO SAPIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 GlobalSystemInterruptBase; + UINT64 IoSapicAddress; +} EFI_ACPI_6_5_IO_SAPIC_STRUCTURE; + +/// +/// Local SAPIC Structure +/// This struct followed by a null-terminated ASCII string - ACPI Processor UID String +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 LocalSapicId; + UINT8 LocalSapicEid; + UINT8 Reserved[3]; + UINT32 Flags; + UINT32 ACPIProcessorUIDValue; +} EFI_ACPI_6_5_PROCESSOR_LOCAL_SAPIC_STRUCTURE; + +/// +/// Platform Interrupt Sources Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT8 InterruptType; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT8 IoSapicVector; + UINT32 GlobalSystemInterrupt; + UINT32 PlatformInterruptSourceFlags; +} EFI_ACPI_6_5_PLATFORM_INTERRUPT_SOURCES_STRUCTURE; + +/// +/// Platform Interrupt Source Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_6_5_CPEI_PROCESSOR_OVERRIDE BIT0 + +/// +/// Processor Local x2APIC Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE; + +/// +/// Local x2APIC NMI Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalX2ApicLint; + UINT8 Reserved[3]; +} EFI_ACPI_6_5_LOCAL_X2APIC_NMI_STRUCTURE; + +/// +/// GIC Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 CPUInterfaceNumber; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ParkingProtocolVersion; + UINT32 PerformanceInterruptGsiv; + UINT64 ParkedAddress; + UINT64 PhysicalBaseAddress; + UINT64 GICV; + UINT64 GICH; + UINT32 VGICMaintenanceInterrupt; + UINT64 GICRBaseAddress; + UINT64 MPIDR; + UINT8 ProcessorPowerEfficiencyClass; + UINT8 Reserved2; + UINT16 SpeOverflowInterrupt; +} EFI_ACPI_6_5_GIC_STRUCTURE; + +/// +/// GIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_GIC_ENABLED BIT0 +#define EFI_ACPI_6_5_PERFORMANCE_INTERRUPT_MODEL BIT1 +#define EFI_ACPI_6_5_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS BIT2 + +/// +/// GIC Distributor Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicId; + UINT64 PhysicalBaseAddress; + UINT32 SystemVectorBase; + UINT8 GicVersion; + UINT8 Reserved2[3]; +} EFI_ACPI_6_5_GIC_DISTRIBUTOR_STRUCTURE; + +/// +/// GIC Version +/// +#define EFI_ACPI_6_5_GIC_V1 0x01 +#define EFI_ACPI_6_5_GIC_V2 0x02 +#define EFI_ACPI_6_5_GIC_V3 0x03 +#define EFI_ACPI_6_5_GIC_V4 0x04 + +/// +/// GIC MSI Frame Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved1; + UINT32 GicMsiFrameId; + UINT64 PhysicalBaseAddress; + UINT32 Flags; + UINT16 SPICount; + UINT16 SPIBase; +} EFI_ACPI_6_5_GIC_MSI_FRAME_STRUCTURE; + +/// +/// GIC MSI Frame Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_SPI_COUNT_BASE_SELECT BIT0 + +/// +/// GICR Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT64 DiscoveryRangeBaseAddress; + UINT32 DiscoveryRangeLength; +} EFI_ACPI_6_5_GICR_STRUCTURE; + +/// +/// GIC Interrupt Translation Service Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Reserved; + UINT32 GicItsId; + UINT64 PhysicalBaseAddress; + UINT32 Reserved2; +} EFI_ACPI_6_5_GIC_ITS_STRUCTURE; + +/// +/// Multiprocessor Wakeup Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 MailBoxVersion; + UINT32 Reserved; + UINT64 MailBoxAddress; +} EFI_ACPI_6_5_MULTIPROCESSOR_WAKEUP_STRUCTURE; + +/// +/// Multiprocessor Wakeup Mailbox Structure +/// +typedef struct { + UINT16 Command; + UINT16 Reserved; + UINT32 AcpiId; + UINT64 WakeupVector; + UINT8 ReservedForOs[2032]; + UINT8 ReservedForFirmware[2048]; +} EFI_ACPI_6_5_MULTIPROCESSOR_WAKEUP_MAILBOX_STRUCTURE; + +#define EFI_ACPI_6_5_MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_NOOP 0x0000 +#define EFI_ACPI_6_5_MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_WAKEUP 0x0001 + +/// +/// Core Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT32 ProcessorId; + UINT32 CoreId; + UINT32 Flags; +} EFI_ACPI_6_5_CORE_PIC_STRUCTURE; + +/// +/// Legacy I/O Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT64 Address; + UINT16 Size; + UINT8 Cascade[2]; + UINT32 CascadeMap[2]; +} EFI_ACPI_6_5_LIO_PIC_STRUCTURE; + +/// +/// HyperTransport Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT64 Address; + UINT16 Size; + UINT8 Cascade[8]; +} EFI_ACPI_6_5_HT_PIC_STRUCTURE; + +/// +/// Extend I/O Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT8 Cascade; + UINT8 Node; + UINT64 NodeMap; +} EFI_ACPI_6_5_EIO_PIC_STRUCTURE; + +/// +/// MSI Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT64 MsgAddress; + UINT32 Start; + UINT32 Count; +} EFI_ACPI_6_5_MSI_PIC_STRUCTURE; + +/// +/// Bridge I/O Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT64 Address; + UINT16 Size; + UINT16 Id; + UINT16 GsiBase; +} EFI_ACPI_6_5_BIO_PIC_STRUCTURE; + +/// +/// Low Pin Count Programmable Interrupt Controller +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Version; + UINT64 Address; + UINT16 Size; + UINT8 Cascade; +} EFI_ACPI_6_5_LPC_PIC_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_6_5_SMART_BATTERY_DESCRIPTION_TABLE; + +/// +/// SBST Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_SMART_BATTERY_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Embedded Controller Boot Resources Table (ECDT) +/// The table is followed by a null terminated ASCII string that contains +/// a fully qualified reference to the name space object. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE EcControl; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE EcData; + UINT32 Uid; + UINT8 GpeBit; +} EFI_ACPI_6_5_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE; + +/// +/// ECDT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_REVISION 0x01 + +/// +/// System Resource Affinity Table (SRAT). The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved1; ///< Must be set to 1 + UINT64 Reserved2; +} EFI_ACPI_6_5_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER; + +/// +/// SRAT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION 0x03 + +// +// SRAT structure types. +// All other values between 0x06 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY 0x00 +#define EFI_ACPI_6_5_MEMORY_AFFINITY 0x01 +#define EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_AFFINITY 0x02 +#define EFI_ACPI_6_5_GICC_AFFINITY 0x03 +#define EFI_ACPI_6_5_GIC_ITS_AFFINITY 0x04 +#define EFI_ACPI_6_5_GENERIC_INITIATOR_AFFINITY 0x05 + +/// +/// Processor Local APIC/SAPIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProximityDomain7To0; + UINT8 ApicId; + UINT32 Flags; + UINT8 LocalSapicEid; + UINT8 ProximityDomain31To8[3]; + UINT32 ClockDomain; +} EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE; + +/// +/// Local APIC/SAPIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED (1 << 0) + +/// +/// Memory Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved1; + UINT32 AddressBaseLow; + UINT32 AddressBaseHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + UINT32 Reserved2; + UINT32 Flags; + UINT64 Reserved3; +} EFI_ACPI_6_5_MEMORY_AFFINITY_STRUCTURE; + +// +// Memory Flags. All other bits are reserved and must be 0. +// +#define EFI_ACPI_6_5_MEMORY_ENABLED (1 << 0) +#define EFI_ACPI_6_5_MEMORY_HOT_PLUGGABLE (1 << 1) +#define EFI_ACPI_6_5_MEMORY_NONVOLATILE (1 << 2) + +/// +/// Processor Local x2APIC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1[2]; + UINT32 ProximityDomain; + UINT32 X2ApicId; + UINT32 Flags; + UINT32 ClockDomain; + UINT8 Reserved2[4]; +} EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE; + +/// +/// GICC Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT32 AcpiProcessorUid; + UINT32 Flags; + UINT32 ClockDomain; +} EFI_ACPI_6_5_GICC_AFFINITY_STRUCTURE; + +/// +/// GICC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_GICC_ENABLED (1 << 0) + +/// +/// GIC Interrupt Translation Service (ITS) Affinity Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT8 Reserved[2]; + UINT32 ItsId; +} EFI_ACPI_6_5_GIC_ITS_AFFINITY_STRUCTURE; + +// +// Generic Initiator Affinity Structure Device Handle Types +// All other values between 0x02 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_6_5_ACPI_DEVICE_HANDLE 0x00 +#define EFI_ACPI_6_5_PCI_DEVICE_HANDLE 0x01 + +/// +/// Device Handle - ACPI +/// +typedef struct { + UINT64 AcpiHid; + UINT32 AcpiUid; + UINT8 Reserved[4]; +} EFI_ACPI_6_5_DEVICE_HANDLE_ACPI; + +/// +/// Device Handle - PCI +/// +typedef struct { + UINT16 PciSegment; + UINT16 PciBdfNumber; + UINT8 Reserved[12]; +} EFI_ACPI_6_5_DEVICE_HANDLE_PCI; + +/// +/// Device Handle +/// +typedef union { + EFI_ACPI_6_5_DEVICE_HANDLE_ACPI Acpi; + EFI_ACPI_6_5_DEVICE_HANDLE_PCI Pci; +} EFI_ACPI_6_5_DEVICE_HANDLE; + +/// +/// Generic Initiator Affinity Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved1; + UINT8 DeviceHandleType; + UINT32 ProximityDomain; + EFI_ACPI_6_5_DEVICE_HANDLE DeviceHandle; + UINT32 Flags; + UINT8 Reserved2[4]; +} EFI_ACPI_6_5_GENERIC_INITIATOR_AFFINITY_STRUCTURE; + +/// +/// Generic Initiator Affinity Structure Flags. All other bits are reserved +/// and must be 0. +/// +#define EFI_ACPI_6_5_GENERIC_INITIATOR_AFFINITY_STRUCTURE_ENABLED BIT0 +#define EFI_ACPI_6_5_GENERIC_INITIATOR_AFFINITY_STRUCTURE_ARCHITECTURAL_TRANSACTIONS BIT1 + +/// +/// System Locality Distance Information Table (SLIT). +/// The rest of the table is a matrix. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 NumberOfSystemLocalities; +} EFI_ACPI_6_5_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER; + +/// +/// SLIT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION 0x01 + +/// +/// Corrected Platform Error Polling Table (CPEP) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[8]; +} EFI_ACPI_6_5_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_HEADER; + +/// +/// CPEP Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_REVISION 0x01 + +// +// CPEP processor structure types. +// +#define EFI_ACPI_6_5_CPEP_PROCESSOR_APIC_SAPIC 0x00 + +/// +/// Corrected Platform Error Polling Processor Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 ProcessorId; + UINT8 ProcessorEid; + UINT32 PollingInterval; +} EFI_ACPI_6_5_CPEP_PROCESSOR_APIC_SAPIC_STRUCTURE; + +/// +/// Maximum System Characteristics Table (MSCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 OffsetProxDomInfo; + UINT32 MaximumNumberOfProximityDomains; + UINT32 MaximumNumberOfClockDomains; + UINT64 MaximumPhysicalAddress; +} EFI_ACPI_6_5_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_HEADER; + +/// +/// MSCT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_REVISION 0x01 + +/// +/// Maximum Proximity Domain Information Structure Definition +/// +typedef struct { + UINT8 Revision; + UINT8 Length; + UINT32 ProximityDomainRangeLow; + UINT32 ProximityDomainRangeHigh; + UINT32 MaximumProcessorCapacity; + UINT64 MaximumMemoryCapacity; +} EFI_ACPI_6_5_MAXIMUM_PROXIMITY_DOMAIN_INFORMATION_STRUCTURE; + +/// +/// ACPI RAS Feature Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier[12]; +} EFI_ACPI_6_5_RAS_FEATURE_TABLE; + +/// +/// RASF Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_RAS_FEATURE_TABLE_REVISION 0x01 + +/// +/// ACPI RASF Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT16 Version; + UINT8 RASCapabilities[16]; + UINT8 SetRASCapabilities[16]; + UINT16 NumberOfRASFParameterBlocks; + UINT32 SetRASCapabilitiesStatus; +} EFI_ACPI_6_5_RASF_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI RASF PCC command code +/// +#define EFI_ACPI_6_5_RASF_PCC_COMMAND_CODE_EXECUTE_RASF_COMMAND 0x01 + +/// +/// ACPI RASF Platform RAS Capabilities +/// +#define EFI_ACPI_6_5_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED BIT0 +#define EFI_ACPI_6_5_RASF_PLATFORM_RAS_CAPABILITY_HARDWARE_BASED_PATROL_SCRUB_SUPPORTED_AND_EXPOSED_TO_SOFTWARE BIT1 +#define EFI_ACPI_6_5_RASF_PLATFORM_RAS_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT2 +#define EFI_ACPI_6_5_RASF_PLATFORM_RAS_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT3 +#define EFI_ACPI_6_5_RASF_PLATFORM_RAS_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT4 + +/// +/// ACPI RASF Parameter Block structure for PATROL_SCRUB +/// +typedef struct { + UINT16 Type; + UINT16 Version; + UINT16 Length; + UINT16 PatrolScrubCommand; + UINT64 RequestedAddressRange[2]; + UINT64 ActualAddressRange[2]; + UINT16 Flags; + UINT8 RequestedSpeed; +} EFI_ACPI_6_5_RASF_PATROL_SCRUB_PLATFORM_BLOCK_STRUCTURE; + +/// +/// ACPI RASF Patrol Scrub command +/// +#define EFI_ACPI_6_5_RASF_PATROL_SCRUB_COMMAND_GET_PATROL_PARAMETERS 0x01 +#define EFI_ACPI_6_5_RASF_PATROL_SCRUB_COMMAND_START_PATROL_SCRUBBER 0x02 +#define EFI_ACPI_6_5_RASF_PATROL_SCRUB_COMMAND_STOP_PATROL_SCRUBBER 0x03 + +/// +/// Memory Power State Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 PlatformCommunicationChannelIdentifier; + UINT8 Reserved[3]; + // Memory Power Node Structure + // Memory Power State Characteristics +} EFI_ACPI_6_5_MEMORY_POWER_STATUS_TABLE; + +/// +/// MPST Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_MEMORY_POWER_STATE_TABLE_REVISION 0x01 + +/// +/// MPST Platform Communication Channel Shared Memory Region definition. +/// +typedef struct { + UINT32 Signature; + UINT16 Command; + UINT16 Status; + UINT32 MemoryPowerCommandRegister; + UINT32 MemoryPowerStatusRegister; + UINT32 PowerStateId; + UINT32 MemoryPowerNodeId; + UINT64 MemoryEnergyConsumed; + UINT64 ExpectedAveragePowerComsuned; +} EFI_ACPI_6_5_MPST_PLATFORM_COMMUNICATION_CHANNEL_SHARED_MEMORY_REGION; + +/// +/// ACPI MPST PCC command code +/// +#define EFI_ACPI_6_5_MPST_PCC_COMMAND_CODE_EXECUTE_MPST_COMMAND 0x03 + +/// +/// ACPI MPST Memory Power command +/// +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_POWER_STATE 0x01 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_COMMAND_SET_MEMORY_POWER_STATE 0x02 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_COMMAND_GET_AVERAGE_POWER_CONSUMED 0x03 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_COMMAND_GET_MEMORY_ENERGY_CONSUMED 0x04 + +/// +/// MPST Memory Power Node Table +/// +typedef struct { + UINT8 PowerStateValue; + UINT8 PowerStateInformationIndex; +} EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE; + +typedef struct { + UINT8 Flag; + UINT8 Reserved; + UINT16 MemoryPowerNodeId; + UINT32 Length; + UINT64 AddressBase; + UINT64 AddressLength; + UINT32 NumberOfPowerStates; + UINT32 NumberOfPhysicalComponents; + // EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE MemoryPowerState[NumberOfPowerStates]; + // UINT16 PhysicalComponentIdentifier[NumberOfPhysicalComponents]; +} EFI_ACPI_6_5_MPST_MEMORY_POWER_STRUCTURE; + +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_STRUCTURE_FLAG_ENABLE 0x01 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_STRUCTURE_FLAG_POWER_MANAGED 0x02 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_STRUCTURE_FLAG_HOT_PLUGGABLE 0x04 + +typedef struct { + UINT16 MemoryPowerNodeCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_5_MPST_MEMORY_POWER_NODE_TABLE; + +/// +/// MPST Memory Power State Characteristics Table +/// +typedef struct { + UINT8 PowerStateStructureID; + UINT8 Flag; + UINT16 Reserved; + UINT32 AveragePowerConsumedInMPS0; + UINT32 RelativePowerSavingToMPS0; + UINT64 ExitLatencyToMPS0; +} EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE; + +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_MEMORY_CONTENT_PRESERVED 0x01 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_ENTRY 0x02 +#define EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_STRUCTURE_FLAG_AUTONOMOUS_MEMORY_POWER_STATE_EXIT 0x04 + +typedef struct { + UINT16 MemoryPowerStateCharacteristicsCount; + UINT8 Reserved[2]; +} EFI_ACPI_6_5_MPST_MEMORY_POWER_STATE_CHARACTERISTICS_TABLE; + +/// +/// Platform Memory Topology Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 NumberOfMemoryDevices; + // EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[NumberOfMemoryDevices]; +} EFI_ACPI_6_5_PLATFORM_MEMORY_TOPOLOGY_TABLE; + +/// +/// PMTT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_MEMORY_TOPOLOGY_TABLE_REVISION 0x02 + +/// +/// Common Memory Device. +/// +typedef struct { + UINT8 Type; + UINT8 Reserved; + UINT16 Length; + UINT16 Flags; + UINT16 Reserved1; + UINT32 NumberOfMemoryDevices; + // UINT8 TypeSpecificData[]; + // EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[NumberOfMemoryDevices]; +} EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE; + +/// +/// Memory Device Type. +/// +#define EFI_ACPI_6_5_PMTT_MEMORY_DEVICE_TYPE_SOCKET 0x0 +#define EFI_ACPI_6_5_PMTT_MEMORY_DEVICE_TYPE_MEMORY_CONTROLLER 0x1 +#define EFI_ACPI_6_5_PMTT_MEMORY_DEVICE_TYPE_DIMM 0x2 +#define EFI_ACPI_6_5_PMTT_MEMORY_DEVICE_TYPE_VENDOR_SPECIFIC_TYPE 0xFF + +/// +/// Socket Type Data. +/// +typedef struct { + EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT16 SocketIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[]; +} EFI_ACPI_6_5_PMTT_SOCKET_TYPE_DATA; + +/// +/// Memory Controller Type Data. +/// +typedef struct { + EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT16 MemoryControllerIdentifier; + UINT16 Reserved; + // EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[]; +} EFI_ACPI_6_5_PMTT_MEMORY_CONTROLLER_TYPE_DATA; + +/// +/// DIMM Type Specific Data. +/// +typedef struct { + EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT32 SmbiosHandle; +} EFI_ACPI_6_5_PMTT_DIMM_TYPE_SPECIFIC_DATA; + +/// +/// Vendor Specific Type Data. +/// +typedef struct { + EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE CommonMemoryDeviceHeader; + UINT8 TypeUuid[16]; + // EFI_ACPI_6_5_PMTT_VENDOR_SPECIFIC_TYPE_DATA VendorSpecificData[]; + // EFI_ACPI_6_5_PMTT_COMMON_MEMORY_DEVICE MemoryDeviceStructure[]; +} EFI_ACPI_6_5_PMTT_VENDOR_SPECIFIC_TYPE_DATA; + +/// +/// Boot Graphics Resource Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + /// + /// 2-bytes (16 bit) version ID. This value must be 1. + /// + UINT16 Version; + /// + /// 1-byte status field indicating current status about the table. + /// Bits[7:3] = Reserved (must be zero) + /// Bits[2:1] = Orientation Offset. These bits describe the clockwise + /// degree offset from the image's default orientation. + /// [00] = 0, no offset + /// [01] = 90 + /// [10] = 180 + /// [11] = 270 + /// Bit [0] = Displayed. A one indicates the boot image graphic is + /// displayed. + /// + UINT8 Status; + /// + /// 1-byte enumerated type field indicating format of the image. + /// 0 = Bitmap + /// 1 - 255 Reserved (for future use) + /// + UINT8 ImageType; + /// + /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy + /// of the image bitmap. + /// + UINT64 ImageAddress; + /// + /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetX; + /// + /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image. + /// (X, Y) display offset of the top left corner of the boot image. + /// The top left corner of the display is at offset (0, 0). + /// + UINT32 ImageOffsetY; +} EFI_ACPI_6_5_BOOT_GRAPHICS_RESOURCE_TABLE; + +/// +/// BGRT Revision +/// +#define EFI_ACPI_6_5_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION 1 + +/// +/// BGRT Version +/// +#define EFI_ACPI_6_5_BGRT_VERSION 0x01 + +/// +/// BGRT Status +/// +#define EFI_ACPI_6_5_BGRT_STATUS_NOT_DISPLAYED 0x00 +#define EFI_ACPI_6_5_BGRT_STATUS_DISPLAYED 0x01 + +/// +/// BGRT Image Type +/// +#define EFI_ACPI_6_5_BGRT_IMAGE_TYPE_BMP 0x00 + +/// +/// FPDT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_FIRMWARE_PERFORMANCE_DATA_TABLE_REVISION 0x01 + +/// +/// FPDT Performance Record Types +/// +#define EFI_ACPI_6_5_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER 0x0000 +#define EFI_ACPI_6_5_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER 0x0001 + +/// +/// FPDT Performance Record Revision +/// +#define EFI_ACPI_6_5_FPDT_RECORD_REVISION_FIRMWARE_BASIC_BOOT_POINTER 0x01 +#define EFI_ACPI_6_5_FPDT_RECORD_REVISION_S3_PERFORMANCE_TABLE_POINTER 0x01 + +/// +/// FPDT Runtime Performance Record Types +/// +#define EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME 0x0000 +#define EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND 0x0001 +#define EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT 0x0002 + +/// +/// FPDT Runtime Performance Record Revision +/// +#define EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_REVISION_S3_RESUME 0x01 +#define EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_REVISION_S3_SUSPEND 0x01 +#define EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT 0x02 + +/// +/// FPDT Performance Record header +/// +typedef struct { + UINT16 Type; + UINT8 Length; + UINT8 Revision; +} EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER; + +/// +/// FPDT Performance Table header +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER; + +/// +/// FPDT Firmware Basic Boot Performance Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the Basic Boot Performance Table. + /// + UINT64 BootPerformanceTablePointer; +} EFI_ACPI_6_5_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT S3 Performance Table Pointer Record Structure +/// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// 64-bit processor-relative physical address of the S3 Performance Table. + /// + UINT64 S3PerformanceTablePointer; +} EFI_ACPI_6_5_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Record Structure +/// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER Header; + UINT32 Reserved; + /// + /// Timer value logged at the beginning of firmware image execution. + /// This may not always be zero or near zero. + /// + UINT64 ResetEnd; + /// + /// Timer value logged just prior to loading the OS boot loader into memory. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 OsLoaderLoadImageStart; + /// + /// Timer value logged just prior to launching the previously loaded OS boot loader image. + /// For non-UEFI compatible boots, the timer value logged will be just prior + /// to the INT 19h handler invocation. + /// + UINT64 OsLoaderStartImageStart; + /// + /// Timer value logged at the point when the OS loader calls the + /// ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesEntry; + /// + /// Timer value logged at the point just prior towhen the OS loader gaining + /// control back from calls the ExitBootServices function for UEFI compatible firmware. + /// For non-UEFI compatible boots, this field must be zero. + /// + UINT64 ExitBootServicesExit; +} EFI_ACPI_6_5_FPDT_FIRMWARE_BASIC_BOOT_RECORD; + +/// +/// FPDT Firmware Basic Boot Performance Table signature +/// +#define EFI_ACPI_6_5_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('F', 'B', 'P', 'T') + +// +// FPDT Firmware Basic Boot Performance Table +// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_5_FPDT_FIRMWARE_BASIC_BOOT_TABLE; + +/// +/// FPDT "S3PT" S3 Performance Table +/// +#define EFI_ACPI_6_5_FPDT_S3_PERFORMANCE_TABLE_SIGNATURE SIGNATURE_32('S', '3', 'P', 'T') + +// +// FPDT Firmware S3 Boot Performance Table +// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER Header; + // + // one or more Performance Records. + // +} EFI_ACPI_6_5_FPDT_FIRMWARE_S3_BOOT_TABLE; + +/// +/// FPDT Basic S3 Resume Performance Record +/// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// A count of the number of S3 resume cycles since the last full boot sequence. + /// + UINT32 ResumeCount; + /// + /// Timer recorded at the end of BIOS S3 resume, just prior to handoff to the + /// OS waking vector. Only the most recent resume cycle's time is retained. + /// + UINT64 FullResume; + /// + /// Average timer value of all resume cycles logged since the last full boot + /// sequence, including the most recent resume. Note that the entire log of + /// timer values does not need to be retained in order to calculate this average. + /// + UINT64 AverageResume; +} EFI_ACPI_6_5_FPDT_S3_RESUME_RECORD; + +/// +/// FPDT Basic S3 Suspend Performance Record +/// +typedef struct { + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER Header; + /// + /// Timer value recorded at the OS write to SLP_TYP upon entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendStart; + /// + /// Timer value recorded at the final firmware write to SLP_TYP (or other + /// mechanism) used to trigger hardware entry to S3. + /// Only the most recent suspend cycle's timer value is retained. + /// + UINT64 SuspendEnd; +} EFI_ACPI_6_5_FPDT_S3_SUSPEND_RECORD; + +/// +/// Firmware Performance Record Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_5_FIRMWARE_PERFORMANCE_RECORD_TABLE; + +/// +/// Generic Timer Description Table definition. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 CntControlBasePhysicalAddress; + UINT32 Reserved; + UINT32 SecurePL1TimerGSIV; + UINT32 SecurePL1TimerFlags; + UINT32 NonSecurePL1TimerGSIV; + UINT32 NonSecurePL1TimerFlags; + UINT32 VirtualTimerGSIV; + UINT32 VirtualTimerFlags; + UINT32 NonSecurePL2TimerGSIV; + UINT32 NonSecurePL2TimerFlags; + UINT64 CntReadBasePhysicalAddress; + UINT32 PlatformTimerCount; + UINT32 PlatformTimerOffset; + UINT32 VirtualPL2TimerGSIV; + UINT32 VirtualPL2TimerFlags; +} EFI_ACPI_6_5_GENERIC_TIMER_DESCRIPTION_TABLE; + +/// +/// GTDT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION 0x03 + +/// +/// Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_5_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_5_GTDT_TIMER_FLAG_ALWAYS_ON_CAPABILITY BIT2 + +/// +/// Platform Timer Type +/// +#define EFI_ACPI_6_5_GTDT_GT_BLOCK 0 +#define EFI_ACPI_6_5_GTDT_ARM_GENERIC_WATCHDOG 1 + +/// +/// GT Block Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 CntCtlBase; + UINT32 GTBlockTimerCount; + UINT32 GTBlockTimerOffset; +} EFI_ACPI_6_5_GTDT_GT_BLOCK_STRUCTURE; + +/// +/// GT Block Timer Structure +/// +typedef struct { + UINT8 GTFrameNumber; + UINT8 Reserved[3]; + UINT64 CntBaseX; + UINT64 CntEL0BaseX; + UINT32 GTxPhysicalTimerGSIV; + UINT32 GTxPhysicalTimerFlags; + UINT32 GTxVirtualTimerGSIV; + UINT32 GTxVirtualTimerFlags; + UINT32 GTxCommonFlags; +} EFI_ACPI_6_5_GTDT_GT_BLOCK_TIMER_STRUCTURE; + +/// +/// GT Block Physical Timers and Virtual Timers Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_5_GTDT_GT_BLOCK_TIMER_FLAG_TIMER_INTERRUPT_POLARITY BIT1 + +/// +/// Common Flags Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_GTDT_GT_BLOCK_COMMON_FLAG_SECURE_TIMER BIT0 +#define EFI_ACPI_6_5_GTDT_GT_BLOCK_COMMON_FLAG_ALWAYS_ON_CAPABILITY BIT1 + +/// +/// Arm Generic Watchdog Structure +/// +typedef struct { + UINT8 Type; + UINT16 Length; + UINT8 Reserved; + UINT64 RefreshFramePhysicalAddress; + UINT64 WatchdogControlFramePhysicalAddress; + UINT32 WatchdogTimerGSIV; + UINT32 WatchdogTimerFlags; +} EFI_ACPI_6_5_GTDT_ARM_GENERIC_WATCHDOG_STRUCTURE; + +/// +/// Arm Generic Watchdog Timer Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_6_5_GTDT_ARM_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_MODE BIT0 +#define EFI_ACPI_6_5_GTDT_ARM_GENERIC_WATCHDOG_FLAG_TIMER_INTERRUPT_POLARITY BIT1 +#define EFI_ACPI_6_5_GTDT_ARM_GENERIC_WATCHDOG_FLAG_SECURE_TIMER BIT2 + +// +// NVDIMM Firmware Interface Table definition. +// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Reserved; +} EFI_ACPI_6_5_NVDIMM_FIRMWARE_INTERFACE_TABLE; + +// +// NFIT Version (as defined in ACPI 6.5 spec.) +// +#define EFI_ACPI_6_5_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION 0x1 + +// +// Definition for NFIT Table Structure Types +// +#define EFI_ACPI_6_5_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE 0 +#define EFI_ACPI_6_5_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE_TYPE 1 +#define EFI_ACPI_6_5_NFIT_INTERLEAVE_STRUCTURE_TYPE 2 +#define EFI_ACPI_6_5_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE_TYPE 3 +#define EFI_ACPI_6_5_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE_TYPE 4 +#define EFI_ACPI_6_5_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE_TYPE 5 +#define EFI_ACPI_6_5_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE_TYPE 6 +#define EFI_ACPI_6_5_NFIT_PLATFORM_CAPABILITIES_STRUCTURE_TYPE 7 + +// +// Definition for NFIT Structure Header +// +typedef struct { + UINT16 Type; + UINT16 Length; +} EFI_ACPI_6_5_NFIT_STRUCTURE_HEADER; + +// +// Definition for System Physical Address Range Structure +// +#define EFI_ACPI_6_5_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_CONTROL_REGION_FOR_MANAGEMENT BIT0 +#define EFI_ACPI_6_5_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_PROXIMITY_DOMAIN_VALID BIT1 +#define EFI_ACPI_6_5_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_FLAGS_SPA_LOCATION_COOKIE_VALID BIT2 + +#define EFI_ACPI_6_5_NFIT_GUID_VOLATILE_MEMORY_REGION { 0x7305944F, 0xFDDA, 0x44E3, { 0xB1, 0x6C, 0x3F, 0x22, 0xD2, 0x52, 0xE5, 0xD0 }} +#define EFI_ACPI_6_5_NFIT_GUID_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_REGION { 0x66F0D379, 0xB4F3, 0x4074, { 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB }} +#define EFI_ACPI_6_5_NFIT_GUID_NVDIMM_CONTROL_REGION { 0x92F701F6, 0x13B4, 0x405D, { 0x91, 0x0B, 0x29, 0x93, 0x67, 0xE8, 0x23, 0x4C }} +#define EFI_ACPI_6_5_NFIT_GUID_NVDIMM_BLOCK_DATA_WINDOW_REGION { 0x91AF0530, 0x5D86, 0x470E, { 0xA6, 0xB0, 0x0A, 0x2D, 0xB9, 0x40, 0x82, 0x49 }} +#define EFI_ACPI_6_5_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_VOLATILE { 0x77AB535A, 0x45FC, 0x6.5B, { 0x55, 0x60, 0xF7, 0xB2, 0x81, 0xD1, 0xF9, 0x6E }} +#define EFI_ACPI_6_5_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_VOLATILE { 0x3D5ABD30, 0x4175, 0x87CE, { 0x6D, 0x64, 0xD2, 0xAD, 0xE5, 0x23, 0xC4, 0xBB }} +#define EFI_ACPI_6_5_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_DISK_REGION_PERSISTENT { 0x5CEA02C9, 0x4D07, 0x69D3, { 0x26, 0x9F ,0x44, 0x96, 0xFB, 0xE0, 0x96, 0xF9 }} +#define EFI_ACPI_6_5_NFIT_GUID_RAM_DISK_SUPPORTING_VIRTUAL_CD_REGION_PERSISTENT { 0x08018188, 0x42CD, 0xBB48, { 0x10, 0x0F, 0x53, 0x87, 0xD5, 0x3D, 0xED, 0x3D }} + +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 SPARangeStructureIndex; + UINT16 Flags; + UINT32 Reserved_8; + UINT32 ProximityDomain; + GUID AddressRangeTypeGUID; + UINT64 SystemPhysicalAddressRangeBase; + UINT64 SystemPhysicalAddressRangeLength; + UINT64 AddressRangeMemoryMappingAttribute; + UINT64 SPALocationCookie; +} EFI_ACPI_6_5_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE; + +// +// Definition for Memory Device to System Physical Address Range Mapping Structure +// +typedef struct { + UINT32 DIMMNumber : 4; + UINT32 MemoryChannelNumber : 4; + UINT32 MemoryControllerID : 4; + UINT32 SocketID : 4; + UINT32 NodeControllerID : 12; + UINT32 Reserved_28 : 4; +} EFI_ACPI_6_5_NFIT_DEVICE_HANDLE; + +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_PREVIOUS_SAVE_FAIL BIT0 +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_LAST_RESTORE_FAIL BIT1 +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_PLATFORM_FLUSH_FAIL BIT2 +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_NOT_ARMED_PRIOR_TO_OSPM_HAND_OFF BIT3 +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_SMART_HEALTH_EVENTS_PRIOR_OSPM_HAND_OFF BIT4 +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_ENABLED_TO_NOTIFY_OSPM_ON_SMART_HEALTH_EVENTS BIT5 +#define EFI_ACPI_6_5_NFIT_MEMORY_DEVICE_STATE_FLAGS_FIRMWARE_NOT_MAP_NVDIMM_TO_SPA BIT6 + +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_5_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NVDIMMPhysicalID; + UINT16 NVDIMMRegionID; + UINT16 SPARangeStructureIndex; + UINT16 NVDIMMControlRegionStructureIndex; + UINT64 NVDIMMRegionSize; + UINT64 RegionOffset; + UINT64 NVDIMMPhysicalAddressRegionBase; + UINT16 InterleaveStructureIndex; + UINT16 InterleaveWays; + UINT16 NVDIMMStateFlags; + UINT16 Reserved_46; +} EFI_ACPI_6_5_NFIT_NVDIMM_REGION_MAPPING_STRUCTURE; + +// +// Definition for Interleave Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 InterleaveStructureIndex; + UINT16 Reserved_6; + UINT32 NumberOfLines; + UINT32 LineSize; + // UINT32 LineOffset[NumberOfLines]; +} EFI_ACPI_6_5_NFIT_INTERLEAVE_STRUCTURE; + +// +// Definition for SMBIOS Management Information Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT32 Reserved_4; + // UINT8 Data[]; +} EFI_ACPI_6_5_NFIT_SMBIOS_MANAGEMENT_INFORMATION_STRUCTURE; + +// +// Definition for NVDIMM Control Region Structure +// +#define EFI_ACPI_6_5_NFIT_NVDIMM_CONTROL_REGION_VALID_FIELDS_MANUFACTURING BIT0 + +#define EFI_ACPI_6_5_NFIT_NVDIMM_CONTROL_REGION_FLAGS_BLOCK_DATA_WINDOWS_BUFFERED BIT0 + +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 RevisionID; + UINT16 SubsystemVendorID; + UINT16 SubsystemDeviceID; + UINT16 SubsystemRevisionID; + UINT8 ValidFields; + UINT8 ManufacturingLocation; + UINT16 ManufacturingDate; + UINT8 Reserved_22[2]; + UINT32 SerialNumber; + UINT16 RegionFormatInterfaceCode; + UINT16 NumberOfBlockControlWindows; + UINT64 SizeOfBlockControlWindow; + UINT64 CommandRegisterOffsetInBlockControlWindow; + UINT64 SizeOfCommandRegisterInBlockControlWindows; + UINT64 StatusRegisterOffsetInBlockControlWindow; + UINT64 SizeOfStatusRegisterInBlockControlWindows; + UINT16 NVDIMMControlRegionFlag; + UINT8 Reserved_74[6]; +} EFI_ACPI_6_5_NFIT_NVDIMM_CONTROL_REGION_STRUCTURE; + +// +// Definition for NVDIMM Block Data Window Region Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT16 NVDIMMControlRegionStructureIndex; + UINT16 NumberOfBlockDataWindows; + UINT64 BlockDataWindowStartOffset; + UINT64 SizeOfBlockDataWindow; + UINT64 BlockAccessibleMemoryCapacity; + UINT64 BeginningAddressOfFirstBlockInBlockAccessibleMemory; +} EFI_ACPI_6_5_NFIT_NVDIMM_BLOCK_DATA_WINDOW_REGION_STRUCTURE; + +// +// Definition for Flush Hint Address Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + EFI_ACPI_6_5_NFIT_DEVICE_HANDLE NFITDeviceHandle; + UINT16 NumberOfFlushHintAddresses; + UINT8 Reserved_10[6]; + // UINT64 FlushHintAddress[NumberOfFlushHintAddresses]; +} EFI_ACPI_6_5_NFIT_FLUSH_HINT_ADDRESS_STRUCTURE; + +// +// Definition for Platform Capabilities Structure +// +typedef struct { + UINT16 Type; + UINT16 Length; + UINT8 HighestValidCapability; + UINT8 Reserved_5[3]; + UINT32 Capabilities; + UINT8 Reserved_12[4]; +} EFI_ACPI_6_5_NFIT_PLATFORM_CAPABILITIES_STRUCTURE; + +#define EFI_ACPI_6_5_NFIT_PLATFORM_CAPABILITY_CPU_CACHE_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT0 +#define EFI_ACPI_6_5_NFIT_PLATFORM_CAPABILITY_MEMORY_CONTROLLER_FLUSH_TO_NVDIMM_DURABILITY_ON_POWER_LOSS BIT1 +#define EFI_ACPI_6_5_NFIT_PLATFORM_CAPABILITY_BYTE_ADDRESSABLE_PERSISTENT_MEMORY_HARDWARE_MIRRORING BIT2 + +/// +/// Secure DEVices Table (SDEV) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_5_SECURE_DEVICES_TABLE_HEADER; + +/// +/// SDEV Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_SECURE_DEVICES_TABLE_REVISION 0x01 + +/// +/// Secure Device types +/// +#define EFI_ACPI_6_5_SDEV_TYPE_ACPI_NAMESPACE_DEVICE 0x00 +#define EFI_ACPI_6_5_SDEV_TYPE_PCIE_ENDPOINT_DEVICE 0x01 + +/// +/// Secure Device flags +/// +#define EFI_ACPI_6_5_SDEV_FLAG_ALLOW_HANDOFF BIT0 +#define EFI_ACPI_6_5_SDEV_FLAG_SECURE_ACCESS_COMPONENTS_PRESENT BIT1 + +/// +/// SDEV Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Flags; + UINT16 Length; +} EFI_ACPI_6_5_SDEV_STRUCTURE_HEADER; + +/// +/// ACPI_NAMESPACE_DEVICE based Secure Device Structure +/// +typedef struct { + EFI_ACPI_6_5_SDEV_STRUCTURE_HEADER Header; + UINT16 DeviceIdentifierOffset; + UINT16 DeviceIdentifierLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; + UINT16 SecureAccessComponentsOffset; + UINT16 SecureAccessComponentsLength; +} EFI_ACPI_6_5_SDEV_STRUCTURE_ACPI_NAMESPACE_DEVICE; + +/// +/// Secure Access Component Types +/// +#define EFI_ACPI_6_5_SDEV_SECURE_ACCESS_COMPONENT_TYPE_IDENTIFICATION 0x00 +#define EFI_ACPI_6_5_SDEV_SECURE_ACCESS_COMPONENT_TYPE_MEMORY 0x01 + +/// +/// Identification Based Secure Access Component +/// +typedef struct { + EFI_ACPI_6_5_SDEV_STRUCTURE_HEADER Header; + UINT16 HardwareIdentifierOffset; + UINT16 HardwareIdentifierLength; + UINT16 SubsystemIdentifierOffset; + UINT16 SubsystemIdentifierLength; + UINT16 HardwareRevision; + UINT8 HardwareRevisionPresent; + UINT8 ClassCodePresent; + UINT8 PciCompatibleBaseClass; + UINT8 PciCompatibleSubClass; + UINT8 PciCompatibleProgrammingInterface; +} EFI_ACPI_6_5_SDEV_SECURE_ACCESS_COMPONENT_IDENTIFICATION_STRUCTURE; + +/// +/// Memory-based Secure Access Component +/// +typedef struct { + EFI_ACPI_6_5_SDEV_STRUCTURE_HEADER Header; + UINT32 Reserved; + UINT64 MemoryAddressBase; + UINT64 MemoryLength; +} EFI_ACPI_6_5_SDEV_SECURE_ACCESS_COMPONENT_MEMORY_STRUCTURE; + +/// +/// PCIe Endpoint Device based Secure Device Structure +/// +typedef struct { + EFI_ACPI_6_5_SDEV_STRUCTURE_HEADER Header; + UINT16 PciSegmentNumber; + UINT16 StartBusNumber; + UINT16 PciPathOffset; + UINT16 PciPathLength; + UINT16 VendorSpecificDataOffset; + UINT16 VendorSpecificDataLength; +} EFI_ACPI_6_5_SDEV_STRUCTURE_PCIE_ENDPOINT_DEVICE; + +/// +/// Boot Error Record Table (BERT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 BootErrorRegionLength; + UINT64 BootErrorRegion; +} EFI_ACPI_6_5_BOOT_ERROR_RECORD_TABLE_HEADER; + +/// +/// BERT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_BOOT_ERROR_RECORD_TABLE_REVISION 0x01 + +/// +/// Boot Error Region Block Status Definition +/// +typedef struct { + UINT32 UncorrectableErrorValid : 1; + UINT32 CorrectableErrorValid : 1; + UINT32 MultipleUncorrectableErrors : 1; + UINT32 MultipleCorrectableErrors : 1; + UINT32 ErrorDataEntryCount : 10; + UINT32 Reserved : 18; +} EFI_ACPI_6_5_ERROR_BLOCK_STATUS; + +/// +/// Boot Error Region Definition +/// +typedef struct { + EFI_ACPI_6_5_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_5_BOOT_ERROR_REGION_STRUCTURE; + +// +// Boot Error Severity types +// +#define EFI_ACPI_6_5_ERROR_SEVERITY_RECOVERABLE 0x00 +#define EFI_ACPI_6_5_ERROR_SEVERITY_FATAL 0x01 +#define EFI_ACPI_6_5_ERROR_SEVERITY_CORRECTED 0x02 +#define EFI_ACPI_6_5_ERROR_SEVERITY_NONE 0x03 +// +// The term 'Correctable' is no longer being used as an error severity of the +// reported error since ACPI Specification Version 5.1 Errata B. +// The below macro is considered as deprecated and should no longer be used. +// +#define EFI_ACPI_6_5_ERROR_SEVERITY_CORRECTABLE 0x00 + +/// +/// Generic Error Data Entry Definition +/// +typedef struct { + UINT8 SectionType[16]; + UINT32 ErrorSeverity; + UINT16 Revision; + UINT8 ValidationBits; + UINT8 Flags; + UINT32 ErrorDataLength; + UINT8 FruId[16]; + UINT8 FruText[20]; + UINT8 Timestamp[8]; +} EFI_ACPI_6_5_GENERIC_ERROR_DATA_ENTRY_STRUCTURE; + +/// +/// Generic Error Data Entry Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_GENERIC_ERROR_DATA_ENTRY_REVISION 0x0300 + +/// +/// HEST - Hardware Error Source Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 ErrorSourceCount; +} EFI_ACPI_6_5_HARDWARE_ERROR_SOURCE_TABLE_HEADER; + +/// +/// HEST Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_HARDWARE_ERROR_SOURCE_TABLE_REVISION 0x01 + +// +// Error Source structure types. +// +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION 0x00 +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK 0x01 +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_NMI_ERROR 0x02 +#define EFI_ACPI_6_5_PCI_EXPRESS_ROOT_PORT_AER 0x06 +#define EFI_ACPI_6_5_PCI_EXPRESS_DEVICE_AER 0x07 +#define EFI_ACPI_6_5_PCI_EXPRESS_BRIDGE_AER 0x08 +#define EFI_ACPI_6_5_GENERIC_HARDWARE_ERROR 0x09 +#define EFI_ACPI_6_5_GENERIC_HARDWARE_ERROR_VERSION_2 0x0A +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK 0x0B + +// +// Error Source structure flags. +// +#define EFI_ACPI_6_5_ERROR_SOURCE_FLAG_FIRMWARE_FIRST (1 << 0) +#define EFI_ACPI_6_5_ERROR_SOURCE_FLAG_GLOBAL (1 << 1) +#define EFI_ACPI_6_5_ERROR_SOURCE_FLAG_GHES_ASSIST (1 << 2) + +/// +/// IA-32 Architecture Machine Check Exception Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT64 GlobalCapabilityInitData; + UINT64 GlobalControlInitData; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[7]; +} EFI_ACPI_6_5_IA32_ARCHITECTURE_MACHINE_CHECK_EXCEPTION_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure Definition +/// +typedef struct { + UINT8 BankNumber; + UINT8 ClearStatusOnInitialization; + UINT8 StatusDataFormat; + UINT8 Reserved0; + UINT32 ControlRegisterMsrAddress; + UINT64 ControlInitData; + UINT32 StatusRegisterMsrAddress; + UINT32 AddressRegisterMsrAddress; + UINT32 MiscRegisterMsrAddress; +} EFI_ACPI_6_5_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_BANK_STRUCTURE; + +/// +/// IA-32 Architecture Machine Check Bank Structure MCA data format +/// +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_IA32 0x00 +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_INTEL64 0x01 +#define EFI_ACPI_6_5_IA32_ARCHITECTURE_MACHINE_CHECK_ERROR_DATA_FORMAT_AMD64 0x02 + +// +// Hardware Error Notification types. All other values are reserved +// +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_POLLED 0x00 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_EXTERNAL_INTERRUPT 0x01 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_LOCAL_INTERRUPT 0x02 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_SCI 0x03 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_NMI 0x04 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_CMCI 0x05 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_MCE 0x06 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_GPIO_SIGNAL 0x07 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEA 0x08 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_ARMV8_SEI 0x09 +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_GSIV 0x0A +#define EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_SOFTWARE_DELEGATED_EXCEPTION 0x0B + +/// +/// Hardware Error Notification Configuration Write Enable Structure Definition +/// +typedef struct { + UINT16 Type : 1; + UINT16 PollInterval : 1; + UINT16 SwitchToPollingThresholdValue : 1; + UINT16 SwitchToPollingThresholdWindow : 1; + UINT16 ErrorThresholdValue : 1; + UINT16 ErrorThresholdWindow : 1; + UINT16 Reserved : 10; +} EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE; + +/// +/// Hardware Error Notification Structure Definition +/// +typedef struct { + UINT8 Type; + UINT8 Length; + EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_CONFIGURATION_WRITE_ENABLE_STRUCTURE ConfigurationWriteEnable; + UINT32 PollInterval; + UINT32 Vector; + UINT32 SwitchToPollingThresholdValue; + UINT32 SwitchToPollingThresholdWindow; + UINT32 ErrorThresholdValue; + UINT32 ErrorThresholdWindow; +} EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_STRUCTURE; + +/// +/// IA-32 Architecture Corrected Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_5_IA32_ARCHITECTURE_CORRECTED_MACHINE_CHECK_STRUCTURE; + +/// +/// IA-32 Architecture NMI Error Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; +} EFI_ACPI_6_5_IA32_ARCHITECTURE_NMI_ERROR_STRUCTURE; + +/// +/// PCI Express Root Port AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 RootErrorCommand; +} EFI_ACPI_6_5_PCI_EXPRESS_ROOT_PORT_AER_STRUCTURE; + +/// +/// PCI Express Device AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_5_PCI_EXPRESS_DEVICE_AER_STRUCTURE; + +/// +/// PCI Express Bridge AER Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 Bus; + UINT16 Device; + UINT16 Function; + UINT16 DeviceControl; + UINT8 Reserved1[2]; + UINT32 UncorrectableErrorMask; + UINT32 UncorrectableErrorSeverity; + UINT32 CorrectableErrorMask; + UINT32 AdvancedErrorCapabilitiesAndControl; + UINT32 SecondaryUncorrectableErrorMask; + UINT32 SecondaryUncorrectableErrorSeverity; + UINT32 SecondaryAdvancedErrorCapabilitiesAndControl; +} EFI_ACPI_6_5_PCI_EXPRESS_BRIDGE_AER_STRUCTURE; + +/// +/// Generic Hardware Error Source Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; +} EFI_ACPI_6_5_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE; + +/// +/// Generic Hardware Error Source Version 2 Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT16 RelatedSourceId; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + UINT32 MaxRawDataLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE ErrorStatusAddress; + EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT32 ErrorStatusBlockLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE ReadAckRegister; + UINT64 ReadAckPreserve; + UINT64 ReadAckWrite; +} EFI_ACPI_6_5_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE; + +/// +/// Generic Error Status Definition +/// +typedef struct { + EFI_ACPI_6_5_ERROR_BLOCK_STATUS BlockStatus; + UINT32 RawDataOffset; + UINT32 RawDataLength; + UINT32 DataLength; + UINT32 ErrorSeverity; +} EFI_ACPI_6_5_GENERIC_ERROR_STATUS_STRUCTURE; + +/// +/// IA-32 Architecture Deferred Machine Check Structure Definition +/// +typedef struct { + UINT16 Type; + UINT16 SourceId; + UINT8 Reserved0[2]; + UINT8 Flags; + UINT8 Enabled; + UINT32 NumberOfRecordsToPreAllocate; + UINT32 MaxSectionsPerRecord; + EFI_ACPI_6_5_HARDWARE_ERROR_NOTIFICATION_STRUCTURE NotificationStructure; + UINT8 NumberOfHardwareBanks; + UINT8 Reserved1[3]; +} EFI_ACPI_6_5_IA32_ARCHITECTURE_DEFERRED_MACHINE_CHECK_STRUCTURE; + +/// +/// HMAT - Heterogeneous Memory Attribute Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 Reserved[4]; +} EFI_ACPI_6_5_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER; + +/// +/// HMAT Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_REVISION 0x02 + +/// +/// HMAT types +/// +#define EFI_ACPI_6_5_HMAT_TYPE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES 0x00 +#define EFI_ACPI_6_5_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO 0x01 +#define EFI_ACPI_6_5_HMAT_TYPE_MEMORY_SIDE_CACHE_INFO 0x02 + +/// +/// HMAT Structure Header +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; +} EFI_ACPI_6_5_HMAT_STRUCTURE_HEADER; + +/// +/// Memory Proximity Domain Attributes Structure flags +/// +typedef struct { + UINT16 InitiatorProximityDomainValid : 1; + UINT16 Reserved : 15; +} EFI_ACPI_6_5_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES_FLAGS; + +/// +/// Memory Proximity Domain Attributes Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_5_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES_FLAGS Flags; + UINT8 Reserved1[2]; + UINT32 InitiatorProximityDomain; + UINT32 MemoryProximityDomain; + UINT8 Reserved2[20]; +} EFI_ACPI_6_5_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES; + +/// +/// System Locality Latency and Bandwidth Information Structure flags +/// +typedef struct { + UINT8 MemoryHierarchy : 4; + UINT8 AccessAttributes : 2; + UINT8 Reserved : 2; +} EFI_ACPI_6_5_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS; + +/// +/// System Locality Latency and Bandwidth Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + EFI_ACPI_6_5_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS Flags; + UINT8 DataType; + UINT8 MinTransferSize; + UINT8 Reserved1; + UINT32 NumberOfInitiatorProximityDomains; + UINT32 NumberOfTargetProximityDomains; + UINT8 Reserved2[4]; + UINT64 EntryBaseUnit; +} EFI_ACPI_6_5_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO; + +/// +/// Memory Side Cache Information Structure cache attributes +/// +typedef struct { + UINT32 TotalCacheLevels : 4; + UINT32 CacheLevel : 4; + UINT32 CacheAssociativity : 4; + UINT32 WritePolicy : 4; + UINT32 CacheLineSize : 16; +} EFI_ACPI_6_5_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES; + +/// +/// Memory Side Cache Information Structure +/// +typedef struct { + UINT16 Type; + UINT8 Reserved[2]; + UINT32 Length; + UINT32 MemoryProximityDomain; + UINT8 Reserved1[4]; + UINT64 MemorySideCacheSize; + EFI_ACPI_6_5_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES CacheAttributes; + UINT8 Reserved2[2]; + UINT16 NumberOfSmbiosHandles; +} EFI_ACPI_6_5_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO; + +/// +/// ERST - Error Record Serialization Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 SerializationHeaderSize; + UINT8 Reserved0[4]; + UINT32 InstructionEntryCount; +} EFI_ACPI_6_5_ERROR_RECORD_SERIALIZATION_TABLE_HEADER; + +/// +/// ERST Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_ERROR_RECORD_SERIALIZATION_TABLE_REVISION 0x01 + +/// +/// ERST Serialization Actions +/// +#define EFI_ACPI_6_5_ERST_BEGIN_WRITE_OPERATION 0x00 +#define EFI_ACPI_6_5_ERST_BEGIN_READ_OPERATION 0x01 +#define EFI_ACPI_6_5_ERST_BEGIN_CLEAR_OPERATION 0x02 +#define EFI_ACPI_6_5_ERST_END_OPERATION 0x03 +#define EFI_ACPI_6_5_ERST_SET_RECORD_OFFSET 0x04 +#define EFI_ACPI_6_5_ERST_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_5_ERST_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_5_ERST_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_5_ERST_GET_RECORD_IDENTIFIER 0x08 +#define EFI_ACPI_6_5_ERST_SET_RECORD_IDENTIFIER 0x09 +#define EFI_ACPI_6_5_ERST_GET_RECORD_COUNT 0x0A +#define EFI_ACPI_6_5_ERST_BEGIN_DUMMY_WRITE_OPERATION 0x0B +#define EFI_ACPI_6_5_ERST_GET_ERROR_LOG_ADDRESS_RANGE 0x0D +#define EFI_ACPI_6_5_ERST_GET_ERROR_LOG_ADDRESS_RANGE_LENGTH 0x0E +#define EFI_ACPI_6_5_ERST_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0x0F +#define EFI_ACPI_6_5_ERST_GET_EXECUTE_OPERATION_TIMINGS 0x10 + +/// +/// ERST Action Command Status +/// +#define EFI_ACPI_6_5_ERST_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_5_ERST_STATUS_NOT_ENOUGH_SPACE 0x01 +#define EFI_ACPI_6_5_ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define EFI_ACPI_6_5_ERST_STATUS_FAILED 0x03 +#define EFI_ACPI_6_5_ERST_STATUS_RECORD_STORE_EMPTY 0x04 +#define EFI_ACPI_6_5_ERST_STATUS_RECORD_NOT_FOUND 0x05 + +/// +/// ERST Serialization Instructions +/// +#define EFI_ACPI_6_5_ERST_READ_REGISTER 0x00 +#define EFI_ACPI_6_5_ERST_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_5_ERST_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_5_ERST_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_5_ERST_NOOP 0x04 +#define EFI_ACPI_6_5_ERST_LOAD_VAR1 0x05 +#define EFI_ACPI_6_5_ERST_LOAD_VAR2 0x06 +#define EFI_ACPI_6_5_ERST_STORE_VAR1 0x07 +#define EFI_ACPI_6_5_ERST_ADD 0x08 +#define EFI_ACPI_6_5_ERST_SUBTRACT 0x09 +#define EFI_ACPI_6_5_ERST_ADD_VALUE 0x0A +#define EFI_ACPI_6_5_ERST_SUBTRACT_VALUE 0x0B +#define EFI_ACPI_6_5_ERST_STALL 0x0C +#define EFI_ACPI_6_5_ERST_STALL_WHILE_TRUE 0x0D +#define EFI_ACPI_6_5_ERST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define EFI_ACPI_6_5_ERST_GOTO 0x0F +#define EFI_ACPI_6_5_ERST_SET_SRC_ADDRESS_BASE 0x10 +#define EFI_ACPI_6_5_ERST_SET_DST_ADDRESS_BASE 0x11 +#define EFI_ACPI_6_5_ERST_MOVE_DATA 0x12 + +/// +/// ERST Instruction Flags +/// +#define EFI_ACPI_6_5_ERST_PRESERVE_REGISTER 0x01 + +/// +/// ERST Serialization Instruction Entry +/// +typedef struct { + UINT8 SerializationAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_5_ERST_SERIALIZATION_INSTRUCTION_ENTRY; + +/// +/// EINJ - Error Injection Table +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 InjectionHeaderSize; + UINT8 InjectionFlags; + UINT8 Reserved0[3]; + UINT32 InjectionEntryCount; +} EFI_ACPI_6_5_ERROR_INJECTION_TABLE_HEADER; + +/// +/// EINJ Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_ERROR_INJECTION_TABLE_REVISION 0x01 + +/// +/// EINJ Error Injection Actions +/// +#define EFI_ACPI_6_5_EINJ_BEGIN_INJECTION_OPERATION 0x00 +#define EFI_ACPI_6_5_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE 0x01 +#define EFI_ACPI_6_5_EINJ_SET_ERROR_TYPE 0x02 +#define EFI_ACPI_6_5_EINJ_GET_ERROR_TYPE 0x03 +#define EFI_ACPI_6_5_EINJ_END_OPERATION 0x04 +#define EFI_ACPI_6_5_EINJ_EXECUTE_OPERATION 0x05 +#define EFI_ACPI_6_5_EINJ_CHECK_BUSY_STATUS 0x06 +#define EFI_ACPI_6_5_EINJ_GET_COMMAND_STATUS 0x07 +#define EFI_ACPI_6_5_EINJ_TRIGGER_ERROR 0xFF + +/// +/// EINJ Action Command Status +/// +#define EFI_ACPI_6_5_EINJ_STATUS_SUCCESS 0x00 +#define EFI_ACPI_6_5_EINJ_STATUS_UNKNOWN_FAILURE 0x01 +#define EFI_ACPI_6_5_EINJ_STATUS_INVALID_ACCESS 0x02 + +/// +/// EINJ Error Type Definition +/// +#define EFI_ACPI_6_5_EINJ_ERROR_PROCESSOR_CORRECTABLE (1 << 0) +#define EFI_ACPI_6_5_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_NONFATAL (1 << 1) +#define EFI_ACPI_6_5_EINJ_ERROR_PROCESSOR_UNCORRECTABLE_FATAL (1 << 2) +#define EFI_ACPI_6_5_EINJ_ERROR_MEMORY_CORRECTABLE (1 << 3) +#define EFI_ACPI_6_5_EINJ_ERROR_MEMORY_UNCORRECTABLE_NONFATAL (1 << 4) +#define EFI_ACPI_6_5_EINJ_ERROR_MEMORY_UNCORRECTABLE_FATAL (1 << 5) +#define EFI_ACPI_6_5_EINJ_ERROR_PCI_EXPRESS_CORRECTABLE (1 << 6) +#define EFI_ACPI_6_5_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_NONFATAL (1 << 7) +#define EFI_ACPI_6_5_EINJ_ERROR_PCI_EXPRESS_UNCORRECTABLE_FATAL (1 << 8) +#define EFI_ACPI_6_5_EINJ_ERROR_PLATFORM_CORRECTABLE (1 << 9) +#define EFI_ACPI_6_5_EINJ_ERROR_PLATFORM_UNCORRECTABLE_NONFATAL (1 << 10) +#define EFI_ACPI_6_5_EINJ_ERROR_PLATFORM_UNCORRECTABLE_FATAL (1 << 11) + +/// +/// EINJ Injection Instructions +/// +#define EFI_ACPI_6_5_EINJ_READ_REGISTER 0x00 +#define EFI_ACPI_6_5_EINJ_READ_REGISTER_VALUE 0x01 +#define EFI_ACPI_6_5_EINJ_WRITE_REGISTER 0x02 +#define EFI_ACPI_6_5_EINJ_WRITE_REGISTER_VALUE 0x03 +#define EFI_ACPI_6_5_EINJ_NOOP 0x04 + +/// +/// EINJ Instruction Flags +/// +#define EFI_ACPI_6_5_EINJ_PRESERVE_REGISTER 0x01 + +/// +/// EINJ Injection Instruction Entry +/// +typedef struct { + UINT8 InjectionAction; + UINT8 Instruction; + UINT8 Flags; + UINT8 Reserved0; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE RegisterRegion; + UINT64 Value; + UINT64 Mask; +} EFI_ACPI_6_5_EINJ_INJECTION_INSTRUCTION_ENTRY; + +/// +/// EINJ Trigger Action Table +/// +typedef struct { + UINT32 HeaderSize; + UINT32 Revision; + UINT32 TableSize; + UINT32 EntryCount; +} EFI_ACPI_6_5_EINJ_TRIGGER_ACTION_TABLE; + +/// +/// Platform Communications Channel Table (PCCT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 Flags; + UINT64 Reserved; +} EFI_ACPI_6_5_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER; + +/// +/// PCCT Version (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION 0x02 + +/// +/// PCCT Global Flags +/// +#define EFI_ACPI_6_5_PCCT_FLAGS_PLATFORM_INTERRUPT BIT0 + +// +// PCCT Subspace type +// +#define EFI_ACPI_6_5_PCCT_SUBSPACE_TYPE_GENERIC 0x00 +#define EFI_ACPI_6_5_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS 0x01 +#define EFI_ACPI_6_5_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS 0x02 +#define EFI_ACPI_6_5_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC 0x03 +#define EFI_ACPI_6_5_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC 0x04 +#define EFI_ACPI_6_5_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS 0x05 + +/// +/// PCC Subspace Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; +} EFI_ACPI_6_5_PCCT_SUBSPACE_HEADER; + +/// +/// Generic Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[6]; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_5_PCCT_SUBSPACE_GENERIC; + +/// +/// Generic Communications Channel Shared Memory Region +/// + +typedef struct { + UINT8 Command; + UINT8 Reserved : 7; + UINT8 NotifyOnCompletion : 1; +} EFI_ACPI_6_5_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND; + +typedef struct { + UINT8 CommandComplete : 1; + UINT8 PlatformInterrupt : 1; + UINT8 Error : 1; + UINT8 PlatformNotification : 1; + UINT8 Reserved : 4; + UINT8 Reserved1; +} EFI_ACPI_6_5_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS; + +typedef struct { + UINT32 Signature; + EFI_ACPI_6_5_PCCT_GENERIC_SHARED_MEMORY_REGION_COMMAND Command; + EFI_ACPI_6_5_PCCT_GENERIC_SHARED_MEMORY_REGION_STATUS Status; +} EFI_ACPI_6_5_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER; + +#define EFI_ACPI_6_5_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_POLARITY BIT0 +#define EFI_ACPI_6_5_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE BIT1 + +/// +/// Type 1 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_5_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 2 HW-Reduced Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT64 AddressLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT16 MinimumRequestTurnaroundTime; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckWrite; +} EFI_ACPI_6_5_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS; + +/// +/// Type 3 Extended PCC Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 PlatformInterrupt; + UINT8 PlatformInterruptFlags; + UINT8 Reserved; + UINT64 BaseAddress; + UINT32 AddressLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + UINT32 NominalLatency; + UINT32 MaximumPeriodicAccessRate; + UINT32 MinimumRequestTurnaroundTime; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE PlatformInterruptAckRegister; + UINT64 PlatformInterruptAckPreserve; + UINT64 PlatformInterruptAckSet; + UINT8 Reserved1[8]; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE CommandCompleteCheckRegister; + UINT64 CommandCompleteCheckMask; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE CommandCompleteUpdateRegister; + UINT64 CommandCompleteUpdatePreserve; + UINT64 CommandCompleteUpdateSet; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE ErrorStatusRegister; + UINT64 ErrorStatusMask; +} EFI_ACPI_6_5_PCCT_SUBSPACE_3_EXTENDED_PCC; + +/// +/// Type 4 Extended PCC Subspace Structure +/// +typedef EFI_ACPI_6_5_PCCT_SUBSPACE_3_EXTENDED_PCC EFI_ACPI_6_5_PCCT_SUBSPACE_4_EXTENDED_PCC; + +#define EFI_ACPI_6_5_PCCT_MASTER_SLAVE_COMMUNICATIONS_CHANNEL_FLAGS_NOTIFY_ON_COMPLETION BIT0 + +typedef struct { + UINT32 Signature; + UINT32 Flags; + UINT32 Length; + UINT32 Command; +} EFI_ACPI_6_5_PCCT_EXTENDED_PCC_SHARED_MEMORY_REGION_HEADER; + +/// +/// Type 5 HW Registers based Communications Subspace Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Version; + UINT64 BaseAddress; + UINT64 SharedMemoryRangeLength; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE DoorbellRegister; + UINT64 DoorbellPreserve; + UINT64 DoorbellWrite; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE CommandCompleteCheckRegister; + UINT64 CommandCompleteCheckMask; + EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE ErrorStatusRegister; + UINT64 ErrorStatusMask; + UINT32 NominalLatency; + UINT32 MinimumRequestTurnaroundTime; +} EFI_ACPI_6_5_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS; + +/// +/// Reduced PCC Subspace Shared Memory Region +/// +typedef struct { + UINT32 Signature; + // UINT8 CommunicationSubspace[]; +} EFI_6_5_PCCT_REDUCED_PCC_SUBSPACE_SHARED_MEMORY_REGION; + +/// +/// Platform Debug Trigger Table (PDTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT8 TriggerCount; + UINT8 Reserved[3]; + UINT32 TriggerIdentifierArrayOffset; +} EFI_ACPI_6_5_PLATFORM_DEBUG_TRIGGER_TABLE_HEADER; + +/// +/// PDTT Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_PLATFORM_DEBUG_TRIGGER_TABLE_REVISION 0x00 + +/// +/// PDTT Platform Communication Channel Identifier Structure +/// +typedef struct { + UINT16 SubChannelIdentifer : 8; + UINT16 Runtime : 1; + UINT16 WaitForCompletion : 1; + UINT16 TriggerOrder : 1; + UINT16 Reserved : 5; +} EFI_ACPI_6_5_PDTT_PCC_IDENTIFIER; + +/// +/// PCC Commands Codes used by Platform Debug Trigger Table +/// +#define EFI_ACPI_6_5_PDTT_PCC_COMMAND_DOORBELL_ONLY 0x00 +#define EFI_ACPI_6_5_PDTT_PCC_COMMAND_VENDOR_SPECIFIC 0x01 + +/// +/// PDTT Platform Communication Channel +/// +typedef EFI_ACPI_6_5_PCCT_GENERIC_SHARED_MEMORY_REGION_HEADER EFI_ACPI_6_5_PDTT_PCC; + +/// +/// Processor Properties Topology Table (PPTT) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; +} EFI_ACPI_6_5_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER; + +/// +/// PPTT Revision (as defined in ACPI 6.5 spec.) +/// +#define EFI_ACPI_6_5_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION 0x03 + +/// +/// PPTT types +/// +#define EFI_ACPI_6_5_PPTT_TYPE_PROCESSOR 0x00 +#define EFI_ACPI_6_5_PPTT_TYPE_CACHE 0x01 + +/// +/// PPTT Structure Header +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; +} EFI_ACPI_6_5_PPTT_STRUCTURE_HEADER; + +/// +/// For PPTT struct processor flags +/// +#define EFI_ACPI_6_5_PPTT_PACKAGE_NOT_PHYSICAL 0x0 +#define EFI_ACPI_6_5_PPTT_PACKAGE_PHYSICAL 0x1 +#define EFI_ACPI_6_5_PPTT_PROCESSOR_ID_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_PROCESSOR_ID_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_PROCESSOR_IS_NOT_THREAD 0x0 +#define EFI_ACPI_6_5_PPTT_PROCESSOR_IS_THREAD 0x1 +#define EFI_ACPI_6_5_PPTT_NODE_IS_NOT_LEAF 0x0 +#define EFI_ACPI_6_5_PPTT_NODE_IS_LEAF 0x1 +#define EFI_ACPI_6_5_PPTT_IMPLEMENTATION_NOT_IDENTICAL 0x0 +#define EFI_ACPI_6_5_PPTT_IMPLEMENTATION_IDENTICAL 0x1 + +/// +/// Processor hierarchy node structure flags +/// +typedef struct { + UINT32 PhysicalPackage : 1; + UINT32 AcpiProcessorIdValid : 1; + UINT32 ProcessorIsAThread : 1; + UINT32 NodeIsALeaf : 1; + UINT32 IdenticalImplementation : 1; + UINT32 Reserved : 27; +} EFI_ACPI_6_5_PPTT_STRUCTURE_PROCESSOR_FLAGS; + +/// +/// Processor hierarchy node structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_5_PPTT_STRUCTURE_PROCESSOR_FLAGS Flags; + UINT32 Parent; + UINT32 AcpiProcessorId; + UINT32 NumberOfPrivateResources; +} EFI_ACPI_6_5_PPTT_STRUCTURE_PROCESSOR; + +/// +/// For PPTT struct cache flags +/// +#define EFI_ACPI_6_5_PPTT_CACHE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_CACHE_SIZE_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_NUMBER_OF_SETS_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_NUMBER_OF_SETS_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_ASSOCIATIVITY_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_ASSOCIATIVITY_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_ALLOCATION_TYPE_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_ALLOCATION_TYPE_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_CACHE_TYPE_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_CACHE_TYPE_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_WRITE_POLICY_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_WRITE_POLICY_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_LINE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_LINE_SIZE_VALID 0x1 +#define EFI_ACPI_6_5_PPTT_CACHE_ID_INVALID 0x0 +#define EFI_ACPI_6_5_PPTT_CACHE_ID_VALID 0x1 + +/// +/// Cache Type Structure flags +/// +typedef struct { + UINT32 SizePropertyValid : 1; + UINT32 NumberOfSetsValid : 1; + UINT32 AssociativityValid : 1; + UINT32 AllocationTypeValid : 1; + UINT32 CacheTypeValid : 1; + UINT32 WritePolicyValid : 1; + UINT32 LineSizeValid : 1; + UINT32 CacheIdValid : 1; + UINT32 Reserved : 24; +} EFI_ACPI_6_5_PPTT_STRUCTURE_CACHE_FLAGS; + +/// +/// For cache attributes +/// +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_ALLOCATION_READ 0x0 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_ALLOCATION_WRITE 0x1 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE 0x2 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_CACHE_TYPE_DATA 0x0 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_CACHE_TYPE_INSTRUCTION 0x1 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_CACHE_TYPE_UNIFIED 0x2 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK 0x0 +#define EFI_ACPI_6_5_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_THROUGH 0x1 + +/// +/// Cache Type Structure cache attributes +/// +typedef struct { + UINT8 AllocationType : 2; + UINT8 CacheType : 2; + UINT8 WritePolicy : 1; + UINT8 Reserved : 3; +} EFI_ACPI_6_5_PPTT_STRUCTURE_CACHE_ATTRIBUTES; + +/// +/// Cache Type Structure +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Reserved[2]; + EFI_ACPI_6_5_PPTT_STRUCTURE_CACHE_FLAGS Flags; + UINT32 NextLevelOfCache; + UINT32 Size; + UINT32 NumberOfSets; + UINT8 Associativity; + EFI_ACPI_6_5_PPTT_STRUCTURE_CACHE_ATTRIBUTES Attributes; + UINT16 LineSize; + UINT32 CacheId; +} EFI_ACPI_6_5_PPTT_STRUCTURE_CACHE; + +/// +/// Platform Health Assessment Table (PHAT) Format +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + // UINT8 PlatformTelemetryRecords[]; +} EFI_ACPI_6_5_PLATFORM_HEALTH_ASSESSMENT_TABLE; + +#define EFI_ACPI_6_5_PLATFORM_HEALTH_ASSESSMENT_TABLE_REVISION 0x01 + +/// +/// PHAT Record Format +/// +typedef struct { + UINT16 PlatformHealthAssessmentRecordType; + UINT16 RecordLength; + UINT8 Revision; + // UINT8 Data[]; +} EFI_ACPI_6_5_PHAT_RECORD; + +/// +/// PHAT Record Type Format +/// +#define EFI_ACPI_6_5_PHAT_RECORD_TYPE_FIRMWARE_VERSION_DATA_RECORD 0x0000 +#define EFI_ACPI_6_5_PHAT_RECORD_TYPE_FIRMWARE_HEALTH_DATA_RECORD 0x0001 + +/// +/// PHAT Version Element +/// +typedef struct { + GUID ComponentId; + UINT64 VersionValue; + UINT32 ProducerId; +} EFI_ACPI_6_5_PHAT_VERSION_ELEMENT; + +/// +/// PHAT Firmware Version Data Record +/// +typedef struct { + UINT16 PlatformRecordType; + UINT16 RecordLength; + UINT8 Revision; + UINT8 Reserved[3]; + UINT32 RecordCount; + // UINT8 PhatVersionElement[]; +} EFI_ACPI_6_5_PHAT_FIRMWARE_VERISON_DATA_RECORD; + +#define EFI_ACPI_6_5_PHAT_FIRMWARE_VERSION_DATA_RECORD_REVISION 0x01 + +/// +/// Firmware Health Data Record Structure +/// +typedef struct { + UINT16 PlatformRecordType; + UINT16 RecordLength; + UINT8 Revision; + UINT16 Reserved; + UINT8 AmHealthy; + GUID DeviceSignature; + UINT32 DeviceSpecificDataOffset; + // UINT8 DevicePath[]; + // UINT8 DeviceSpecificData[]; +} EFI_ACPI_6_5_PHAT_FIRMWARE_HEALTH_DATA_RECORD_STRUCTURE; + +#define EFI_ACPI_6_5_PHAT_FIRMWARE_HEALTH_DATA_RECORD_REVISION 0x01 + +/// +/// Firmware Health Data Record device health state +/// +#define EFI_ACPI_6_5_PHAT_FIRMWARE_HEALTH_DATA_RECORD_ERRORS_FOUND 0x00 +#define EFI_ACPI_6_5_PHAT_FIRMWARE_HEALTH_DATA_RECORD_NO_ERRORS_FOUND 0x01 +#define EFI_ACPI_6_5_PHAT_FIRMWARE_HEALTH_DATA_RECORD_UNKNOWN 0x02 +#define EFI_ACPI_6_5_PHAT_FIRMWARE_HEALTH_DATA_RECORD_ADVISORY 0x03 + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer +/// +#define EFI_ACPI_6_5_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table +/// +#define EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "APMT" Arm Performance Monitoring Unit Table +/// +#define EFI_ACPI_6_5_ARM_PERFORMANCE_MONITORING_UNIT_TABLE_SIGNATURE SIGNATURE_32('A', 'P', 'M', 'T') + +/// +/// "BERT" Boot Error Record Table +/// +#define EFI_ACPI_6_5_BOOT_ERROR_RECORD_TABLE_SIGNATURE SIGNATURE_32('B', 'E', 'R', 'T') + +/// +/// "BGRT" Boot Graphics Resource Table +/// +#define EFI_ACPI_6_5_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('B', 'G', 'R', 'T') + +/// +/// "CDIT" Component Distance Information Table +/// +#define EFI_ACPI_6_5_COMPONENT_DISTANCE_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('C', 'D', 'I', 'T') + +/// +/// "CPEP" Corrected Platform Error Polling Table +/// +#define EFI_ACPI_6_5_CORRECTED_PLATFORM_ERROR_POLLING_TABLE_SIGNATURE SIGNATURE_32('C', 'P', 'E', 'P') + +/// +/// "CRAT" Component Resource Attribute Table +/// +#define EFI_ACPI_6_5_COMPONENT_RESOURCE_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('C', 'R', 'A', 'T') + +/// +/// "DSDT" Differentiated System Description Table +/// +#define EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "ECDT" Embedded Controller Boot Resources Table +/// +#define EFI_ACPI_6_5_EMBEDDED_CONTROLLER_BOOT_RESOURCES_TABLE_SIGNATURE SIGNATURE_32('E', 'C', 'D', 'T') + +/// +/// "EINJ" Error Injection Table +/// +#define EFI_ACPI_6_5_ERROR_INJECTION_TABLE_SIGNATURE SIGNATURE_32('E', 'I', 'N', 'J') + +/// +/// "ERST" Error Record Serialization Table +/// +#define EFI_ACPI_6_5_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE SIGNATURE_32('E', 'R', 'S', 'T') + +/// +/// "FACP" Fixed ACPI Description Table +/// +#define EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "FACS" Firmware ACPI Control Structure +/// +#define EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FPDT" Firmware Performance Data Table +/// +#define EFI_ACPI_6_5_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE SIGNATURE_32('F', 'P', 'D', 'T') + +/// +/// "GTDT" Generic Timer Description Table +/// +#define EFI_ACPI_6_5_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('G', 'T', 'D', 'T') + +/// +/// "HEST" Hardware Error Source Table +/// +#define EFI_ACPI_6_5_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('H', 'E', 'S', 'T') + +/// +/// "HMAT" Heterogeneous Memory Attribute Table +/// +#define EFI_ACPI_6_5_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE SIGNATURE_32('H', 'M', 'A', 'T') + +/// +/// "MPST" Memory Power State Table +/// +#define EFI_ACPI_6_5_MEMORY_POWER_STATE_TABLE_SIGNATURE SIGNATURE_32('M', 'P', 'S', 'T') + +/// +/// "MSCT" Maximum System Characteristics Table +/// +#define EFI_ACPI_6_5_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'C', 'T') + +/// +/// "NFIT" NVDIMM Firmware Interface Table +/// +#define EFI_ACPI_6_5_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('N', 'F', 'I', 'T') + +/// +/// "PDTT" Platform Debug Trigger Table +/// +#define EFI_ACPI_6_5_PLATFORM_DEBUG_TRIGGER_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'D', 'T', 'T') + +/// +/// "PMTT" Platform Memory Topology Table +/// +#define EFI_ACPI_6_5_PLATFORM_MEMORY_TOPOLOGY_TABLE_SIGNATURE SIGNATURE_32('P', 'M', 'T', 'T') + +/// +/// "PPTT" Processor Properties Topology Table +/// +#define EFI_ACPI_6_5_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('P', 'P', 'T', 'T') + +/// +/// "PSDT" Persistent System Description Table +/// +#define EFI_ACPI_6_5_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RASF" ACPI RAS Feature Table +/// +#define EFI_ACPI_6_5_ACPI_RAS_FEATURE_TABLE_SIGNATURE SIGNATURE_32('R', 'A', 'S', 'F') + +/// +/// "RSDT" Root System Description Table +/// +#define EFI_ACPI_6_5_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table +/// +#define EFI_ACPI_6_5_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SDEV" Secure DEVices Table +/// +#define EFI_ACPI_6_5_SECURE_DEVICES_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'V') + +/// +/// "SLIT" System Locality Information Table +/// +#define EFI_ACPI_6_5_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'T') + +/// +/// "SRAT" System Resource Affinity Table +/// +#define EFI_ACPI_6_5_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE SIGNATURE_32('S', 'R', 'A', 'T') + +/// +/// "SSDT" Secondary System Description Table +/// +#define EFI_ACPI_6_5_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +/// +/// "XSDT" Extended System Description Table +/// +#define EFI_ACPI_6_5_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('X', 'S', 'D', 'T') + +/// +/// "BOOT" MS Simple Boot Spec +/// +#define EFI_ACPI_6_5_SIMPLE_BOOT_FLAG_TABLE_SIGNATURE SIGNATURE_32('B', 'O', 'O', 'T') + +/// +/// "CSRT" MS Core System Resource Table +/// +#define EFI_ACPI_6_5_CORE_SYSTEM_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('C', 'S', 'R', 'T') + +/// +/// "DBG2" MS Debug Port 2 Spec +/// +#define EFI_ACPI_6_5_DEBUG_PORT_2_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', '2') + +/// +/// "DBGP" MS Debug Port Spec +/// +#define EFI_ACPI_6_5_DEBUG_PORT_TABLE_SIGNATURE SIGNATURE_32('D', 'B', 'G', 'P') + +/// +/// "DMAR" DMA Remapping Table +/// +#define EFI_ACPI_6_5_DMA_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('D', 'M', 'A', 'R') + +/// +/// "DRTM" Dynamic Root of Trust for Measurement Table +/// +#define EFI_ACPI_6_5_DYNAMIC_ROOT_OF_TRUST_FOR_MEASUREMENT_TABLE_SIGNATURE SIGNATURE_32('D', 'R', 'T', 'M') + +/// +/// "ETDT" Event Timer Description Table +/// +#define EFI_ACPI_6_5_EVENT_TIMER_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('E', 'T', 'D', 'T') + +/// +/// "HPET" IA-PC High Precision Event Timer Table +/// +#define EFI_ACPI_6_5_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE SIGNATURE_32('H', 'P', 'E', 'T') + +/// +/// "iBFT" iSCSI Boot Firmware Table +/// +#define EFI_ACPI_6_5_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE SIGNATURE_32('i', 'B', 'F', 'T') + +/// +/// "IORT" I/O Remapping Table +/// +#define EFI_ACPI_6_5_IO_REMAPPING_TABLE_SIGNATURE SIGNATURE_32('I', 'O', 'R', 'T') + +/// +/// "IVRS" I/O Virtualization Reporting Structure +/// +#define EFI_ACPI_6_5_IO_VIRTUALIZATION_REPORTING_STRUCTURE_SIGNATURE SIGNATURE_32('I', 'V', 'R', 'S') + +/// +/// "LPIT" Low Power Idle Table +/// +#define EFI_ACPI_6_5_LOW_POWER_IDLE_TABLE_STRUCTURE_SIGNATURE SIGNATURE_32('L', 'P', 'I', 'T') + +/// +/// "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table +/// +#define EFI_ACPI_6_5_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'F', 'G') + +/// +/// "MCHI" Management Controller Host Interface Table +/// +#define EFI_ACPI_6_5_MANAGEMENT_CONTROLLER_HOST_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('M', 'C', 'H', 'I') + +/// +/// "MSDM" MS Data Management Table +/// +#define EFI_ACPI_6_5_DATA_MANAGEMENT_TABLE_SIGNATURE SIGNATURE_32('M', 'S', 'D', 'M') + +/// +/// "PCCT" Platform Communications Channel Table +/// +#define EFI_ACPI_6_5_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE SIGNATURE_32('P', 'C', 'C', 'T') + +/// +/// "PHAT" Platform Health Assessment Table +/// +#define EFI_ACPI_6_5_PLATFORM_HEALTH_ASSESSMENT_TABLE_SIGNATURE SIGNATURE_32('P', 'H', 'A', 'T') + +/// +/// "SDEI" Software Delegated Exceptions Interface Table +/// +#define EFI_ACPI_6_5_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'D', 'E', 'I') + +/// +/// "SLIC" MS Software Licensing Table Specification +/// +#define EFI_ACPI_6_5_SOFTWARE_LICENSING_TABLE_SIGNATURE SIGNATURE_32('S', 'L', 'I', 'C') + +/// +/// "SPCR" Serial Port Concole Redirection Table +/// +#define EFI_ACPI_6_5_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'C', 'R') + +/// +/// "SPMI" Server Platform Management Interface Table +/// +#define EFI_ACPI_6_5_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE SIGNATURE_32('S', 'P', 'M', 'I') + +/// +/// "STAO" _STA Override Table +/// +#define EFI_ACPI_6_5_STA_OVERRIDE_TABLE_SIGNATURE SIGNATURE_32('S', 'T', 'A', 'O') + +/// +/// "TCPA" Trusted Computing Platform Alliance Capabilities Table +/// +#define EFI_ACPI_6_5_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE SIGNATURE_32('T', 'C', 'P', 'A') + +/// +/// "TPM2" Trusted Computing Platform 1 Table +/// +#define EFI_ACPI_6_5_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE SIGNATURE_32('T', 'P', 'M', '2') + +/// +/// "UEFI" UEFI ACPI Data Table +/// +#define EFI_ACPI_6_5_UEFI_ACPI_DATA_TABLE_SIGNATURE SIGNATURE_32('U', 'E', 'F', 'I') + +/// +/// "WAET" Windows ACPI Emulated Devices Table +/// +#define EFI_ACPI_6_5_WINDOWS_ACPI_EMULATED_DEVICES_TABLE_SIGNATURE SIGNATURE_32('W', 'A', 'E', 'T') + +/// +/// "WDAT" Watchdog Action Table +/// +#define EFI_ACPI_6_5_WATCHDOG_ACTION_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'A', 'T') + +/// +/// "WDRT" Watchdog Resource Table +/// +#define EFI_ACPI_6_5_WATCHDOG_RESOURCE_TABLE_SIGNATURE SIGNATURE_32('W', 'D', 'R', 'T') + +/// +/// "WPBT" MS Platform Binary Table +/// +#define EFI_ACPI_6_5_PLATFORM_BINARY_TABLE_SIGNATURE SIGNATURE_32('W', 'P', 'B', 'T') + +/// +/// "WSMT" Windows SMM Security Mitigation Table +/// +#define EFI_ACPI_6_5_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE SIGNATURE_32('W', 'S', 'M', 'T') + +/// +/// "XENV" Xen Project Table +/// +#define EFI_ACPI_6_5_XEN_PROJECT_TABLE_SIGNATURE SIGNATURE_32('X', 'E', 'N', 'V') + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/AcpiAml.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/AcpiAml.h new file mode 100644 index 0000000..79e30b7 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/AcpiAml.h @@ -0,0 +1,184 @@ +/** @file + This file contains AML code definition in the latest ACPI spec. + + Copyright (c) 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ACPI_AML_H_ +#define _ACPI_AML_H_ + +// +// ACPI AML definition +// + +// +// Primary OpCode +// +#define AML_ZERO_OP 0x00 +#define AML_ONE_OP 0x01 +#define AML_ALIAS_OP 0x06 +#define AML_NAME_OP 0x08 +#define AML_BYTE_PREFIX 0x0a +#define AML_WORD_PREFIX 0x0b +#define AML_DWORD_PREFIX 0x0c +#define AML_STRING_PREFIX 0x0d +#define AML_QWORD_PREFIX 0x0e +#define AML_SCOPE_OP 0x10 +#define AML_BUFFER_OP 0x11 +#define AML_PACKAGE_OP 0x12 +#define AML_VAR_PACKAGE_OP 0x13 +#define AML_METHOD_OP 0x14 +#define AML_EXTERNAL_OP 0x15 +#define AML_DUAL_NAME_PREFIX 0x2e +#define AML_MULTI_NAME_PREFIX 0x2f +#define AML_NAME_CHAR_A 0x41 +#define AML_NAME_CHAR_B 0x42 +#define AML_NAME_CHAR_C 0x43 +#define AML_NAME_CHAR_D 0x44 +#define AML_NAME_CHAR_E 0x45 +#define AML_NAME_CHAR_F 0x46 +#define AML_NAME_CHAR_G 0x47 +#define AML_NAME_CHAR_H 0x48 +#define AML_NAME_CHAR_I 0x49 +#define AML_NAME_CHAR_J 0x4a +#define AML_NAME_CHAR_K 0x4b +#define AML_NAME_CHAR_L 0x4c +#define AML_NAME_CHAR_M 0x4d +#define AML_NAME_CHAR_N 0x4e +#define AML_NAME_CHAR_O 0x4f +#define AML_NAME_CHAR_P 0x50 +#define AML_NAME_CHAR_Q 0x51 +#define AML_NAME_CHAR_R 0x52 +#define AML_NAME_CHAR_S 0x53 +#define AML_NAME_CHAR_T 0x54 +#define AML_NAME_CHAR_U 0x55 +#define AML_NAME_CHAR_V 0x56 +#define AML_NAME_CHAR_W 0x57 +#define AML_NAME_CHAR_X 0x58 +#define AML_NAME_CHAR_Y 0x59 +#define AML_NAME_CHAR_Z 0x5a +#define AML_ROOT_CHAR 0x5c +#define AML_PARENT_PREFIX_CHAR 0x5e +#define AML_NAME_CHAR__ 0x5f +#define AML_LOCAL0 0x60 +#define AML_LOCAL1 0x61 +#define AML_LOCAL2 0x62 +#define AML_LOCAL3 0x63 +#define AML_LOCAL4 0x64 +#define AML_LOCAL5 0x65 +#define AML_LOCAL6 0x66 +#define AML_LOCAL7 0x67 +#define AML_ARG0 0x68 +#define AML_ARG1 0x69 +#define AML_ARG2 0x6a +#define AML_ARG3 0x6b +#define AML_ARG4 0x6c +#define AML_ARG5 0x6d +#define AML_ARG6 0x6e +#define AML_STORE_OP 0x70 +#define AML_REF_OF_OP 0x71 +#define AML_ADD_OP 0x72 +#define AML_CONCAT_OP 0x73 +#define AML_SUBTRACT_OP 0x74 +#define AML_INCREMENT_OP 0x75 +#define AML_DECREMENT_OP 0x76 +#define AML_MULTIPLY_OP 0x77 +#define AML_DIVIDE_OP 0x78 +#define AML_SHIFT_LEFT_OP 0x79 +#define AML_SHIFT_RIGHT_OP 0x7a +#define AML_AND_OP 0x7b +#define AML_NAND_OP 0x7c +#define AML_OR_OP 0x7d +#define AML_NOR_OP 0x7e +#define AML_XOR_OP 0x7f +#define AML_NOT_OP 0x80 +#define AML_FIND_SET_LEFT_BIT_OP 0x81 +#define AML_FIND_SET_RIGHT_BIT_OP 0x82 +#define AML_DEREF_OF_OP 0x83 +#define AML_CONCAT_RES_OP 0x84 +#define AML_MOD_OP 0x85 +#define AML_NOTIFY_OP 0x86 +#define AML_SIZE_OF_OP 0x87 +#define AML_INDEX_OP 0x88 +#define AML_MATCH_OP 0x89 +#define AML_CREATE_DWORD_FIELD_OP 0x8a +#define AML_CREATE_WORD_FIELD_OP 0x8b +#define AML_CREATE_BYTE_FIELD_OP 0x8c +#define AML_CREATE_BIT_FIELD_OP 0x8d +#define AML_OBJECT_TYPE_OP 0x8e +#define AML_CREATE_QWORD_FIELD_OP 0x8f +#define AML_LAND_OP 0x90 +#define AML_LOR_OP 0x91 +#define AML_LNOT_OP 0x92 +#define AML_LEQUAL_OP 0x93 +#define AML_LGREATER_OP 0x94 +#define AML_LLESS_OP 0x95 +#define AML_TO_BUFFER_OP 0x96 +#define AML_TO_DEC_STRING_OP 0x97 +#define AML_TO_HEX_STRING_OP 0x98 +#define AML_TO_INTEGER_OP 0x99 +#define AML_TO_STRING_OP 0x9c +#define AML_COPY_OBJECT_OP 0x9d +#define AML_MID_OP 0x9e +#define AML_CONTINUE_OP 0x9f +#define AML_IF_OP 0xa0 +#define AML_ELSE_OP 0xa1 +#define AML_WHILE_OP 0xa2 +#define AML_NOOP_OP 0xa3 +#define AML_RETURN_OP 0xa4 +#define AML_BREAK_OP 0xa5 +#define AML_BREAK_POINT_OP 0xcc +#define AML_ONES_OP 0xff + +// +// Extended OpCode +// +#define AML_EXT_OP 0x5b + +#define AML_EXT_MUTEX_OP 0x01 +#define AML_EXT_EVENT_OP 0x02 +#define AML_EXT_COND_REF_OF_OP 0x12 +#define AML_EXT_CREATE_FIELD_OP 0x13 +#define AML_EXT_LOAD_TABLE_OP 0x1f +#define AML_EXT_LOAD_OP 0x20 +#define AML_EXT_STALL_OP 0x21 +#define AML_EXT_SLEEP_OP 0x22 +#define AML_EXT_ACQUIRE_OP 0x23 +#define AML_EXT_SIGNAL_OP 0x24 +#define AML_EXT_WAIT_OP 0x25 +#define AML_EXT_RESET_OP 0x26 +#define AML_EXT_RELEASE_OP 0x27 +#define AML_EXT_FROM_BCD_OP 0x28 +#define AML_EXT_TO_BCD_OP 0x29 +#define AML_EXT_UNLOAD_OP 0x2a +#define AML_EXT_REVISION_OP 0x30 +#define AML_EXT_DEBUG_OP 0x31 +#define AML_EXT_FATAL_OP 0x32 +#define AML_EXT_TIMER_OP 0x33 +#define AML_EXT_REGION_OP 0x80 +#define AML_EXT_FIELD_OP 0x81 +#define AML_EXT_DEVICE_OP 0x82 +#define AML_EXT_PROCESSOR_OP 0x83 +#define AML_EXT_POWER_RES_OP 0x84 +#define AML_EXT_THERMAL_ZONE_OP 0x85 +#define AML_EXT_INDEX_FIELD_OP 0x86 +#define AML_EXT_BANK_FIELD_OP 0x87 +#define AML_EXT_DATA_REGION_OP 0x88 + +// +// FieldElement OpCode +// +#define AML_FIELD_RESERVED_OP 0x00 +#define AML_FIELD_ACCESS_OP 0x01 +#define AML_FIELD_CONNECTION_OP 0x02 +#define AML_FIELD_EXT_ACCESS_OP 0x03 + +// +// AML Name segment definitions +// +#define AML_NAME_SEG_SIZE 4 + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h new file mode 100644 index 0000000..d47bf84 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h @@ -0,0 +1,49 @@ +/** @file + ACPI memory mapped configuration space access table definition, defined at + in the PCI Firmware Specification, version 3.0. + Specification is available at http://www.pcisig.com. + + Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_H_ +#define _MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_H_ + +#include + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// Memory Mapped Configuration Space Access Table (MCFG) +/// This table is a basic description table header followed by +/// a number of base address allocation structures. +/// +typedef struct { + UINT64 BaseAddress; + UINT16 PciSegmentGroupNumber; + UINT8 StartBusNumber; + UINT8 EndBusNumber; + UINT32 Reserved; +} EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE; + +/// +/// MCFG Table header definition. The rest of the table +/// must be defined in a platform specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT64 Reserved; +} EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER; + +/// +/// MCFG Revision (defined in spec) +/// +#define EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION 0x01 + +#pragma pack() + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/IndustryStandard/PeImage.h b/tools/src/GenFw/MdePkg/Include/IndustryStandard/PeImage.h new file mode 100644 index 0000000..935d509 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/IndustryStandard/PeImage.h @@ -0,0 +1,806 @@ +/** @file + EFI image format for PE32, PE32+ and TE. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.3 - February 6, 2013. + This file also includes some definitions in PI Specification, Revision 1.0. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+Portions Copyright (c) 2016 - 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PE_IMAGE_H__ +#define __PE_IMAGE_H__ + +// +// PE32+ Subsystem type for EFI images +// +#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13///< defined PI Specification, 1.0 + +// +// PE32+ Machine type for EFI images +// +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_X64 0x8664 +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2 +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 +#define IMAGE_FILE_MACHINE_RISCV32 0x5032 +#define IMAGE_FILE_MACHINE_RISCV64 0x5064 +#define IMAGE_FILE_MACHINE_RISCV128 0x5128 +#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232 +#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264 + +// +// EXE file formats +// +#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z') +#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E') +#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E') +#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0') + +/// +/// PE images can start with an optional DOS header, so if an image is run +/// under DOS it can print an error message. +/// +typedef struct { + UINT16 e_magic; ///< Magic number. + UINT16 e_cblp; ///< Bytes on last page of file. + UINT16 e_cp; ///< Pages in file. + UINT16 e_crlc; ///< Relocations. + UINT16 e_cparhdr; ///< Size of header in paragraphs. + UINT16 e_minalloc; ///< Minimum extra paragraphs needed. + UINT16 e_maxalloc; ///< Maximum extra paragraphs needed. + UINT16 e_ss; ///< Initial (relative) SS value. + UINT16 e_sp; ///< Initial SP value. + UINT16 e_csum; ///< Checksum. + UINT16 e_ip; ///< Initial IP value. + UINT16 e_cs; ///< Initial (relative) CS value. + UINT16 e_lfarlc; ///< File address of relocation table. + UINT16 e_ovno; ///< Overlay number. + UINT16 e_res[4]; ///< Reserved words. + UINT16 e_oemid; ///< OEM identifier (for e_oeminfo). + UINT16 e_oeminfo; ///< OEM information; e_oemid specific. + UINT16 e_res2[10]; ///< Reserved words. + UINT32 e_lfanew; ///< File address of new exe header. +} EFI_IMAGE_DOS_HEADER; + +/// +/// COFF File Header (Object and Image). +/// +typedef struct { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} EFI_IMAGE_FILE_HEADER; + +/// +/// Size of EFI_IMAGE_FILE_HEADER. +/// +#define EFI_IMAGE_SIZEOF_FILE_HEADER 20 + +// +// Characteristics +// +#define EFI_IMAGE_FILE_RELOCS_STRIPPED BIT0 ///< 0x0001 Relocation info stripped from file. +#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references). +#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line numbers stripped from file. +#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file. +#define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE BIT5 ///< 0x0020 Supports addresses > 2-GB +#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed. +#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine. +#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file. +#define EFI_IMAGE_FILE_SYSTEM BIT12 ///< 0x1000 System File. +#define EFI_IMAGE_FILE_DLL BIT13 ///< 0x2000 File is a DLL. +#define EFI_IMAGE_FILE_BYTES_REVERSED_HI BIT15 ///< 0x8000 Bytes of machine word are reversed. + +/// +/// Header Data Directories. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 Size; +} EFI_IMAGE_DATA_DIRECTORY; + +// +// Directory Entries +// +#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 +#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and +/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + +/// +/// Optional Header Standard Fields for PE32. +/// +typedef struct { + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+. + /// + /// Optional Header Windows-Specific Fields. + /// + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER32; + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and +/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +/// +/// Optional Header Standard Fields for PE32+. +/// +typedef struct { + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + /// + /// Optional Header Windows-Specific Fields. + /// + UINT64 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT64 SizeOfStackReserve; + UINT64 SizeOfStackCommit; + UINT64 SizeOfHeapReserve; + UINT64 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER64; + +/// +/// @attention +/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools. +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} EFI_IMAGE_NT_HEADERS32; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) + +/// +/// @attention +/// EFI_IMAGE_HEADERS64 is for use ONLY by tools. +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} EFI_IMAGE_NT_HEADERS64; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) + +// +// Other Windows Subsystem Values +// +#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 +#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 + +/// +/// Length of ShortName. +/// +#define EFI_IMAGE_SIZEOF_SHORT_NAME 8 + +/// +/// Section Table. This table immediately follows the optional header. +/// +typedef struct { + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} EFI_IMAGE_SECTION_HEADER; + +/// +/// Size of EFI_IMAGE_SECTION_HEADER. +/// +#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 + +// +// Section Flags Values +// +#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved. +#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020 +#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040 +#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080 + +#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved. +#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information. +#define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image. +#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000 + +#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000 +#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000 +#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000 +#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000 +#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000 +#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000 +#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000 + +#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000 +#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000 +#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000 +#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000 +#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000 +#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000 +#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000 + +/// +/// Size of a Symbol Table Record. +/// +#define EFI_IMAGE_SIZEOF_SYMBOL 18 + +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// +#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common. +#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value. +#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item. + +// +// Symbol Type (fundamental) values. +// +#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type. +#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type. +#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character. +#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer. +#define EFI_IMAGE_SYM_TYPE_INT 4 +#define EFI_IMAGE_SYM_TYPE_LONG 5 +#define EFI_IMAGE_SYM_TYPE_FLOAT 6 +#define EFI_IMAGE_SYM_TYPE_DOUBLE 7 +#define EFI_IMAGE_SYM_TYPE_STRUCT 8 +#define EFI_IMAGE_SYM_TYPE_UNION 9 +#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration. +#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration. +#define EFI_IMAGE_SYM_TYPE_BYTE 12 +#define EFI_IMAGE_SYM_TYPE_WORD 13 +#define EFI_IMAGE_SYM_TYPE_UINT 14 +#define EFI_IMAGE_SYM_TYPE_DWORD 15 + +// +// Symbol Type (derived) values. +// +#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type. +#define EFI_IMAGE_SYM_DTYPE_POINTER 1 +#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 +#define EFI_IMAGE_SYM_DTYPE_ARRAY 3 + +// +// Storage classes. +// +#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1) +#define EFI_IMAGE_SYM_CLASS_NULL 0 +#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 +#define EFI_IMAGE_SYM_CLASS_STATIC 3 +#define EFI_IMAGE_SYM_CLASS_REGISTER 4 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define EFI_IMAGE_SYM_CLASS_LABEL 6 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 +#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 +#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 +#define EFI_IMAGE_SYM_CLASS_BLOCK 100 +#define EFI_IMAGE_SYM_CLASS_FUNCTION 101 +#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define EFI_IMAGE_SYM_CLASS_FILE 103 +#define EFI_IMAGE_SYM_CLASS_SECTION 104 +#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// +// type packing constants +// +#define EFI_IMAGE_N_BTMASK 017 +#define EFI_IMAGE_N_TMASK 060 +#define EFI_IMAGE_N_TMASK1 0300 +#define EFI_IMAGE_N_TMASK2 0360 +#define EFI_IMAGE_N_BTSHFT 4 +#define EFI_IMAGE_N_TSHIFT 2 + +// +// Communal selection types. +// +#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define EFI_IMAGE_COMDAT_SELECT_ANY 2 +#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +// +// the following values only be referred in PeCoff, not defined in PECOFF. +// +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/// +/// Relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} EFI_IMAGE_RELOCATION; + +/// +/// Size of EFI_IMAGE_RELOCATION +/// +#define EFI_IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// +#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary. +#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included. +#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address. +#define EFI_IMAGE_REL_I386_SECTION 0x000A +#define EFI_IMAGE_REL_I386_SECREL 0x000B +#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address. + +// +// x64 processor relocation types. +// +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +/// +/// Based relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +} EFI_IMAGE_BASE_RELOCATION; + +/// +/// Size of EFI_IMAGE_BASE_RELOCATION. +/// +#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// +#define EFI_IMAGE_REL_BASED_ABSOLUTE 0 +#define EFI_IMAGE_REL_BASED_HIGH 1 +#define EFI_IMAGE_REL_BASED_LOW 2 +#define EFI_IMAGE_REL_BASED_HIGHLOW 3 +#define EFI_IMAGE_REL_BASED_HIGHADJ 4 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7 +#define EFI_IMAGE_REL_BASED_IA64_IMM64 9 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define EFI_IMAGE_REL_BASED_DIR64 10 + +/// +/// Relocation types of RISC-V processor. +/// +#define EFI_IMAGE_REL_BASED_RISCV_HI20 5 +#define EFI_IMAGE_REL_BASED_RISCV_LOW12I 7 +#define EFI_IMAGE_REL_BASED_RISCV_LOW12S 8 + +// +// Relocation types of LoongArch processor. +// +#define EFI_IMAGE_REL_BASED_LOONGARCH32_MARK_LA 8 +#define EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA 8 + +/// +/// Line number format. +/// +typedef struct { + union { + UINT32 SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; ///< Virtual address of line number. + } Type; + UINT16 Linenumber; ///< Line number. +} EFI_IMAGE_LINENUMBER; + +/// +/// Size of EFI_IMAGE_LINENUMBER. +/// +#define EFI_IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// +#define EFI_IMAGE_ARCHIVE_START_SIZE 8 +#define EFI_IMAGE_ARCHIVE_START "!\n" +#define EFI_IMAGE_ARCHIVE_END "`\n" +#define EFI_IMAGE_ARCHIVE_PAD "\n" +#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +/// +/// Archive Member Headers +/// +typedef struct { + UINT8 Name[16]; ///< File member name - `/' terminated. + UINT8 Date[12]; ///< File member date - decimal. + UINT8 UserID[6]; ///< File member user id - decimal. + UINT8 GroupID[6]; ///< File member group id - decimal. + UINT8 Mode[8]; ///< File member mode - octal. + UINT8 Size[10]; ///< File member size - decimal. + UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A). +} EFI_IMAGE_ARCHIVE_MEMBER_HEADER; + +/// +/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER. +/// +#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL Support +// + +/// +/// Export Directory Table. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 AddressOfFunctions; + UINT32 AddressOfNames; + UINT32 AddressOfNameOrdinals; +} EFI_IMAGE_EXPORT_DIRECTORY; + +// +// Based export types. +// +#define EFI_IMAGE_EXPORT_ORDINAL_BASE 1 +#define EFI_IMAGE_EXPORT_ADDR_SIZE 4 +#define EFI_IMAGE_EXPORT_ORDINAL_SIZE 2 + +/// +/// Hint/Name Table. +/// +typedef struct { + UINT16 Hint; + UINT8 Name[1]; +} EFI_IMAGE_IMPORT_BY_NAME; + +/// +/// Import Address Table RVA (Thunk Table). +/// +typedef struct { + union { + UINT32 Function; + UINT32 Ordinal; + EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; + } u1; +} EFI_IMAGE_THUNK_DATA; + +#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32. +#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) +#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +/// +/// Import Directory Table +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + EFI_IMAGE_THUNK_DATA *FirstThunk; +} EFI_IMAGE_IMPORT_DESCRIPTOR; + +/// +/// Debug Directory Format. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base. + UINT32 FileOffset; ///< The file pointer to the debug data. +} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information. +#define EFI_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20 + +/// +/// Debug Data Structure defined in Microsoft C++. +/// +#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0') +typedef struct { + UINT32 Signature; ///< "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +/// +/// Debug Data Structure defined in Microsoft C++. +/// +#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S') +typedef struct { + UINT32 Signature; ///< "RSDS". + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + +/// +/// Debug Data Structure defined by Apple Mach-O to Coff utility. +/// +#define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C') +typedef struct { + UINT32 Signature; ///< "MTOC". + GUID MachOUuid; + // + // Filename of .DLL (Mach-O with debug info) goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; + +// avoid conflict with windows header files +#ifndef RUNTIME_FUNCTION_INDIRECT + +// +// .pdata entries for X64 +// +typedef struct { + UINT32 FunctionStartAddress; + UINT32 FunctionEndAddress; + UINT32 UnwindInfoAddress; +} RUNTIME_FUNCTION; + +#endif + +typedef struct { + UINT8 Version : 3; + UINT8 Flags : 5; + UINT8 SizeOfProlog; + UINT8 CountOfUnwindCodes; + UINT8 FrameRegister : 4; + UINT8 FrameRegisterOffset : 4; +} UNWIND_INFO; + +/// +/// Extended DLL Characteristics +/// +#define EFI_IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT 0x0001 +#define EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT 0x0040 + +typedef struct { + UINT32 DllCharacteristicsEx; +} EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY; + +/// +/// Resource format. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT16 NumberOfNamedEntries; + UINT16 NumberOfIdEntries; + // + // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here. + // +} EFI_IMAGE_RESOURCE_DIRECTORY; + +/// +/// Resource directory entry format. +/// +typedef struct { + union { + struct { + UINT32 NameOffset : 31; + UINT32 NameIsString : 1; + } s; + UINT32 Id; + } u1; + union { + UINT32 OffsetToData; + struct { + UINT32 OffsetToDirectory : 31; + UINT32 DataIsDirectory : 1; + } s; + } u2; +} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY; + +/// +/// Resource directory entry for string. +/// +typedef struct { + UINT16 Length; + CHAR16 String[1]; +} EFI_IMAGE_RESOURCE_DIRECTORY_STRING; + +/// +/// Resource directory entry for data array. +/// +typedef struct { + UINT32 OffsetToData; + UINT32 Size; + UINT32 CodePage; + UINT32 Reserved; +} EFI_IMAGE_RESOURCE_DATA_ENTRY; + +/// +/// Header format for TE images, defined in the PI Specification, 1.0. +/// +typedef struct { + UINT16 Signature; ///< The signature for TE format = "VZ". + UINT16 Machine; ///< From the original file header. + UINT8 NumberOfSections; ///< From the original file header. + UINT8 Subsystem; ///< From original optional header. + UINT16 StrippedSize; ///< Number of bytes we removed from the header. + UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header. + UINT32 BaseOfCode; ///< From original image -- required for ITP debug. + UINT64 ImageBase; ///< From original file header. + EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory. +} EFI_TE_IMAGE_HEADER; + +#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z') + +// +// Data directory indexes in our TE image header +// +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 + +/// +/// Union of PE32, PE32+, and TE headers. +/// +typedef union { + EFI_IMAGE_NT_HEADERS32 Pe32; + EFI_IMAGE_NT_HEADERS64 Pe32Plus; + EFI_TE_IMAGE_HEADER Te; +} EFI_IMAGE_OPTIONAL_HEADER_UNION; + +typedef union { + EFI_IMAGE_NT_HEADERS32 *Pe32; + EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + EFI_TE_IMAGE_HEADER *Te; + EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; +} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; + +#endif diff --git a/tools/src/GenFw/MdePkg/Include/X64/ProcessorBind.h b/tools/src/GenFw/MdePkg/Include/X64/ProcessorBind.h new file mode 100644 index 0000000..2519843 --- /dev/null +++ b/tools/src/GenFw/MdePkg/Include/X64/ProcessorBind.h @@ -0,0 +1,319 @@ +/** @file + Processor or Compiler specific defines and types x64 (Intel 64, AMD64). + + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PROCESSOR_BIND_H__ +#define __PROCESSOR_BIND_H__ + +/// +/// Define the processor type so other code can make processor based choices +/// +#define MDE_CPU_X64 + +// +// Make sure we are using the correct packing rules per EFI specification +// +#if !defined (__GNUC__) + #pragma pack() +#endif + +#if defined (__INTEL_COMPILER) +// +// Disable ICC's remark #869: "Parameter" was never referenced warning. +// This is legal ANSI C code so we disable the remark that is turned on with -Wall +// + #pragma warning ( disable : 869 ) + +// +// Disable ICC's remark #1418: external function definition with no prior declaration. +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// + #pragma warning ( disable : 1418 ) + +// +// Disable ICC's remark #1419: external declaration in primary source file +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// + #pragma warning ( disable : 1419 ) + +// +// Disable ICC's remark #593: "Variable" was set but never used. +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// + #pragma warning ( disable : 593 ) + +#endif + +#if defined (_MSC_EXTENSIONS) + +// +// Disable warning that make it impossible to compile at /W4 +// This only works for Microsoft* tools +// + +// +// Disabling bitfield type checking warnings. +// + #pragma warning ( disable : 4214 ) + +// +// Disabling the unreferenced formal parameter warnings. +// + #pragma warning ( disable : 4100 ) + +// +// Disable slightly different base types warning as CHAR8 * can not be set +// to a constant string. +// + #pragma warning ( disable : 4057 ) + +// +// ASSERT(FALSE) or while (TRUE) are legal constructs so suppress this warning +// + #pragma warning ( disable : 4127 ) + +// +// This warning is caused by functions defined but not used. For precompiled header only. +// + #pragma warning ( disable : 4505 ) + +// +// This warning is caused by empty (after preprocessing) source file. For precompiled header only. +// + #pragma warning ( disable : 4206 ) + + #if defined (_MSC_VER) && _MSC_VER >= 1800 + +// +// This warning is for potentially uninitialized local variable, and it may cause false +// positive issues in VS2015 build +// + #pragma warning ( disable : 4701 ) + +// +// This warning is for potentially uninitialized local pointer variable, and it may cause +// false positive issues in VS2015 build +// + #pragma warning ( disable : 4703 ) + + #endif + +#endif + +#if defined (_MSC_EXTENSIONS) +// +// use Microsoft C compiler dependent integer width types +// + +/// +/// 8-byte unsigned value +/// +typedef unsigned __int64 UINT64; +/// +/// 8-byte signed value +/// +typedef __int64 INT64; +/// +/// 4-byte unsigned value +/// +typedef unsigned __int32 UINT32; +/// +/// 4-byte signed value +/// +typedef __int32 INT32; +/// +/// 2-byte unsigned value +/// +typedef unsigned short UINT16; +/// +/// 2-byte Character. Unless otherwise specified all strings are stored in the +/// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards. +/// +typedef unsigned short CHAR16; +/// +/// 2-byte signed value +/// +typedef short INT16; +/// +/// Logical Boolean. 1-byte value containing 0 for FALSE or a 1 for TRUE. Other +/// values are undefined. +/// +typedef unsigned char BOOLEAN; +/// +/// 1-byte unsigned value +/// +typedef unsigned char UINT8; +/// +/// 1-byte Character +/// +typedef char CHAR8; +/// +/// 1-byte signed value +/// +typedef signed char INT8; +#else +/// +/// 8-byte unsigned value +/// +typedef unsigned long long UINT64; +/// +/// 8-byte signed value +/// +typedef long long INT64; +/// +/// 4-byte unsigned value +/// +typedef unsigned int UINT32; +/// +/// 4-byte signed value +/// +typedef int INT32; +/// +/// 2-byte unsigned value +/// +typedef unsigned short UINT16; +/// +/// 2-byte Character. Unless otherwise specified all strings are stored in the +/// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards. +/// +typedef unsigned short CHAR16; +/// +/// 2-byte signed value +/// +typedef short INT16; +/// +/// Logical Boolean. 1-byte value containing 0 for FALSE or a 1 for TRUE. Other +/// values are undefined. +/// +typedef unsigned char BOOLEAN; +/// +/// 1-byte unsigned value +/// +typedef unsigned char UINT8; +/// +/// 1-byte Character +/// +typedef char CHAR8; +/// +/// 1-byte signed value +/// +typedef signed char INT8; +#endif + +/// +/// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions, +/// 8 bytes on supported 64-bit processor instructions) +/// +typedef UINT64 UINTN; +/// +/// Signed value of native width. (4 bytes on supported 32-bit processor instructions, +/// 8 bytes on supported 64-bit processor instructions) +/// +typedef INT64 INTN; + +// +// Processor specific defines +// + +/// +/// A value of native width with the highest bit set. +/// +#define MAX_BIT 0x8000000000000000ULL +/// +/// A value of native width with the two highest bits set. +/// +#define MAX_2_BITS 0xC000000000000000ULL + +/// +/// Maximum legal x64 address +/// +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFFULL + +/// +/// Maximum usable address at boot time +/// +#define MAX_ALLOC_ADDRESS MAX_ADDRESS + +/// +/// Maximum legal x64 INTN and UINTN values. +/// +#define MAX_INTN ((INTN)0x7FFFFFFFFFFFFFFFULL) +#define MAX_UINTN ((UINTN)0xFFFFFFFFFFFFFFFFULL) + +/// +/// Minimum legal x64 INTN value. +/// +#define MIN_INTN (((INTN)-9223372036854775807LL) - 1) + +/// +/// The stack alignment required for x64 +/// +#define CPU_STACK_ALIGNMENT 16 + +/// +/// Page allocation granularity for x64 +/// +#define DEFAULT_PAGE_ALLOCATION_GRANULARITY (0x1000) +#define RUNTIME_PAGE_ALLOCATION_GRANULARITY (0x1000) + +// +// Modifier to ensure that all protocol member functions and EFI intrinsics +// use the correct C calling convention. All protocol member functions and +// EFI intrinsics are required to modify their member functions with EFIAPI. +// +#ifdef EFIAPI +/// +/// If EFIAPI is already defined, then we use that definition. +/// +#elif defined (_MSC_EXTENSIONS) +/// +/// Microsoft* compiler specific method for EFIAPI calling convention. +/// +#define EFIAPI __cdecl +#elif defined (__GNUC__) +/// +/// Define the standard calling convention regardless of optimization level. +/// The GCC support assumes a GCC compiler that supports the EFI ABI. The EFI +/// ABI is much closer to the x64 Microsoft* ABI than standard x64 (x86-64) +/// GCC ABI. Thus a standard x64 (x86-64) GCC compiler can not be used for +/// x64. Warning the assembly code in the MDE x64 does not follow the correct +/// ABI for the standard x64 (x86-64) GCC. +/// +#define EFIAPI +#else +/// +/// The default for a non Microsoft* or GCC compiler is to assume the EFI ABI +/// is the standard. +/// +#define EFIAPI +#endif + +#if defined (__GNUC__) || defined (__clang__) +/// +/// For GNU assembly code, .global or .globl can declare global symbols. +/// Define this macro to unify the usage. +/// +#define ASM_GLOBAL .globl +#endif + +/** + Return the pointer to the first instruction of a function given a function pointer. + On x64 CPU architectures, these two pointer values are the same, + so the implementation of this macro is very simple. + + @param FunctionPointer A pointer to a function. + + @return The pointer to the first instruction of a function given a function pointer. + +**/ +#define FUNCTION_ENTRY_POINT(FunctionPointer) (VOID *)(UINTN)(FunctionPointer) + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif + +#endif diff --git a/tools/src/GenFw/build-win.sh b/tools/src/GenFw/build-win.sh new file mode 100755 index 0000000..b6b4bff --- /dev/null +++ b/tools/src/GenFw/build-win.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +error() { + printf "\033[1;31mError\033[0m\n" + exit 1 +} + +cd "$(dirname "$(readlink -f "$0")")" + +printf "\033[1;32mBuilding Common...\033[0m\n" +cd Common +./build-win.sh || error +cd .. +printf "\033[1;32mCommon was built\033[0m\n\n" + +printf "\033[1;32mBuilding GenFw...\033[0m\n" +cd GenFw +./build-win.sh || error +mv GenFw.exe ../../../ +cd .. +printf "\033[1;32mGenFw was built\033[0m\n\n" diff --git a/tools/src/GenFw/build.sh b/tools/src/GenFw/build.sh new file mode 100755 index 0000000..8fc97c9 --- /dev/null +++ b/tools/src/GenFw/build.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +error() { + printf "\033[1;31mError\033[0m\n" + exit 1 +} + +cd "$(dirname "$(readlink -f "$0")")" + +printf "\033[1;32mBuilding Common...\033[0m\n" +cd Common +./build.sh || error +cd .. +printf "\033[1;32mCommon was built\033[0m\n\n" + +printf "\033[1;32mBuilding GenFw...\033[0m\n" +cd GenFw +./build.sh || error +mv GenFw ../../../ +cd .. +printf "\033[1;32mGenFw was built\033[0m\n\n" diff --git a/tools/src/GenFw/clean.sh b/tools/src/GenFw/clean.sh new file mode 100755 index 0000000..12193ec --- /dev/null +++ b/tools/src/GenFw/clean.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +Common/clean.sh +GenFw/clean.sh diff --git a/tools/src/build-i686-elf-tools-win.sh b/tools/src/build-i686-elf-tools-win.sh new file mode 100755 index 0000000..653c9e3 --- /dev/null +++ b/tools/src/build-i686-elf-tools-win.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +set -e +cd "$(dirname "$(readlink -f "$0")")" + +if [ ! -d "../i686-elf-tools-linux" ]; then + # If the linux tools do not exist, build them first because they are required to build the windows tools + ./build-i686-elf-tools.sh +fi + +BINUTILS_VERSION=2.40 +GCC_VERSION=13.1.0 +BUILD_OUTPUT_DIR="$(pwd)/../i686-elf-tools-windows" + +git clone --depth 1 https://github.com/mxe/mxe.git +cd mxe +make -j$(nproc) gcc +cd .. + +export PATH="$(pwd)/mxe/usr/bin:$(pwd)/../i686-elf-tools-linux/bin:$PATH" + +wget https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.gz +wget https://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.gz + +tar -xf binutils-$BINUTILS_VERSION.tar.gz +tar -xf gcc-$GCC_VERSION.tar.gz + +mkdir $BUILD_OUTPUT_DIR + +mkdir -p binutils-$BINUTILS_VERSION/build +cd binutils-$BINUTILS_VERSION/build +rm ./config.cache || true +LDFLAGS=-s ../configure --host=i686-w64-mingw32.static --target=i686-elf --with-sysroot --disable-nls --disable-werror --prefix="${BUILD_OUTPUT_DIR}" +make -j$(nproc) MAKEINFO=true +make install MAKEINFO=true +cd ../.. + +cd gcc-$GCC_VERSION +contrib/download_prerequisites +mkdir -p build +cd build +LDFLAGS=-s ../configure --host=i686-w64-mingw32.static --target=i686-elf --disable-nls --enable-languages=c,c++ --without-headers --prefix="${BUILD_OUTPUT_DIR}" +make -j$(nproc) all-gcc +make install-gcc +make -j$(nproc) all-target-libgcc +make install-target-libgcc +cd ../.. diff --git a/tools/src/build-i686-elf-tools.sh b/tools/src/build-i686-elf-tools.sh new file mode 100755 index 0000000..8930122 --- /dev/null +++ b/tools/src/build-i686-elf-tools.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +set -e +cd "$(dirname "$(readlink -f "$0")")" + +BINUTILS_VERSION=2.40 +GCC_VERSION=13.1.0 +BUILD_OUTPUT_DIR="$(pwd)/../i686-elf-tools-linux" + +wget https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.gz +wget https://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.gz + +tar -xf binutils-$BINUTILS_VERSION.tar.gz +tar -xf gcc-$GCC_VERSION.tar.gz + +mkdir $BUILD_OUTPUT_DIR + +mkdir binutils-$BINUTILS_VERSION/build +cd binutils-$BINUTILS_VERSION/build +LDFLAGS=-s ../configure --target=i686-elf --with-sysroot --disable-nls --disable-werror --prefix="${BUILD_OUTPUT_DIR}" +make -j$(nproc) MAKEINFO=true +make install MAKEINFO=true +cd ../.. + +cd gcc-$GCC_VERSION +contrib/download_prerequisites +mkdir build +cd build +LDFLAGS=-s ../configure --target=i686-elf --disable-nls --enable-languages=c,c++ --without-headers --prefix="${BUILD_OUTPUT_DIR}" +make -j$(nproc) all-gcc +make install-gcc +make -j$(nproc) all-target-libgcc +make install-target-libgcc +cd ../.. diff --git a/tools/src/imgtools/build-win.sh b/tools/src/imgtools/build-win.sh new file mode 100755 index 0000000..93dfb95 --- /dev/null +++ b/tools/src/imgtools/build-win.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +mkdir obj 2>/dev/null + +for srcfile in src/*.c; do + srcfilebase=$(basename "$srcfile") + printf "\033[1;34mCompiling\033[1;97m\t==> $srcfilebase...\033[0m" + x86_64-w64-mingw32-gcc -c $srcfile -o obj/${srcfilebase%.c}.o || exit 1 + printf "\033[1;32mdone\033[0m\n" +done + +x86_64-w64-mingw32-gcc -s -o imgtools.exe obj/*.o +mv imgtools.exe ../../ diff --git a/tools/src/imgtools/build.sh b/tools/src/imgtools/build.sh new file mode 100755 index 0000000..0b75213 --- /dev/null +++ b/tools/src/imgtools/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +mkdir obj 2>/dev/null + +for srcfile in src/*.c; do + srcfilebase=$(basename "$srcfile") + printf "\033[1;34mCompiling\033[1;97m\t==> $srcfilebase...\033[0m" + gcc -c $srcfile -o obj/${srcfilebase%.c}.o || exit 1 + printf "\033[1;32mdone\033[0m\n" +done + +gcc -s -o imgtools obj/*.o +mv imgtools ../../ diff --git a/tools/src/imgtools/clean.sh b/tools/src/imgtools/clean.sh new file mode 100755 index 0000000..2e9e6ab --- /dev/null +++ b/tools/src/imgtools/clean.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +rm obj/*.o 2>/dev/null diff --git a/tools/src/imgtools/src/fat.c b/tools/src/imgtools/src/fat.c new file mode 100755 index 0000000..f8dd488 --- /dev/null +++ b/tools/src/imgtools/src/fat.c @@ -0,0 +1,2912 @@ +#include "fat.h" +#include "math.h" +#include "string.h" +#include +#include +#include +#include +#include + +/** +* @brief Locates the last occurrence of a character in a string. +* +* @param str the string to search in. +* @param c the character to be located. +* @return int32_t the zero-based position of c if that character is found, or -1 if it is not. +*/ +int32_t strrchr_new(char* str, char c) { + int32_t ret = -1; + for (int32_t i = 0; str[i] != 0; ++i) { + if (str[i] == c) ret = i; + } + return ret; +} + +/** +* @brief Removes trailing white-space characters. +* +* @param str string to be trimmed. +* @return char* pointer to the string str. +*/ +char* strtrimend(char *str) +{ + char *end; + + // Trim trailing space + end = str + strlen(str) - 1; + while (end >= str && ((unsigned char)*end) == 0x20) end--; + + // Write new null terminator character + end[1] = '\0'; + + return str; +} + +/** +* @brief Computes the checksum of a string using the BSD checksum algorithm. +* +* @param str string pointer to the string. +* @return uint8_t the resulting checksum. +*/ +uint8_t BSDChecksum(char* str) { + uint8_t sum; + uint8_t i; + size_t len = strlen(str); + for (sum = i = 0; i < len; ++i) { + sum = (uint8_t)((((sum & 1) << 7) | ((sum & 0xFE) >> 1)) + (uint8_t)str[i]); + } + return sum; +} + +/** +* @brief Replaces all instances of the passed substring in the passed string. (Make sure that the passed buffer containing the string is big enough.) +* +* @param search the substring to look for. +* @param replace the substring with which to replaces the found substrings. +* @param string the string in which to look. +* @return char* pointer to the passed string with the replacements performed. +*/ +char* stringReplace(const char *search, const char *replace, char *string) { + char *searchStart; + int len = 0; + int searchLen = strlen(search); + + for (;;) { + searchStart = strstr(string, search); + if (searchStart == NULL) + return string; + + len = searchStart - string; + char* tempString = (char*) malloc(strlen(string) - len - searchLen + 1); + strcpy(tempString, searchStart + searchLen); + + const char* i = replace; + + do { + *searchStart++ = *i++; + } while (*i); + + i = tempString; + do { + *searchStart++ = *i++; + } while (*i); + + free(tempString); + + *searchStart = '\0'; + } +} + +/** + * @brief Convert all letters of a string to lower case. + * + * @param str string to be converted + * @return char* pointer to the converted string str + */ +char* strlwr(char* str) { + char* tmp = str; + + while (*str != '\0') { + if (*str >= 65 && *str <= 90) + *str = *str + 32; + + ++str; + } + + return tmp; +} + +/** + * @brief Convert all letters of a string to upper case. + * + * @param str string to be converted + * @return char* pointer to the converted string str + */ +char* strupr(char* str) { + char* tmp = str; + + while (*str != '\0') { + if (*str >= 97 && *str <= 122) + *str = *str - 32; + + ++str; + } + + return tmp; +} + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + + + + + + + + + +FAT* FAT_create(storage_dev_t* storageDev, uint32_t lbaStart, uint32_t lbaLength, uint8_t fileSys) { + FAT* inst = (FAT*)malloc(sizeof(FAT)); + inst->storageDev = storageDev; + inst->lbaStart = lbaStart; + inst->lbaLength = lbaLength; + inst->fileSys = fileSys; + //Read BIOS Parameter Block + uint8_t secBytes[512]; + storage_readSector(storageDev, lbaStart, secBytes, 512); + switch (fileSys) { + case FAT12: // FAT12 + inst->sectorsPerFAT = secBytes[0x16] + (secBytes[0x17] << 8); + inst->startClustOfRootDir = 0; // unused in FAT12 + inst->maxRootDirEntries = secBytes[17] + (secBytes[18] << 8); + break; + case FAT16: // FAT16 + inst->sectorsPerFAT = secBytes[0x16] + (secBytes[0x17] << 8); + inst->startClustOfRootDir = 0; // unused in FAT16 + inst->maxRootDirEntries = secBytes[17] + (secBytes[18] << 8); + break; + default: // FAT32 + inst->sectorsPerFAT = secBytes[0x24] + (secBytes[0x25] << 8) + (secBytes[0x26] << 16) + (secBytes[0x27] << 24); + inst->startClustOfRootDir = secBytes[0x2C] + (secBytes[0x2D] << 8) + (secBytes[0x2E] << 16) + (secBytes[0x2F] << 24); + inst->maxRootDirEntries = 0; // unused in FAT32 (number of root directory entries is not limited) + break; + } + inst->reservedSectors = secBytes[14] + (secBytes[15] << 8); + inst->FATCopies = secBytes[16]; + inst->sectorsPerCluster = secBytes[13]; + return inst; +} + +void FAT_destroy(FAT* inst) { + if (inst) { + free(inst); + } +} + +uint32_t FAT_FATgetClusterDetailed(FAT* inst, uint32_t start_clust) { + if (start_clust < 2) return 0; + switch (inst->fileSys) { + case FAT12: // FAT12 + if (start_clust >= ((inst->sectorsPerFAT * 512 * 2) / 3)) return 0; + break; + case FAT16: // FAT16 + if (start_clust >= inst->sectorsPerFAT * 256) return 0; + break; + default: // FAT32 + if (start_clust >= inst->sectorsPerFAT * 128) return 0; + break; + } + uint8_t secBytes[512]; + switch (inst->fileSys) { + case FAT12: // FAT12 + if (((start_clust * 3) / (512 * 2)) == (((start_clust * 3) / 2 + 1) / 512)) { + // One sector is used + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (start_clust * 3) / (512 * 2), secBytes, 512); + if ((start_clust % 2) == 0) { // begins at start of byte + return (secBytes[((start_clust * 3) / 2) % 512] + ((secBytes[((start_clust * 3) / 2 + 1) % 512] & 0x0F) << 8)); + } + else { + return ((secBytes[((start_clust * 3) / 2 + 1) % 512] << 4) + ((secBytes[((start_clust * 3) / 2) % 512] & 0xF0) >> 4)); + } + } + else { + // Two sectors are used + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (start_clust * 3) / (512 * 2), secBytes, 512); + uint8_t secBytes2[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (start_clust * 3 + 2) / (512 * 2), secBytes2, 512); + if ((start_clust % 2) == 0) { // begins at start of byte + return (secBytes[511] + ((secBytes2[0] & 0x0F) << 8)); + } + else { + return ((secBytes2[0] << 4) + ((secBytes[511] & 0xF0) >> 4)); + } + } + break; + case FAT16: // FAT16 + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 256, secBytes, 512); + return secBytes[(start_clust * 2) % 512] + (secBytes[((start_clust * 2) % 512) + 1] << 8); + break; + default: // FAT32 + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 128, secBytes, 512); + return secBytes[(start_clust * 4) % 512] + (secBytes[((start_clust * 4) % 512) + 1] << 8) + (secBytes[((start_clust * 4) % 512) + 2] << 16) + (secBytes[((start_clust * 4) % 512) + 3] << 24); + break; + } + return 0; + /*if (start_clust < 2) return 0; + if (start_clust >= inst->sectorsPerFAT*128) return 0; + uint8_t secBytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust/128, secBytes, 512); + uint32_t ret_clust = secBytes[(start_clust*4) % 512] + (secBytes[((start_clust * 4) % 512) + 1] << 8) + (secBytes[((start_clust * 4) % 512) + 2] << 16) + (secBytes[((start_clust * 4) % 512) + 3] << 24); + if (ret_clust == 0) return 0; //Free cluster + if (ret_clust == 0x0FFFFFF7) return 0x0FFFFFF7; //Damaged cluster + if (ret_clust >= 0x0FFFFFF8) return 0x0FFFFFF8; //Last cluster + return ret_clust;*/ +} + +uint32_t FAT_FATgetCluster(FAT* inst, uint32_t start_clust) { + uint32_t ret_clust = FAT_FATgetClusterDetailed(inst, start_clust); + if (ret_clust == 0) return 0; //Free cluster + switch (inst->fileSys) { + case FAT12: + if (ret_clust == 0xFF7) return 0; //Damaged cluster + if (ret_clust >= 0xFF8) return 0; //Last cluster + break; + case FAT16: + if (ret_clust == 0xFFF7) return 0; //Damaged cluster + if (ret_clust >= 0xFFF8) return 0; //Last cluster + break; + default: + if (ret_clust == 0x0FFFFFF7) return 0; //Damaged cluster + if (ret_clust >= 0x0FFFFFF8) return 0; //Last cluster + break; + } + return ret_clust; +} + +uint32_t* FAT_FATgetClusterChain(FAT* inst, uint32_t start_clust, uint32_t start_offset, uint32_t max_size) { + /*listHead_t* clustList = listCreate(); + uint32_t i = 0; + while(start_clust != 0){ + if(i >= (start_offset/(inst->sectorsPerCluster*512))){ + listAppend(clustList, (void*)start_clust); + } + start_clust = FAT_FATgetCluster(inst, start_clust); + if(++i >= (start_offset+max_size+inst->sectorsPerCluster*512-1) / (inst->sectorsPerCluster*512)){ + break; + } + } + return clustList;*/ + + uint32_t* clustArr = (uint32_t*) malloc((max_size * 4) / (inst->sectorsPerCluster * 512) + 4); + //listHead_t* clustList = listCreate(); + uint32_t i = 0; + uint32_t prev_clust = start_clust + 131072; // Just make sure, that prev_clust starts with a different value than start_clust + uint8_t secBytes[512]; + + while (start_clust != 0) { + if (i >= (start_offset / (inst->sectorsPerCluster * 512))) { + clustArr[1 + i - (start_offset / (inst->sectorsPerCluster * 512))] = start_clust; + //listAppend(clustList, (void*)start_clust); + } + + switch (inst->fileSys) { + case FAT12: // FAT12 + if (((start_clust * 3) / (512 * 2)) == (((start_clust * 3) / 2 + 1) / 512)) { + // One sector is used + if (((prev_clust * 3) / (512 * 2)) != ((start_clust * 3) / (512 * 2))) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + ((start_clust * 3) / (512 * 2)), secBytes, 512); + } + prev_clust = start_clust; + if ((start_clust % 2) == 0) { // begins at start of byte + start_clust = (secBytes[((start_clust * 3) / 2) % 512] + ((secBytes[((start_clust * 3) / 2 + 1) % 512] & 0x0F) << 8)); + } + else { + start_clust = ((secBytes[((start_clust * 3) / 2 + 1) % 512] << 4) + ((secBytes[((start_clust * 3) / 2) % 512] & 0xF0) >> 4)); + } + } + else { + // Two sectors are used + if (((prev_clust * 3) / (512 * 2)) != ((start_clust * 3) / (512 * 2))) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + ((start_clust * 3) / (512 * 2)), secBytes, 512); + } + uint8_t secBytes2[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + ((start_clust * 3) / 2 + 1) / 512, secBytes2, 512); + prev_clust = start_clust; + if ((start_clust % 2) == 0) { // begins at start of byte + start_clust = (secBytes[511] + ((secBytes2[0] & 0x0F) << 8)); + } + else { + start_clust = ((secBytes2[0] << 4) + ((secBytes[511] & 0xF0) >> 4)); + } + } + break; + case FAT16: // FAT16 + if ((prev_clust / 256) != (start_clust / 256)) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 256, secBytes, 512); + } + prev_clust = start_clust; + start_clust = secBytes[(start_clust * 2) % 512] + (secBytes[((start_clust * 2) % 512) + 1] << 8); + break; + default: // FAT32 + if ((prev_clust / 128) != (start_clust / 128)) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 128, secBytes, 512); + } + prev_clust = start_clust; + start_clust = secBytes[(start_clust * 4) % 512] + (secBytes[((start_clust * 4) % 512) + 1] << 8) + (secBytes[((start_clust * 4) % 512) + 2] << 16) + (secBytes[((start_clust * 4) % 512) + 3] << 24); + break; + } + + if (++i >= (start_offset + max_size + inst->sectorsPerCluster * 512 - 1) / (inst->sectorsPerCluster * 512)) { + break; + } + } + + //return clustList; + clustArr[0] = i - (start_offset / (inst->sectorsPerCluster * 512)); + return clustArr; +} + +void FAT_FATclearClusterChain(FAT* inst, uint32_t start_clust) { + uint32_t prev_clust = start_clust + 131072; // Just make sure, that prev_clust starts with a different value than start_clust + uint8_t secBytes[512]; + + while (start_clust != 0) { + switch (inst->fileSys) { + case FAT12: // FAT12 + if (((uint32_t)(start_clust * 1.5) / 512) == ((uint32_t)(start_clust * 1.5 + 1) / 512)) { + // One sector is used + if (((uint32_t)(prev_clust * 1.5) / 512) != ((uint32_t)(start_clust * 1.5) / 512)) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 / 512), secBytes, 512); + } + prev_clust = start_clust; + if ((uint32_t)(start_clust*1.5) == start_clust * 1.5) { // begins at start of byte + start_clust = (secBytes[(uint32_t)(start_clust*1.5) % 512] + ((secBytes[(uint32_t)(start_clust*1.5 + 1) % 512] & 0x0F) << 8)); + secBytes[(uint32_t)(prev_clust*1.5) % 512] = 0; + secBytes[(uint32_t)(prev_clust*1.5 + 1) % 512] = secBytes[(uint32_t)(prev_clust*1.5 + 1) % 512] & 0xF0; + } + else { + start_clust = ((secBytes[(uint32_t)(start_clust*1.5 + 1) % 512] << 4) + ((secBytes[(uint32_t)(start_clust*1.5) % 512] & 0xF0) >> 4)); + secBytes[(uint32_t)(prev_clust*1.5 + 1) % 512] = 0; + secBytes[(uint32_t)(prev_clust*1.5) % 512] = secBytes[(uint32_t)(prev_clust*1.5) % 512] & 0x0F; + } + if (((uint32_t)(prev_clust * 1.5) / 512) != ((uint32_t)(start_clust * 1.5) / 512)) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(prev_clust * 1.5) / 512, secBytes, 512); + } + } + else { + // Two sectors are used + if (((uint32_t)(prev_clust * 1.5) / 512) != ((uint32_t)(start_clust * 1.5) / 512)) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5) / 512, secBytes, 512); + } + uint8_t secBytes2[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 + 1) / 512, secBytes2, 512); + prev_clust = start_clust; + if ((uint32_t)(start_clust*1.5) == start_clust * 1.5) { // begins at start of byte + start_clust = (secBytes[511] + ((secBytes2[0] & 0x0F) << 8)); + secBytes[511] = 0; + secBytes2[0] = secBytes2[0] & 0xF0; + } + else { + start_clust = ((secBytes2[0] << 4) + ((secBytes[511] & 0xF0) >> 4)); + secBytes[511] = secBytes[511] & 0x0F; + secBytes2[0] = 0; + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(prev_clust * 1.5) / 512, secBytes, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(prev_clust * 1.5 + 1) / 512, secBytes2, 512); + } + if (start_clust == 0xFF7) start_clust = 0; //Damaged cluster + if (start_clust >= 0xFF8) start_clust = 0; //Last cluster + break; + case FAT16: // FAT16 + if ((prev_clust / 256) != (start_clust / 256)) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 256, secBytes, 512); + } + prev_clust = start_clust; + start_clust = secBytes[(start_clust * 2) % 512] + (secBytes[((start_clust * 2) % 512) + 1] << 8); + if (start_clust == 0xFFF7) start_clust = 0; //Damaged cluster + if (start_clust >= 0xFFF8) start_clust = 0; //Last cluster + secBytes[(prev_clust * 2) % 512] = 0; + secBytes[((prev_clust * 2) % 512) + 1] = 0; + if ((prev_clust / 256) != (start_clust / 256)) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + prev_clust / 256, secBytes, 512); + } + break; + default: // FAT32 + if ((prev_clust / 128) != (start_clust / 128)) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 128, secBytes, 512); + } + prev_clust = start_clust; + start_clust = secBytes[(start_clust * 4) % 512] + (secBytes[((start_clust * 4) % 512) + 1] << 8) + (secBytes[((start_clust * 4) % 512) + 2] << 16) + (secBytes[((start_clust * 4) % 512) + 3] << 24); + if (start_clust == 0x0FFFFFF7) start_clust = 0; //Damaged cluster + if (start_clust >= 0x0FFFFFF8) start_clust = 0; //Last cluster + secBytes[(prev_clust * 4) % 512] = 0; + secBytes[((prev_clust * 4) % 512) + 1] = 0; + secBytes[((prev_clust * 4) % 512) + 2] = 0; + secBytes[((prev_clust * 4) % 512) + 3] = 0; + if ((prev_clust / 128) != (start_clust / 128)) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + prev_clust / 128, secBytes, 512); + } + break; + } + } + switch (inst->fileSys) { + case FAT12: // FAT12 + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(prev_clust * 1.5 / 512), secBytes, 512); + break; + case FAT16: // FAT16 + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + prev_clust / 256, secBytes, 512); + break; + default: // FAT32 + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + prev_clust / 128, secBytes, 512); + break; + } +} + +void FAT_FATsetCluster(FAT* inst, uint32_t start_clust, uint32_t pointing_to) { + switch (inst->fileSys) { + case FAT12: // FAT12 + if (start_clust >= (uint32_t)((inst->sectorsPerFAT * 512) / 1.5)) return; + break; + case FAT16: // FAT16 + if (start_clust >= inst->sectorsPerFAT * 256) return; + break; + default: // FAT32 + if (start_clust >= inst->sectorsPerFAT * 128) return; + break; + } + uint8_t secBytes[512]; + switch (inst->fileSys) { + case FAT12: // FAT12 + if (((uint32_t)(start_clust * 1.5) / 512) == ((uint32_t)(start_clust * 1.5 + 1) / 512)) { + // One sector is used + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 / 512), secBytes, 512); + if ((uint32_t)(start_clust*1.5) == start_clust * 1.5) { // begins at start of byte + secBytes[(uint32_t)(start_clust*1.5) % 512] = (uint8_t)(pointing_to & 0x0FF); + secBytes[(uint32_t)(start_clust*1.5 + 1) % 512] &= 0xF0; + secBytes[(uint32_t)(start_clust*1.5 + 1) % 512] |= (uint8_t)((pointing_to & 0xF00) >> 8); + } + else { + secBytes[(uint32_t)(start_clust*1.5) % 512] &= 0x0F; + secBytes[(uint32_t)(start_clust*1.5) % 512] |= (uint8_t)((pointing_to & 0x0F) << 4); + secBytes[(uint32_t)(start_clust*1.5 + 1) % 512] = (uint8_t)(pointing_to >> 4); + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 / 512), secBytes, 512); + } + else { + // Two sectors are used + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5) / 512, secBytes, 512); + uint8_t secBytes2[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 + 1) / 512, secBytes2, 512); + if ((uint32_t)(start_clust*1.5) == start_clust * 1.5) { // begins at start of byte + secBytes[511] = (uint8_t)(pointing_to & 0x0FF); + secBytes2[0] &= 0xF0; + secBytes2[0] |= (uint8_t)((pointing_to & 0xF00) >> 8); + } + else { + secBytes[511] &= 0x0F; + secBytes[511] |= (uint8_t)((pointing_to & 0x0F) << 4); + secBytes2[0] = (uint8_t)(pointing_to >> 4); + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 / 512), secBytes, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(start_clust * 1.5 + 1) / 512, secBytes2, 512); + } + break; + case FAT16: // FAT16 + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 256, secBytes, 512); + secBytes[(start_clust * 2) % 512] = (uint8_t)(pointing_to & 0x00FF); + secBytes[(start_clust * 2) % 512 + 1] = (uint8_t)((pointing_to & 0xFF00) >> 8); + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 256, secBytes, 512); + break; + default: // FAT32 + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 128, secBytes, 512); + secBytes[(start_clust * 4) % 512] = (uint8_t)(pointing_to & 0x000000FF); + secBytes[(start_clust * 4) % 512 + 1] = (uint8_t)((pointing_to & 0x0000FF00) >> 8); + secBytes[(start_clust * 4) % 512 + 2] = (uint8_t)((pointing_to & 0x00FF0000) >> 16); + secBytes[(start_clust * 4) % 512 + 3] = (uint8_t)((pointing_to & 0xFF000000) >> 24); + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 128, secBytes, 512); + break; + } + + /*if (start_clust >= inst->sectorsPerFAT*128) return; + uint8_t secBytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust/128, secBytes, 512); + secBytes[(start_clust * 4) % 512] = (uint8_t)(pointing_to & 0x000000FF); + secBytes[(start_clust * 4) % 512 + 1] = (uint8_t)((pointing_to & 0x0000FF00) >> 8); + secBytes[(start_clust * 4) % 512 + 2] = (uint8_t)((pointing_to & 0x00FF0000) >> 16); + secBytes[(start_clust * 4) % 512 + 3] = (uint8_t)((pointing_to & 0xFF000000) >> 24); + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + start_clust / 128, secBytes, 512);*/ +} + +uint32_t FAT_FATfindFreeCluster(FAT* inst) { + uint8_t secBytes[512]; + uint32_t cur_clust; //Starts at cluster 2, which is the first one + uint32_t prev_fatsec = 0xFFFFFFFF; // Has to be different than cur_clust + uint32_t ret_clust; + switch (inst->fileSys) { + case FAT12: // FAT12 + for (cur_clust = 2; cur_clust < (uint32_t)((inst->sectorsPerFAT * 512) / 1.5); ++cur_clust) { + if (((uint32_t)(cur_clust * 1.5) / 512) == ((uint32_t)(cur_clust * 1.5 + 1) / 512)) { + // One sector is used + if (prev_fatsec != (uint32_t)(cur_clust * 1.5 / 512)) { // Make sure the sector is only beeing read when necessary + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(cur_clust * 1.5 / 512), secBytes, 512); + prev_fatsec = (uint32_t)(cur_clust * 1.5 / 512); + } + if ((uint32_t)(cur_clust*1.5) == cur_clust * 1.5) { // begins at start of byte + ret_clust = (secBytes[(uint32_t)(cur_clust*1.5) % 512] + ((secBytes[(uint32_t)(cur_clust*1.5 + 1) % 512] & 0x0F) << 8)); + } + else { + ret_clust = ((secBytes[(uint32_t)(cur_clust*1.5 + 1) % 512] << 4) + ((secBytes[(uint32_t)(cur_clust*1.5) % 512] & 0xF0) >> 4)); + } + } + else { + // Two sectors are used + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(cur_clust * 1.5) / 512, secBytes, 512); + uint8_t secBytes2[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + (uint32_t)(cur_clust * 1.5 + 1) / 512, secBytes2, 512); + if ((uint32_t)(cur_clust*1.5) == cur_clust * 1.5) { // begins at start of byte + ret_clust = (secBytes[511] + ((secBytes2[0] & 0x0F) << 8)); + } + else { + ret_clust = ((secBytes2[0] << 4) + ((secBytes[511] & 0xF0) >> 4)); + } + } + if (ret_clust == 0) return cur_clust; + } + break; + case FAT16: // FAT16 + for (cur_clust = 2; cur_clust < (inst->sectorsPerFAT * 256); ++cur_clust) { + if (prev_fatsec != cur_clust / 256) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + cur_clust / 256, secBytes, 512); + prev_fatsec = cur_clust / 256; + } + ret_clust = secBytes[(cur_clust * 2) % 512] + (secBytes[((cur_clust * 2) % 512) + 1] << 8); + if (ret_clust == 0) return cur_clust; //Free cluster + } + break; + default: // FAT32 + for (cur_clust = 2; cur_clust < (inst->sectorsPerFAT * 128); ++cur_clust) { + if (prev_fatsec != cur_clust / 128) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + cur_clust / 128, secBytes, 512); + prev_fatsec = cur_clust / 128; + } + ret_clust = secBytes[(cur_clust * 4) % 512] + (secBytes[((cur_clust * 4) % 512) + 1] << 8) + (secBytes[((cur_clust * 4) % 512) + 2] << 16) + (secBytes[((cur_clust * 4) % 512) + 3] << 24); + if (ret_clust == 0) return cur_clust; //Free cluster + } + break; + } + return 0; +} + +char* formatFilePath(char* filepath) { + char delimiter[] = "/\\"; +#define FAT_MAX_PATH_FILES 16 +#define FAT_MAX_FNAME_LEN 34 + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + unsigned int ret_arr_size = strlen(filepath) + 1; + int i, j; + for (i = 0; i < FAT_MAX_PATH_FILES; ++i) { + for (j = 0; j < FAT_MAX_FNAME_LEN; ++j) { + spl_path[i][j] = '\0'; + } + } + int path_size = 0; + char* cur_file = strtok(filepath, delimiter); + while (cur_file != 0 && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not to long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + for (i = 0; i < path_size; ++i) { + if (strcmp(spl_path[i], ".") == 0) { //if spl_path[i] equals "." + strcpy(spl_path[i], ""); + continue; + } + if (strcmp(spl_path[i], "..") == 0) { //if spl_path[i] equals ".." + if (i > 0) { + for (j = i - 1; j >= 0; --j) { + if (strlen(spl_path[j]) != 0) { + strcpy(spl_path[j], ""); + break; + } + } + } + strcpy(spl_path[i], ""); + continue; + } + } + + for (i = 0; i < ret_arr_size; ++i) { + filepath[i] = '\0'; + } + for (i = 0; i < path_size; ++i) { + if (strcmp(spl_path[i], "")) { //if spl_path[i] does NOT equal to "" + if (strcmp(filepath, "") == 0) { //if filepath.Length is 0 + strcpy(filepath, spl_path[i]); + } + else { + strcat(filepath, "/"); + strcat(filepath, spl_path[i]); + } + } + } + return filepath; +} + +uint32_t* FAT_readFileEntryLocation(FAT* inst, char* filepath) { + uint32_t ret_long_clust = 0; + uint32_t ret_long_offset = 0; + uint8_t ret_has_long = 0; + uint8_t ret[32]; + //Format and split the file path + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < FAT_MAX_PATH_FILES; ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path[k][l] = 0; + } + } + char delimiter[] = "/"; + int path_size = 0; + formatFilePath(filepath); + size_t tmp_filepath_len = strlen(filepath) + 1; + //char tmp_filepath[tmp_filepath_len]; !!! MEMORY LEAK !!! + char* tmp_filepath = (char*) malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + char* cur_file = strtok(tmp_filepath, delimiter); + while (cur_file != 0 && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not to long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + + free(tmp_filepath); // !!! MEMORY LEAK !!! + + uint32_t cur_clust = inst->startClustOfRootDir; + + for (uint32_t k = 0; k < path_size; ++k) { + //Split the current file into name and extension + int32_t cur_file_len = strlen(spl_path[k]); + int32_t lastDot = strrchr_new(spl_path[k], '.'); + if (lastDot == -1) lastDot = cur_file_len; + //char cur_file_name[lastDot + 1]; !!! MEMORY LEAK !!! + char* cur_file_name = (char*) malloc(lastDot + 1); + for (uint32_t j = 0; j < lastDot; ++j) { + cur_file_name[j] = spl_path[k][j]; + } + cur_file_name[lastDot] = 0; //Null termination + // char cur_file_ext[cur_file_len - lastDot]; !!! MEMORY LEAK !!! + char* cur_file_ext = (char*) malloc(cur_file_len - lastDot); + for (uint32_t j = (lastDot + 1); j < cur_file_len; ++j) { + cur_file_ext[j - (lastDot + 1)] = spl_path[k][j]; + } + cur_file_ext[MAX(cur_file_len - lastDot - 1, 0)] = 0; //Null termination + + char long_fname_buffer[208]; + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + + + + + + + + + + if ((inst->fileSys <= FAT16) && k == 0) { //root directory of FAT12 and FAT16 + uint8_t loopBreak = 0; + for (uint32_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0x00) return 0; //Free from here on + if (cur_sec_bytes[i] == 0xE5) continue; //File was deleted + + if (cur_sec_bytes[i + 11] == 0x0F) { //Part of long filename + if (!ret_has_long) { + ret_long_clust = j; + ret_long_offset = i; + ret_has_long = 1; + } + + uint8_t cur_long_fname_temp[] = { cur_sec_bytes[i + 1], cur_sec_bytes[i + 3], cur_sec_bytes[i + 5], cur_sec_bytes[i + 7], cur_sec_bytes[i + 9], + cur_sec_bytes[i + 14], cur_sec_bytes[i + 16], cur_sec_bytes[i + 18], cur_sec_bytes[i + 20], cur_sec_bytes[i + 22], cur_sec_bytes[i + 24], + cur_sec_bytes[i + 28], cur_sec_bytes[i + 30] }; + for (uint8_t l = 0; l < /*Length of cur_long_fname_temp*/13; ++l) { + if ((/*if last long file name entry*/(cur_sec_bytes[i] & 0xF0) == 0x40) && (cur_long_fname_temp[l] == 0)) break; + long_fname_buffer[((cur_sec_bytes[i] & 0x0F) - 1) * 13 + l] = (char)cur_long_fname_temp[l]; + } + continue; + } + + char cur_filename[FAT_MAX_FNAME_LEN]; + char cur_ext[FAT_MAX_FNAME_LEN]; + + if (long_fname_buffer[0] == 0) { //if file name is short + for (uint8_t l = 0; l < 8; ++l) { + cur_filename[l] = (char)cur_sec_bytes[i + l]; + } + cur_filename[8] = 0; //Null termination + strtrimend(cur_filename); + for (uint8_t l = 0; l < 3; ++l) { + cur_ext[l] = (char)cur_sec_bytes[i + 8 + l]; + } + cur_ext[3] = 0; //Null termination + strtrimend(cur_ext); + ret_has_long = 0; + } + else { //if file name is long + //Split the current file into name and extension + cur_file_len = strlen(long_fname_buffer); + lastDot = strrchr_new(long_fname_buffer, '.'); + if (lastDot == -1) lastDot = cur_file_len; + cur_filename[1] = 0; //Null termination if lastDot = 0 + for (uint32_t l = 0; l < lastDot; ++l) { + cur_filename[l] = long_fname_buffer[l]; + } + cur_filename[lastDot] = 0; //Null termination + for (uint32_t l = (lastDot + 1); l < cur_file_len; ++l) { + cur_ext[l - (lastDot + 1)] = long_fname_buffer[l]; + } + cur_ext[cur_file_len - lastDot - 1] = 0; //Null termination + + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + } + + strlwr(cur_filename); + strlwr(cur_file_name); + if (strcmp(cur_filename, cur_file_name) == 0) { //if the requested file name matches the file name of the current entry + if (*cur_file_ext == 0) { //if cur_file_ext is empty + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + strlwr(cur_ext); + strlwr(cur_file_ext); + if (strcmp(cur_ext, cur_file_ext) == 0) { //if the requested file extension matches the file extension of the current entry + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + ret_has_long = 0; + continue; + } + } + + if (k == (path_size - 1)) { //if is final file + uint32_t* entry_loc = (uint32_t*) malloc(16); + entry_loc[0] = j; + entry_loc[1] = i; + if (ret_has_long) { + entry_loc[2] = ret_long_clust; + entry_loc[3] = ret_long_offset; + } + else { + entry_loc[2] = entry_loc[0]; + entry_loc[3] = entry_loc[1]; + } + entry_loc[1] |= 0x80000000; //indicates that the entry is in the root directory before the clusters + return entry_loc; + } + else { + if ((ret[11] & FAT_ATTR_SUBDIR) == FAT_ATTR_SUBDIR) { //Subdirectory + ret_has_long = 0; + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + return 0; + } + } + } + ret_has_long = false; + } + if (loopBreak) break; + } + } + else { + while (cur_clust != 0) { + uint8_t loopBreak = 0; + + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0x00) return 0; //Free from here on + if (cur_sec_bytes[i] == 0xE5) continue; //File was deleted + + if (cur_sec_bytes[i + 11] == 0x0F) { //Part of long filename + if (!ret_has_long) { + ret_long_clust = cur_clust; + ret_long_offset = i; + ret_has_long = 1; + } + + uint8_t cur_long_fname_temp[] = { cur_sec_bytes[i + 1], cur_sec_bytes[i + 3], cur_sec_bytes[i + 5], cur_sec_bytes[i + 7], cur_sec_bytes[i + 9], + cur_sec_bytes[i + 14], cur_sec_bytes[i + 16], cur_sec_bytes[i + 18], cur_sec_bytes[i + 20], cur_sec_bytes[i + 22], cur_sec_bytes[i + 24], + cur_sec_bytes[i + 28], cur_sec_bytes[i + 30] }; + for (uint8_t l = 0; l < /*Length of cur_long_fname_temp*/13; ++l) { + if ((/*if last long file name entry*/(cur_sec_bytes[i] & 0xF0) == 0x40) && (cur_long_fname_temp[l] == 0)) break; + long_fname_buffer[((cur_sec_bytes[i] & 0x0F) - 1) * 13 + l] = (char)cur_long_fname_temp[l]; + } + continue; + } + + char cur_filename[FAT_MAX_FNAME_LEN]; + char cur_ext[FAT_MAX_FNAME_LEN]; + + if (long_fname_buffer[0] == 0) { //if file name is short + for (uint8_t l = 0; l < 8; ++l) { + cur_filename[l] = (char)cur_sec_bytes[i + l]; + } + cur_filename[8] = 0; //Null termination + strtrimend(cur_filename); + for (uint8_t l = 0; l < 3; ++l) { + cur_ext[l] = (char)cur_sec_bytes[i + 8 + l]; + } + cur_ext[3] = 0; //Null termination + strtrimend(cur_ext); + ret_has_long = 0; + } + else { //if file name is long + //Split the current file into name and extension + cur_file_len = strlen(long_fname_buffer); + lastDot = strrchr_new(long_fname_buffer, '.'); + if (lastDot == -1) lastDot = cur_file_len; + cur_filename[1] = 0; //Null termination if lastDot = 0 + for (uint32_t l = 0; l < lastDot; ++l) { + cur_filename[l] = long_fname_buffer[l]; + } + cur_filename[lastDot] = 0; //Null termination + for (uint32_t l = (lastDot + 1); l < cur_file_len; ++l) { + cur_ext[l - (lastDot + 1)] = long_fname_buffer[l]; + } + cur_ext[cur_file_len - lastDot - 1] = 0; //Null termination + + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + } + + strlwr(cur_filename); + strlwr(cur_file_name); + if (strcmp(cur_filename, cur_file_name) == 0) { //if the requested file name matches the file name of the current entry + if (*cur_file_ext == 0) { //if cur_file_ext is empty + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + strlwr(cur_ext); + strlwr(cur_file_ext); + if (strcmp(cur_ext, cur_file_ext) == 0) { //if the requested file extension matches the file extension of the current entry + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + ret_has_long = 0; + continue; + } + } + + if (k == (path_size - 1)) { //if is final file + uint32_t* entry_loc = (uint32_t*) malloc(16); + entry_loc[0] = cur_clust; + entry_loc[1] = j * 512 + i; + if (ret_has_long) { + entry_loc[2] = ret_long_clust; + entry_loc[3] = ret_long_offset; + } + else { + entry_loc[2] = entry_loc[0]; + entry_loc[3] = entry_loc[1]; + } + return entry_loc; + } + else { + if ((ret[11] & FAT_ATTR_SUBDIR) == FAT_ATTR_SUBDIR) { //Subdirectory + ret_has_long = 0; + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + return 0; + } + } + } + ret_has_long = false; + } + if (loopBreak) break; + } + if (loopBreak) break; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + } + return 0; +} + +uint8_t FAT_writeFileContents(FAT* inst, char* filepath, uint8_t* contents, uint32_t length) { + uint32_t* entry_loc = FAT_readFileEntryLocation(inst, filepath); + if (entry_loc == 0) return 0; + uint8_t isRootDirOfFAT12Or16 = 0; + if (entry_loc[1] & 0x80000000) { + isRootDirOfFAT12Or16 = 1; + entry_loc[1] &= 0x7FFFFFFF; + } + uint8_t entry_sec_bytes[512]; + if (isRootDirOfFAT12Or16) { // if file is in the root directory of a FAT12 or FAT16 file system + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + } + else { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2)*inst->sectorsPerCluster + entry_loc[1] / 512, entry_sec_bytes, 512); + } + uint8_t entry[32]; + memcpy(entry, entry_sec_bytes + (entry_loc[1] % 512), 32); + + uint32_t cur_clust = entry[0x1A] + (entry[0x1B] << 8) + (entry[0x14] << 16) + (entry[0x15] << 24); + uint32_t prev_clust = 0; + + if (cur_clust == 0) { + cur_clust = FAT_FATfindFreeCluster(inst); + entry[0x1A] = cur_clust; + entry[0x1B] = (cur_clust >> 8); + entry[0x14] = (cur_clust >> 16); + entry[0x15] = (cur_clust >> 24); + } + entry[0x1C] = length; + entry[0x1D] = (length >> 8); + entry[0x1E] = (length >> 16); + entry[0x1F] = (length >> 24); + memcpy(entry_sec_bytes + (entry_loc[1] % 512), entry, 32); + //free(entry_loc); !!! MEMORY LEAK !!! + if (isRootDirOfFAT12Or16) { // if file is in the root directory of a FAT12 or FAT16 file system + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + } + else { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2) * inst->sectorsPerCluster + entry_loc[1] / 512, entry_sec_bytes, 512); + } + + for (uint32_t i = 0; i <= (length / 512) / inst->sectorsPerCluster; ++i) { + if (prev_clust != 0) { + //Write FAT + FAT_FATsetCluster(inst, prev_clust, cur_clust); + } + + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + uint8_t cur_content_sec[512] = { 0 }; + memcpy(cur_content_sec, contents + i * 512 * inst->sectorsPerCluster + j * 512, ((i * 512 * inst->sectorsPerCluster + j * 512 + 512) > length) ? (length % 512) : 512); + //Write content + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2) * inst->sectorsPerCluster + j, cur_content_sec, 512); + } + prev_clust = cur_clust; + //If the cluster chain has ended, just find a free cluster + if (FAT_FATgetClusterDetailed(inst, cur_clust) == 0) { + FAT_FATsetCluster(inst, cur_clust, (inst->fileSys == FAT12) ? 0x0FF8 : ((inst->fileSys == FAT16) ? 0xFFF8 : 0x0FFFFFF8)); + cur_clust = FAT_FATfindFreeCluster(inst); + FAT_FATsetCluster(inst, prev_clust, 0); + } + else if (FAT_FATgetClusterDetailed(inst, cur_clust) >= ((inst->fileSys == FAT12) ? 0x0FF8 : ((inst->fileSys == FAT16) ? 0xFFF8 : 0x0FFFFFF8))) { + cur_clust = FAT_FATfindFreeCluster(inst); + } + else { + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + + FAT_FATsetCluster(inst, prev_clust, (inst->fileSys == FAT12) ? 0x0FF8 : ((inst->fileSys == FAT16) ? 0xFFF8 : 0x0FFFFFF8)); //Last cluster + + //Clean up the remaining clusters + /*while(cur_clust != 0){ + prev_clust = cur_clust; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + FAT_FATsetCluster(inst, prev_clust, 0); + }*/ + FAT_FATclearClusterChain(inst, cur_clust); + return 1; +} + +uint8_t FAT_createDirectory(FAT* inst, char* filepath) { + uint8_t* entry = FAT_createFile(inst, filepath, FAT_ATTR_SUBDIR); + if (entry == 0) return 0; //Directory could not be created + + uint8_t new_dir_entry[32]; + memcpy(new_dir_entry, entry, 32); + free(entry); + //Directory created or found + //Format and split the file path + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < FAT_MAX_PATH_FILES; ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path[k][l] = 0; + } + } + char delimiter[] = "/"; + int path_size = 0; + formatFilePath(filepath); + size_t tmp_filepath_len = strlen(filepath) + 1; + //char tmp_filepath[tmp_filepath_len]; !!!MEMORY LEAK !!! + char* tmp_filepath = (char*)malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + char* cur_file = strtok(tmp_filepath, delimiter); + while (cur_file && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not to long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + + //Get the file container path + uint16_t path_container_len = 0; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + ++path_container_len; //This line is before the break, because there needs to be space for the '/' and the null termination + if (spl_path[k][l] == 0) break; + } + } + //char path_container[path_container_len]; !!! MEMORY LEAK !!! + char* path_container = (char*) malloc(path_container_len); + memset(path_container, 0, path_container_len); + uint16_t i = 0; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + if (spl_path[k][l] == 0) break; + path_container[i] = spl_path[k][l]; + ++i; + } + if (path_container_len == (i + 1)) break; + path_container[i] = '/'; + ++i; + } + + uint32_t* entry_loc = FAT_readFileEntryLocation(inst, filepath); + if (entry_loc == 0) return 0; //Could not find the entry to the new directory + uint8_t isRootDirOfFAT12Or16 = 0; + if (entry_loc[1] & 0x80000000) { + isRootDirOfFAT12Or16 = 1; + entry_loc[1] &= 0x7FFFFFFF; + } + uint8_t entry_sec_bytes[512]; + if (isRootDirOfFAT12Or16) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + } + else { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2)*inst->sectorsPerCluster + entry_loc[1] / 512, entry_sec_bytes, 512); + } + + uint32_t cur_clust = FAT_FATfindFreeCluster(inst); + new_dir_entry[0x1A] = cur_clust; + new_dir_entry[0x1B] = (cur_clust >> 8); + new_dir_entry[0x14] = (cur_clust >> 16); + new_dir_entry[0x15] = (cur_clust >> 24); + + memcpy(entry_sec_bytes + (entry_loc[1] % 512), new_dir_entry, 32); + if (isRootDirOfFAT12Or16) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + } + else { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2) * inst->sectorsPerCluster + entry_loc[1] / 512, entry_sec_bytes, 512); + } + + uint8_t dir_contents[] = { '.', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, (cur_clust >> 16), (cur_clust >> 24), 0x00, 0x00, 0x00, 0x00, cur_clust, (cur_clust >> 8), 0x00, 0x00, 0x00, 0x00, + '.', '.', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, (entry_loc[0] >> 16), (entry_loc[0] >> 24), 0x00, 0x00, 0x00, 0x00, entry_loc[0], (entry_loc[0] >> 8), 0x00, 0x00, 0x00, 0x00 }; + //free(entry_loc); !!! MEMORY LEAK !!! + //Write content + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2) * inst->sectorsPerCluster, dir_contents, 64); + + //Last cluster + FAT_FATsetCluster(inst, cur_clust, (inst->fileSys == FAT12) ? 0x0FF8 : ((inst->fileSys == FAT16) ? 0xFFF8 : 0x0FFFFFF8)); + + return 1; //Directory contents successfully saved +} + +void FAT_deleteFile(FAT* inst, char* filepath) { + //TODO: handle deletion of directory + uint8_t* entry = FAT_readFileEntry(inst, filepath); + if (entry == 0) return; //File doesn't exist + if (entry[11] & FAT_ATTR_SUBDIR) { + file_t file_inst = { { 0 },{ 0 }, 0, 0, 0 }; + uint32_t i = 0; + while (FAT_readFileEntryByIndex(inst, &file_inst, filepath, i)) { + if (strcmp(file_inst.name, ".") && strcmp(file_inst.name, "..")) { + size_t tmp_filepath_len = strlen(filepath) + strlen(file_inst.name) + 2; + //char tmp_filepath[tmp_filepath_len]; !!! MEMORY LEAK !!! + char* tmp_filepath = (char*)malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + strcat(tmp_filepath, "/"); + strcat(tmp_filepath, file_inst.name); + FAT_deleteFile(inst, tmp_filepath); + } + ++i; + } + } + uint32_t* entry_loc = FAT_readFileEntryLocation(inst, filepath); + //entry_loc[0] cluster of short name entry + //entry_loc[1] offset from start of cluster of short name entry + //entry_loc[2] cluster of long name entry (if there is none then same as entry_loc[0]) + //entry_loc[3] offset from start of cluster of long name entry (if there is none then same as entry_loc[1]) + uint8_t isRootDirOfFAT12Or16 = 0; + if (entry_loc[1] & 0x80000000) { + isRootDirOfFAT12Or16 = 1; + entry_loc[1] &= 0x7FFFFFFF; + } + + uint8_t entry_sec_bytes[512]; + + if (isRootDirOfFAT12Or16) { + if (entry_loc[0] == entry_loc[2]) { + for (uint32_t j = entry_loc[3]; j <= entry_loc[1]; j += 32) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + entry_sec_bytes[j % 512] = 0xE5; + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + } + } + else { + //Still in the first of the two clusters + for (uint32_t j = entry_loc[3]; j <= 512; j += 32) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[2], entry_sec_bytes, 512); + entry_sec_bytes[j % 512] = 0xE5; + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[2], entry_sec_bytes, 512); + } + //Already in the second of the two clusters + for (uint32_t j = 0; j <= entry_loc[1]; j += 32) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + entry_sec_bytes[j % 512] = 0xE5; + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + entry_loc[0], entry_sec_bytes, 512); + } + } + } + else { + if (entry_loc[0] == entry_loc[2]) { + //Still in the first of the two clusters + for (uint32_t j = entry_loc[3]; j <= entry_loc[1]; j += 32) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2)*inst->sectorsPerCluster + j / 512, entry_sec_bytes, 512); + entry_sec_bytes[j % 512] = 0xE5; + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2)*inst->sectorsPerCluster + j / 512, entry_sec_bytes, 512); + } + } + else { + //Still in the first of the two clusters + for (uint32_t j = entry_loc[3]; j <= inst->sectorsPerCluster * 512; j += 32) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[2] - 2)*inst->sectorsPerCluster + j / 512, entry_sec_bytes, 512); + entry_sec_bytes[j % 512] = 0xE5; + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[2] - 2)*inst->sectorsPerCluster + j / 512, entry_sec_bytes, 512); + } + //Already in the second of the two clusters + for (uint32_t j = 0; j <= entry_loc[1]; j += 32) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2)*inst->sectorsPerCluster + j / 512, entry_sec_bytes, 512); + entry_sec_bytes[j % 512] = 0xE5; + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (entry_loc[0] - 2)*inst->sectorsPerCluster + j / 512, entry_sec_bytes, 512); + } + } + } + free(entry_loc); + + uint32_t cur_clust = entry[0x1A] + (entry[0x1B] << 8) + (entry[0x14] << 16) + (entry[0x15] << 24); + free(entry); + //Clean up the remaining clusters + FAT_FATclearClusterChain(inst, cur_clust); + /*listHead_t* clustList = FAT_FATgetClusterChain(inst, cur_clust, 0, FAT_getFilesize(entry)); + uint32_t clustList_index = 1; + while(cur_clust != 0){ + FAT_FATsetCluster(inst, cur_clust, 0); + cur_clust = (uint32_t)listShowElement(clustList, ++clustList_index); + } + listDeleteAllWithoutData(clustList);*/ + /*uint32_t prev_clust = 0; + while(cur_clust != 0){ + prev_clust = cur_clust; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + FAT_FATsetCluster(inst, prev_clust, 0); + }*/ +} + +char* FAT_readVolumeLabel(FAT* inst) { + if (inst->fileSys <= FAT16) { + for (uint16_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + for (uint16_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i + 11] == FAT_ATTR_VOLLABEL) { + //Entry is a volume label + static char ret[12]; + for (uint8_t k = 0; k < 11; ++k) { + ret[k] = cur_sec_bytes[i + k]; + } + ret[12] = 0; + return strtrimend(ret); + } + } + } + } + else { + uint32_t cur_clust = inst->startClustOfRootDir; + + while (cur_clust != 0) { + for (uint8_t j = 0; j < inst->sectorsPerCluster; ++j) { + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + for (uint16_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i + 11] == FAT_ATTR_VOLLABEL) { + //Entry is a volume label + static char ret[12]; + for (uint8_t k = 0; k < 11; ++k) { + ret[k] = cur_sec_bytes[i + k]; + } + ret[12] = 0; + return strtrimend(ret); + } + } + } + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + return 0; +} + +uint8_t* FAT_readFileEntry(FAT* inst, char* filepath) { + uint8_t* ret = (uint8_t*) malloc(32); + //Format and split the file path + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < FAT_MAX_PATH_FILES; ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path[k][l] = 0; + } + } + char delimiter[] = "/"; + int path_size = 0; + formatFilePath(filepath); + size_t tmp_filepath_len = strlen(filepath) + 1; + //char tmp_filepath[tmp_filepath_len]; !!!MEMORY LEAK !!! + char* tmp_filepath = (char*)malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + char* cur_file = strtok(tmp_filepath, delimiter); + while (cur_file != 0 && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not to long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + + uint32_t cur_clust = inst->startClustOfRootDir; + + for (uint32_t k = 0; k < path_size; ++k) { + //Split the current file into name and extension + int cur_file_len = strlen(spl_path[k]); + int32_t lastDot = strrchr_new(spl_path[k], '.'); + if (lastDot == -1) lastDot = cur_file_len; + //char cur_file_name[lastDot + 1]; !!!MEMORY LEAK !!! + char* cur_file_name = (char*)malloc(lastDot + 1); + for (uint32_t j = 0; j < lastDot; ++j) { + cur_file_name[j] = spl_path[k][j]; + } + cur_file_name[lastDot] = 0; //Null termination + //char cur_file_ext[cur_file_len - lastDot]; !!!MEMORY LEAK !!! + char* cur_file_ext = (char*)malloc(cur_file_len - lastDot); + for (uint32_t j = (lastDot + 1); j < cur_file_len; ++j) { + cur_file_ext[j - (lastDot + 1)] = spl_path[k][j]; + } + cur_file_ext[MAX(cur_file_len - lastDot - 1, 0)] = 0; //Null termination + + char long_fname_buffer[208]; + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + + + if ((inst->fileSys <= FAT16) && k == 0) { //root directory of FAT12 and FAT16 + + uint8_t loopBreak = 0; + for (uint16_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0x00) { + free(ret); + return 0; //Free from here on + } + if (cur_sec_bytes[i] == 0xE5) continue; //File was deleted + + if (cur_sec_bytes[i + 11] == 0x0F) { //Part of long filename + uint8_t cur_long_fname_temp[] = { cur_sec_bytes[i + 1], cur_sec_bytes[i + 3], cur_sec_bytes[i + 5], cur_sec_bytes[i + 7], cur_sec_bytes[i + 9], + cur_sec_bytes[i + 14], cur_sec_bytes[i + 16], cur_sec_bytes[i + 18], cur_sec_bytes[i + 20], cur_sec_bytes[i + 22], cur_sec_bytes[i + 24], + cur_sec_bytes[i + 28], cur_sec_bytes[i + 30] }; + for (uint8_t l = 0; l < /*Length of cur_long_fname_temp*/13; ++l) { + if ((/*if last long file name entry*/(cur_sec_bytes[i] & 0xF0) == 0x40) && (cur_long_fname_temp[l] == 0)) break; + long_fname_buffer[((cur_sec_bytes[i] & 0x0F) - 1) * 13 + l] = (char)cur_long_fname_temp[l]; + } + continue; + } + + char cur_filename[FAT_MAX_FNAME_LEN]; + char cur_ext[FAT_MAX_FNAME_LEN]; + + if (long_fname_buffer[0] == 0) { //if file name is short + for (uint8_t l = 0; l < 8; ++l) { + cur_filename[l] = (char)cur_sec_bytes[i + l]; + } + cur_filename[8] = 0; //Null termination + strtrimend(cur_filename); + for (uint8_t l = 0; l < 3; ++l) { + cur_ext[l] = (char)cur_sec_bytes[i + 8 + l]; + } + cur_ext[3] = 0; //Null termination + strtrimend(cur_ext); + } + else { //if file name is long + //Split the current file into name and extension + cur_file_len = strlen(long_fname_buffer); + lastDot = strrchr_new(long_fname_buffer, '.'); + if (lastDot == -1) lastDot = cur_file_len; + cur_filename[1] = 0; //Null termination if lastDot = 0 + for (uint32_t l = 0; l < lastDot; ++l) { + cur_filename[l] = long_fname_buffer[l]; + } + cur_filename[lastDot] = 0; //Null termination + for (uint32_t l = (lastDot + 1); l < cur_file_len; ++l) { + cur_ext[l - (lastDot + 1)] = long_fname_buffer[l]; + } + cur_ext[cur_file_len - lastDot - 1] = 0; //Null termination + + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + } + + strlwr(cur_filename); + strlwr(cur_file_name); + if (strcmp(cur_filename, cur_file_name) == 0) { //if the requested file name matches the file name of the current entry + if (*cur_file_ext == 0) { //if cur_file_ext is empty + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + strlwr(cur_ext); + strlwr(cur_file_ext); + if (strcmp(cur_ext, cur_file_ext) == 0) { //if the requested file extension matches the file extension of the current entry + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else continue; + } + + if (k == (path_size - 1)) { //if is final file + return ret; + } + else { + if ((ret[11] & FAT_ATTR_SUBDIR) == FAT_ATTR_SUBDIR) { //Subdirectory + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + free(ret); + return 0; + } + } + + } + } + if (loopBreak) break; + } + + } + else { + while (cur_clust != 0) { + uint8_t loopBreak = 0; + + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0x00) { + free(ret); + return 0; //Free from here on + } + if (cur_sec_bytes[i] == 0xE5) continue; //File was deleted + + if (cur_sec_bytes[i + 11] == 0x0F) { //Part of long filename + uint8_t cur_long_fname_temp[] = { cur_sec_bytes[i + 1], cur_sec_bytes[i + 3], cur_sec_bytes[i + 5], cur_sec_bytes[i + 7], cur_sec_bytes[i + 9], + cur_sec_bytes[i + 14], cur_sec_bytes[i + 16], cur_sec_bytes[i + 18], cur_sec_bytes[i + 20], cur_sec_bytes[i + 22], cur_sec_bytes[i + 24], + cur_sec_bytes[i + 28], cur_sec_bytes[i + 30] }; + for (uint8_t l = 0; l < /*Length of cur_long_fname_temp*/13; ++l) { + if ((/*if last long file name entry*/(cur_sec_bytes[i] & 0xF0) == 0x40) && (cur_long_fname_temp[l] == 0)) break; + long_fname_buffer[((cur_sec_bytes[i] & 0x0F) - 1) * 13 + l] = (char)cur_long_fname_temp[l]; + } + continue; + } + + char cur_filename[FAT_MAX_FNAME_LEN]; + char cur_ext[FAT_MAX_FNAME_LEN]; + + if (long_fname_buffer[0] == 0) { //if file name is short + for (uint8_t l = 0; l < 8; ++l) { + cur_filename[l] = (char)cur_sec_bytes[i + l]; + } + cur_filename[8] = 0; //Null termination + strtrimend(cur_filename); + for (uint8_t l = 0; l < 3; ++l) { + cur_ext[l] = (char)cur_sec_bytes[i + 8 + l]; + } + cur_ext[3] = 0; //Null termination + strtrimend(cur_ext); + } + else { //if file name is long + //Split the current file into name and extension + cur_file_len = strlen(long_fname_buffer); + lastDot = strrchr_new(long_fname_buffer, '.'); + if (lastDot == -1) lastDot = cur_file_len; + cur_filename[1] = 0; //Null termination if lastDot = 0 + for (uint32_t l = 0; l < lastDot; ++l) { + cur_filename[l] = long_fname_buffer[l]; + } + cur_filename[lastDot] = 0; //Null termination + for (uint32_t l = (lastDot + 1); l < cur_file_len; ++l) { + cur_ext[l - (lastDot + 1)] = long_fname_buffer[l]; + } + cur_ext[cur_file_len - lastDot - 1] = 0; //Null termination + + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + } + + strlwr(cur_filename); + strlwr(cur_file_name); + if (strcmp(cur_filename, cur_file_name) == 0) { //if the requested file name matches the file name of the current entry + if (*cur_file_ext == 0) { //if cur_file_ext is empty + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + strlwr(cur_ext); + strlwr(cur_file_ext); + if (strcmp(cur_ext, cur_file_ext) == 0) { //if the requested file extension matches the file extension of the current entry + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else continue; + } + + if (k == (path_size - 1)) { //if is final file + return ret; + } + else { + if ((ret[11] & FAT_ATTR_SUBDIR) == FAT_ATTR_SUBDIR) { //Subdirectory + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + free(ret); + return 0; + } + } + + } + } + if (loopBreak) break; + } + if (loopBreak) break; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + } + free(ret); + return 0; +} + +uint32_t FAT_getFilesize(uint8_t* entry) { + if (entry == 0) return 0; + return entry[0x1C] + (uint32_t)(entry[0x1D] << 8) + (uint32_t)(entry[0x1E] << 16) + (uint32_t)(entry[0x1F] << 24); +} + +uint8_t FAT_readFileByte(FAT* inst, uint8_t* entry) { + static uint32_t cur_clust; + static uint32_t j; + static uint16_t i; + static uint8_t* cur_sec_bytes; + if (entry != 0) { + cur_clust = entry[0x1A] + (entry[0x1B] << 8) + (entry[0x14] << 16) + (entry[0x15] << 24); + j = 0; + i = 0; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + } + + if (cur_clust != 0) { + if (i < 512) { + return cur_sec_bytes[i++]; + } + ++j; + i = 1; + if (j < inst->sectorsPerCluster) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + return cur_sec_bytes[0]; + } + + cur_clust = FAT_FATgetCluster(inst, cur_clust); + j = 0; + i = 1; + if (cur_clust != 0) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + return cur_sec_bytes[0]; + } + } + return 0; //No more data (file end) +} + +void FAT_readFileContents(FAT* inst, uint8_t* entry, uint8_t* buffer, uint32_t start, uint32_t len) { + if (len == 0) return; + uint32_t cur_clust = entry[0x1A] + (entry[0x1B] << 8) + (entry[0x14] << 16) + (entry[0x15] << 24); + uint32_t* clustArr = FAT_FATgetClusterChain(inst, cur_clust, start, len); + + // uint8_t cur_sec_bytes[512*inst->sectorsPerCluster]; + // uint32_t pos = (start/(inst->sectorsPerCluster*512))*(inst->sectorsPerCluster*512); + // uint32_t clustArr_index = 1; + // if(clustArr[0] == 0) cur_clust = 0; + // else cur_clust = clustArr[clustArr_index]; + // //uint32_t clustList_index = 1; + // //cur_clust = (uint32_t)listShowElement(clustList, clustList_index); + // + // while(cur_clust != 0){ + // //uint32_t next_cluster = (uint32_t)listShowElement(clustList, clustList_index+1); + // uint32_t next_cluster = clustArr[clustArr_index+1]; + // + // if(( pos >= start ) + // && ( (pos+2*512*inst->sectorsPerCluster-1) <= (start+len) ) + // && (next_cluster == (cur_clust+1)) ){ // if the next cluster comes directly after the current one + // storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries/16 + (cur_clust - 2)*inst->sectorsPerCluster, buffer+pos-start, 2*512*inst->sectorsPerCluster); + // pos += 2*512*inst->sectorsPerCluster; + // //++clustList_index; + // ++clustArr_index; + // //next_cluster = (uint32_t)listShowElement(clustList, clustList_index+1); + // next_cluster = clustArr[clustArr_index+1]; + // } + // else if(( pos >= start ) + // && ( (pos+512*inst->sectorsPerCluster-1) <= (start+len) )){ + // storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries/16 + (cur_clust - 2)*inst->sectorsPerCluster, buffer+pos-start, 512*inst->sectorsPerCluster); + // pos += 512*inst->sectorsPerCluster; + // } + // else { + // storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries/16 + (cur_clust - 2)*inst->sectorsPerCluster, cur_sec_bytes, 512*inst->sectorsPerCluster); + // for(uint16_t i = 0; i < 512*inst->sectorsPerCluster; ++i){ + // if((pos >= start) && (pos < (start+len))){ + // buffer[pos-start] = cur_sec_bytes[i]; + // } + // if(pos >= (start+len)){ + // free(clustArr); + // //listDeleteAllWithoutData(clustList); + // return; + // } + // ++pos; + // } + // } + // + // /*for(uint32_t j = 0; j < inst->sectorsPerCluster; ++j){ + // storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries/16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + // for(uint16_t i = 0; i < 512; ++i){ + // if((pos >= start) && (pos < (start+len))){ + // buffer[pos-start] = cur_sec_bytes[i]; + // } + // if(pos >= (start+len)){ + // listDeleteAllWithoutData(clustList); + // return; + // } + // ++pos; + // } + // }*/ + // //++clustList_index; + // ++clustArr_index; + // cur_clust = next_cluster; + // } + + //uint8_t cur_sec_bytes[512 * inst->sectorsPerCluster]; !!!MEMORY LEAK !!! + uint8_t* cur_sec_bytes = (uint8_t*)malloc(512 * inst->sectorsPerCluster); + uint32_t pos = (start / (inst->sectorsPerCluster * 512))*(inst->sectorsPerCluster * 512); + if (clustArr[0] == 0) cur_clust = 0; + else cur_clust = clustArr[1]; + + for (uint32_t clustArr_index = 1; clustArr_index <= clustArr[0]; ++clustArr_index) { + uint32_t next_cluster = clustArr[clustArr_index + 1]; + + if ((pos >= start) + && ((pos + 2 * 512 * inst->sectorsPerCluster - 1) <= (start + len)) + && (next_cluster == (cur_clust + 1))) { // if the next cluster comes directly after the current one + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster, buffer + pos - start, 2 * 512 * inst->sectorsPerCluster); + pos += 2 * 512 * inst->sectorsPerCluster; + ++clustArr_index; + next_cluster = clustArr[clustArr_index + 1]; + } + else if ((pos >= start) + && ((pos + 512 * inst->sectorsPerCluster - 1) <= (start + len))) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster, buffer + pos - start, 512 * inst->sectorsPerCluster); + pos += 512 * inst->sectorsPerCluster; + } + else { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster, cur_sec_bytes, 512 * inst->sectorsPerCluster); + for (uint16_t i = 0; i < 512 * inst->sectorsPerCluster; ++i) { + if ((pos >= start) && (pos < (start + len))) { + buffer[pos - start] = cur_sec_bytes[i]; + } + if (pos >= (start + len)) { + free(clustArr); + return; + } + ++pos; + } + } + + cur_clust = next_cluster; + } + + free(clustArr); + //listDeleteAllWithoutData(clustList); +} + +char* FAT_longNameToShortName(FAT* inst, char* filepath) { + //Format and split the file path + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < FAT_MAX_PATH_FILES; ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path[k][l] = 0; + } + } + char delimiter[] = "/"; + int path_size = 0; + formatFilePath(filepath); + size_t tmp_filepath_len = strlen(filepath) + 1; + //char tmp_filepath[tmp_filepath_len]; !!! MEMORY LEAK !!! + char* tmp_filepath = (char*)malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + char* cur_file = strtok(tmp_filepath, delimiter); + while (cur_file != 0 && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not to long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + + //Get the file container path + uint16_t path_container_len = 0; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + ++path_container_len; //This line is before the break, because there needs to be space for the '/' and the null termination + if (spl_path[k][l] == 0) break; + } + } + //char path_container[path_container_len]; !!! MEMORY LEAK !!! + char* path_container = (char*)malloc(path_container_len); + memset(path_container, 0, path_container_len); + uint16_t i = 0; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + if (spl_path[k][l] == 0) break; + path_container[i] = spl_path[k][l]; + ++i; + } + if (path_container_len == (i + 1)) break; + path_container[i] = '/'; + ++i; + } + + uint8_t* entry; + + //Get the start cluster of the container + uint32_t start_clust; + uint32_t cur_clust; + if (path_container_len == 0) { + start_clust = inst->startClustOfRootDir; //file is in the root directory + } + else { + entry = FAT_readFileEntry(inst, path_container); + if (entry == 0) return 0; + start_clust = entry[0x1A] + (entry[0x1B] << 8) + (entry[0x14] << 16) + (entry[0x15] << 24); + free(entry); + } + cur_clust = start_clust; + + ///Get the short file name without tilda + char* file_str = spl_path[path_size - 1]; + strupr(file_str); + + //Split the new file into name and extension + size_t file_str_len = strlen(file_str); + int32_t lastDot = strrchr_new(file_str, '.'); + if (lastDot == -1) lastDot = file_str_len; + //char filename[lastDot + 1]; !!!MEMORY LEAK !!! + char* filename = (char*)malloc(lastDot + 1); + for (uint32_t j = 0; j < lastDot; ++j) { + filename[j] = file_str[j]; + } + filename[lastDot] = 0; //Null termination + //char fileext[file_str_len - lastDot]; !!!MEMORY LEAK !!! + char* fileext = (char*)malloc(file_str_len - lastDot); + for (uint32_t j = (lastDot + 1); j < file_str_len; ++j) { + fileext[j - (lastDot + 1)] = file_str[j]; + } + fileext[file_str_len - lastDot] = 0; //Null termination + + static char short_name[11]; + memset(short_name, 0x20, 11); + for (uint8_t k = 0; k < MIN(strlen(filename), 8); ++k) { + short_name[k] = filename[k]; + } + for (uint8_t k = 0; k < MIN(file_str_len - lastDot, 3); ++k) { + short_name[8 + k] = fileext[k]; + } + + uint16_t aftild = 1; + uint8_t loopBreak = 0; + + short_name[6] = '~'; + short_name[7] = '1'; + + if ((inst->fileSys <= FAT16) && (path_container_len == 0)) { //root directory of FAT12 and FAT16 + for (uint16_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + for (i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0) { + loopBreak = 1; + break; + } + if ((cur_sec_bytes[i + 11] == 0x0F) || (cur_sec_bytes[i] == 0xE5)) continue; + char cur_filename[11]; + for (uint8_t k = 0; k < 11; ++k) { + cur_filename[k] = cur_sec_bytes[i + k]; + } + if (strncmp(cur_filename, short_name, 11) == 0) { + //File entry with this name already exists, let's try a different name + ++aftild; + if (aftild < 10) { + short_name[6] = '~'; + short_name[7] = '0' + aftild; + } + else if (aftild < 100) { + short_name[5] = '~'; + short_name[6] = '0' + aftild / 10; + short_name[7] = '0' + (aftild % 10); + } + else if (aftild < 1000) { + short_name[4] = '~'; + short_name[5] = '0' + aftild / 100; + short_name[6] = '0' + (aftild % 100) / 10; + short_name[7] = '0' + (aftild % 10); + } + j = 0; + break; + } + } + if (loopBreak) break; + } + } + else { + while (cur_clust != 0) { + uint8_t loopRepeat = 0; + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + for (i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0) { + loopBreak = 1; + break; + } + if ((cur_sec_bytes[i + 11] == 0x0F) || (cur_sec_bytes[i] == 0xE5)) continue; + char cur_filename[11]; + for (uint8_t k = 0; k < 11; ++k) { + cur_filename[k] = cur_sec_bytes[i + k]; + } + if (strncmp(cur_filename, short_name, 11) == 0) { + //File entry with this name already exists, let's try a different name + ++aftild; + if (aftild < 10) { + short_name[6] = '~'; + short_name[7] = '0' + aftild; + } + else if (aftild < 100) { + short_name[5] = '~'; + short_name[6] = '0' + aftild / 10; + short_name[7] = '0' + (aftild % 10); + } + else if (aftild < 1000) { + short_name[4] = '~'; + short_name[5] = '0' + aftild / 100; + short_name[6] = '0' + (aftild % 100) / 10; + short_name[7] = '0' + (aftild % 10); + } + loopRepeat = 1; + break; + } + } + if (loopBreak || loopRepeat) break; + } + if (loopRepeat) { + cur_clust = start_clust; + continue; + } + if (loopBreak) break; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + + return short_name; //return the short file name +} + +uint8_t* FAT_createFile(FAT* inst, char* filepath, uint8_t attribute) { + uint8_t* entry = FAT_readFileEntry(inst, filepath); + if (entry != 0) return entry; //File already exists + + //Format and split the file path + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < FAT_MAX_PATH_FILES; ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path[k][l] = 0; + } + } + char delimiter[] = "/"; + int path_size = 0; + formatFilePath(filepath); + size_t tmp_filepath_len = strlen(filepath) + 1; + //char tmp_filepath[tmp_filepath_len]; !!!MEMORY LEAK !!! + char* tmp_filepath = (char*)malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + char* cur_file = strtok(tmp_filepath, delimiter); + while (cur_file != 0 && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not to long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + + //Get the file container path + //char spl_path_container[path_size - 1][FAT_MAX_FNAME_LEN]; !!! MEMORY LEAK !!! + char spl_path_container[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path_container[k][l] = spl_path[k][l]; + } + } + + uint32_t cur_clust; + uint32_t prev_clust = 0; + + if (path_size <= 1) { + //Container is the root directory + cur_clust = inst->startClustOfRootDir; // cur_clust is going to be 0 if fileSys is FAT12 or FAT16 + } + else { + //Join spl_path_container together to path_container + uint16_t path_container_len = 0; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + ++path_container_len; //This line is before the break, because there needs to be space for the '/' and the null termination + if (spl_path_container[k][l] == 0) break; + } + } + //char path_container[path_container_len]; !!!MEMORY LEAK !!! + char* path_container = (char*)malloc(path_container_len); + memset(path_container, 0, path_container_len); + uint16_t i = 0; + for (uint32_t k = 0; k < (path_size - 1); ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + if (spl_path_container[k][l] == 0) break; + path_container[i] = spl_path_container[k][l]; + ++i; + } + if (path_container_len == (i + 1)) break; + path_container[i] = '/'; + ++i; + } + + //Read file entry of the container + entry = FAT_readFileEntry(inst, path_container); + if (entry == 0) return 0; + cur_clust = entry[0x1A] + (entry[0x1B] << 8) + (entry[0x14] << 16) + (entry[0x15] << 24); + free(entry); + } + + + char* new_file_str = spl_path[path_size - 1]; + + //Split the new file into name and extension + int32_t cur_file_len = strlen(new_file_str); + int32_t lastDot = strrchr_new(new_file_str, '.'); + if (lastDot == -1) lastDot = cur_file_len; + //char new_filename[lastDot + 1]; !!!MEMORY LEAK !!! + char* new_filename = (char*)malloc(lastDot + 1); + for (uint32_t j = 0; j < lastDot; ++j) { + new_filename[j] = new_file_str[j]; + } + new_filename[lastDot] = 0; //Null termination + //char new_fileext[cur_file_len - lastDot]; //TODO: I think there has be a +1 !!! MEMORY LEAK !!! + char* new_fileext = (char*)malloc(cur_file_len - lastDot); + for (uint32_t j = (lastDot + 1); j < cur_file_len; ++j) { + new_fileext[j - (lastDot + 1)] = new_file_str[j]; + } + new_fileext[MAX(cur_file_len - lastDot - 1, 0)] = 0; //Null termination + + uint8_t is_long_fname = 0; + char* new_filenameext; + uint8_t long_fname_entry_count = 0; + uint8_t long_fname_entry_index = 0; + uint8_t* long_fname_entry_buffer = 0; + entry = (uint8_t*) malloc(32);//entry = (uint8_t [32]){0}; + if ((strlen(new_filename) > 8) || (strlen(new_fileext) > 3)) { //if long filename + is_long_fname = 1; + if (strlen(new_fileext) == 0) { + new_filenameext = new_filename; + } + else { + new_filenameext = new_file_str; + } + for (uint8_t l = 0; l < (strlen(new_filenameext) + 13); l += 13) { + ++long_fname_entry_count; + } + + long_fname_entry_buffer = (uint8_t*) malloc(long_fname_entry_count * 32); + + char* new_fname_short = FAT_longNameToShortName(inst, filepath); //get the short name + + for (uint8_t l = 0; l < strlen(new_filenameext); l += 13) { + entry[0] = ((l + 13) < strlen(new_filenameext)) ? ((uint8_t)(l / 13 + 1)) : ((uint8_t)(0x41 + l / 13)); + uint8_t i; + for (i = 1; i < 11; ++i) { + entry[i] = 0xFF; + } + entry[11] = 0x0F; //attribute + entry[12] = 0x00; + entry[13] = BSDChecksum(new_fname_short); + for (i = 14; i < 26; ++i) { + entry[i] = 0xFF; + } + entry[26] = 0x00; + entry[27] = 0x00; + entry[28] = 0xFF; + entry[29] = 0xFF; + entry[30] = 0xFF; + entry[31] = 0xFF; + + for (uint8_t k = 0; k < MIN(strlen(new_filenameext) + 1 - l, 13); ++k) { + if (k < 5) { + entry[1 + k * 2] = new_filenameext[l + k]; + entry[1 + k * 2 + 1] = 0x00; + } + else if (k < 11) { + entry[4 + k * 2] = new_filenameext[l + k]; + entry[4 + k * 2 + 1] = 0x00; + } + else if (k < 13) { + entry[6 + k * 2] = new_filenameext[l + k]; + entry[6 + k * 2 + 1] = 0x00; + } + } + + for (i = 0; i < 32; ++i) { + long_fname_entry_buffer[(long_fname_entry_count - 2) * 32 - (l / 13) * 32 + i] = entry[i]; + } + } + + //Short file entry + for (uint8_t k = 0; k < 11; ++k) { + entry[k] = new_fname_short[k]; + } + entry[11] = attribute; + entry[12] = 0x00; + entry[13] = 0x00; //TODO: Time and date values + entry[14] = 0x00; + entry[15] = 0x00; + entry[0x10] = 0x00; + entry[0x11] = 0x00; + entry[0x12] = 0x00; + entry[0x13] = 0x00; + entry[0x16] = 0x00; + entry[0x17] = 0x00; + entry[0x18] = 0x00; + entry[0x19] = 0x00; + entry[0x1C] = 0x00; //Filesize + entry[0x1D] = 0x00; + entry[0x1E] = 0x00; + entry[0x1F] = 0x00; + entry[0x14] = 0x00; //First cluster + entry[0x15] = 0x00; + entry[0x1A] = 0x00; + entry[0x1B] = 0x00; + + for (uint8_t i = 0; i < 32; ++i) { + long_fname_entry_buffer[long_fname_entry_count * 32 - 32 + i] = entry[i]; + } + } + + + uint8_t cur_sec_bytes[512]; + + if ((inst->fileSys <= FAT16) && (path_size == 1)) { //root directory of FAT12 and FAT16 + for (uint16_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + for (uint16_t i = 0; i < 512; i += 32) { + + if ((cur_sec_bytes[i] == 0x00) || (cur_sec_bytes[i] == 0xE5)) { + if (is_long_fname) { + for (uint16_t l = i; l < 512; l += 32) { + for (uint8_t k = 0; k < 32; ++k) { + cur_sec_bytes[l + k] = long_fname_entry_buffer[long_fname_entry_index * 32 + k]; + } + ++long_fname_entry_index; + if (long_fname_entry_index == long_fname_entry_count) break; //Everything has been written + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + j, cur_sec_bytes, 512); + + if (long_fname_entry_index == long_fname_entry_count) { + //Everything has been written + free(long_fname_entry_buffer); + return entry; + } + } + else { + uint16_t k; + for (k = 0; k < MIN(/*new_filename.Length*/lastDot, 8); ++k) { + entry[k] = new_filename[k]; + } + //Fill in the spaces for the file name + for (; k < 8; ++k) { + entry[k] = 0x20; + } + for (k = 0; k < MIN(/*new_fileext.Length*/cur_file_len - lastDot, 3); ++k) { + entry[8 + k] = new_fileext[k]; + } + //Fill in the spaces for the file extension + for (; k < 3; ++k) { + entry[8 + k] = 0x20; + } + + entry[11] = attribute; + entry[12] = 0x00; + entry[13] = 0x00; //TODO: Time and date values + entry[14] = 0x00; + entry[15] = 0x00; + entry[0x10] = 0x00; + entry[0x11] = 0x00; + entry[0x12] = 0x00; + entry[0x13] = 0x00; + entry[0x16] = 0x00; + entry[0x17] = 0x00; + entry[0x18] = 0x00; + entry[0x19] = 0x00; + entry[0x1C] = 0x00; //Filesize + entry[0x1D] = 0x00; + entry[0x1E] = 0x00; + entry[0x1F] = 0x00; + entry[0x14] = 0x00; //First cluster + entry[0x15] = 0x00; + entry[0x1A] = 0x00; + entry[0x1B] = 0x00; + + for (k = 0; k < 32; ++k) { + cur_sec_bytes[i + k] = entry[k]; + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + j, cur_sec_bytes, 512); + return entry; + } + } + } + } + } + else { + + while (cur_clust != 0) { + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + for (uint16_t i = 0; i < 512; i += 32) { + + if ((cur_sec_bytes[i] == 0x00) || (cur_sec_bytes[i] == 0xE5)) { + if (is_long_fname) { + for (uint16_t l = i; l < 512; l += 32) { + for (uint8_t k = 0; k < 32; ++k) { + cur_sec_bytes[l + k] = long_fname_entry_buffer[long_fname_entry_index * 32 + k]; + } + ++long_fname_entry_index; + if (long_fname_entry_index == long_fname_entry_count) break; //Everything has been written + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2) * inst->sectorsPerCluster + j, cur_sec_bytes, 512); + + if (long_fname_entry_index == long_fname_entry_count) { + //Everything has been written + free(long_fname_entry_buffer); + return entry; + } + } + else { + uint16_t k; + for (k = 0; k < MIN(/*new_filename.Length*/lastDot, 8); ++k) { + entry[k] = new_filename[k]; + } + //Fill in the spaces for the file name + for (; k < 8; ++k) { + entry[k] = 0x20; + } + for (k = 0; k < MIN(/*new_fileext.Length*/cur_file_len - lastDot, 3); ++k) { + entry[8 + k] = new_fileext[k]; + } + //Fill in the spaces for the file extension + for (; k < 3; ++k) { + entry[8 + k] = 0x20; + } + + entry[11] = attribute; + entry[12] = 0x00; + entry[13] = 0x00; //TODO: Time and date values + entry[14] = 0x00; + entry[15] = 0x00; + entry[0x10] = 0x00; + entry[0x11] = 0x00; + entry[0x12] = 0x00; + entry[0x13] = 0x00; + entry[0x16] = 0x00; + entry[0x17] = 0x00; + entry[0x18] = 0x00; + entry[0x19] = 0x00; + entry[0x1C] = 0x00; //Filesize + entry[0x1D] = 0x00; + entry[0x1E] = 0x00; + entry[0x1F] = 0x00; + entry[0x14] = 0x00; //First cluster + entry[0x15] = 0x00; + entry[0x1A] = 0x00; + entry[0x1B] = 0x00; + + for (k = 0; k < 32; ++k) { + cur_sec_bytes[i + k] = entry[k]; + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2) * inst->sectorsPerCluster + j, cur_sec_bytes, 512); + return entry; + } + } + } + } + prev_clust = cur_clust; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + //create a new cluster of directory if previous one is full + if (cur_clust == 0) { + cur_clust = FAT_FATfindFreeCluster(inst); + if (cur_clust == 0) { + if (is_long_fname) free(long_fname_entry_buffer); + return 0; //return NULL if there is no free cluster + } + FAT_FATsetCluster(inst, prev_clust, cur_clust); + FAT_FATsetCluster(inst, cur_clust, (inst->fileSys == FAT12) ? 0x0FF8 : ((inst->fileSys == FAT16) ? 0xFFF8 : 0x0FFFFFF8)); + } + } + + } + + if (is_long_fname) free(long_fname_entry_buffer); + return 0; +} + +void FAT_setVolumeLabel(FAT* inst, char* volumeLabel) { + stringReplace("/", " ", volumeLabel); + stringReplace("\\", " ", volumeLabel); + + if (inst->fileSys <= FAT16) { + for (uint32_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i + 11] == FAT_ATTR_VOLLABEL) { + //Entry is a volume label + uint8_t k; + for (k = 0; k < 11; ++k) { + if (volumeLabel[k] == 0) break; + cur_sec_bytes[i + k] = volumeLabel[k]; + } + for (; k < 11; ++k) { + cur_sec_bytes[i + k] = 0x20; + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + j, cur_sec_bytes, 512); + return; + } + } + } + } + else { + uint32_t cur_clust = inst->startClustOfRootDir; + + while (cur_clust != 0) { + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i + 11] == FAT_ATTR_VOLLABEL) { + //Entry is a volume label + uint8_t k; + for (k = 0; k < 11; ++k) { + if (volumeLabel[k] == 0) break; + cur_sec_bytes[i + k] = volumeLabel[k]; + } + for (; k < 11; ++k) { + cur_sec_bytes[i + k] = 0x20; + } + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + (cur_clust - 2) * inst->sectorsPerCluster + j, cur_sec_bytes, 512); + return; + } + } + } + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + + //If there is no Volume Label, create one + char temp_volumeLabel[13]; + uint8_t k; + for (k = 0; k < 13; ++k) { + temp_volumeLabel[k] = 0; + } + uint8_t volLabel_len = strlen(volumeLabel); + for (k = 0; k < MIN(volLabel_len, 8); ++k) { + temp_volumeLabel[k] = volumeLabel[k]; + } + if (volLabel_len >= 9) temp_volumeLabel[8] = '.'; + for (k = 8; k < MIN(volLabel_len, 11); ++k) { + temp_volumeLabel[k + 1] = volumeLabel[k]; + } + free(FAT_createFile(inst, temp_volumeLabel, FAT_ATTR_VOLLABEL)); +} + +uint8_t FAT_readFileEntryByIndex(FAT* inst, file_t* file_inst, char* filepath, uint32_t index) { + uint8_t ret[32]; + //Format and split the file path + char spl_path[FAT_MAX_PATH_FILES][FAT_MAX_FNAME_LEN]; + for (uint32_t k = 0; k < FAT_MAX_PATH_FILES; ++k) { + for (uint32_t l = 0; l < FAT_MAX_FNAME_LEN; ++l) { + spl_path[k][l] = 0; + } + } + char delimiter[] = "/"; + int path_size = 0; + formatFilePath(filepath); + size_t tmp_filepath_len = strlen(filepath) + 1; + //char tmp_filepath[tmp_filepath_len]; !!!MEMORY LEAK !!! + char* tmp_filepath = (char*)malloc(tmp_filepath_len); + memset(tmp_filepath, 0, tmp_filepath_len); + strcpy(tmp_filepath, filepath); + char* cur_file = strtok(tmp_filepath, delimiter); + while (cur_file != 0 && path_size < FAT_MAX_PATH_FILES) { + if (strlen(cur_file) > FAT_MAX_FNAME_LEN - 1) break; //make sure current filename is not too long + strcpy(spl_path[path_size], cur_file); + cur_file = strtok(0, delimiter); + ++path_size; + } + + uint32_t cur_clust = inst->startClustOfRootDir; + + for (uint32_t k = 0; k < path_size + 1; ++k) { + int32_t cur_file_len = 0; + int32_t lastDot = 0; + if (k < path_size) { + //Split the current file into name and extension + cur_file_len = strlen(spl_path[k]); + lastDot = strrchr_new(spl_path[k], '.'); + if (lastDot == -1) lastDot = cur_file_len; + } + //char cur_file_name[lastDot + 1]; !!!MEMORY LEAK !!! + char* cur_file_name = (char*)malloc(lastDot + 1); + //char cur_file_ext[cur_file_len - lastDot]; !!!MEMORY LEAK !!! + char* cur_file_ext = (char*)malloc(cur_file_len - lastDot); + if (k < path_size) { + for (uint32_t j = 0; j < lastDot; ++j) { + cur_file_name[j] = spl_path[k][j]; + } + cur_file_name[lastDot] = 0; //Null termination + + for (uint32_t j = (lastDot + 1); j < cur_file_len; ++j) { + cur_file_ext[j - (lastDot + 1)] = spl_path[k][j]; + } + cur_file_ext[MAX(cur_file_len - lastDot - 1, 0)] = 0; //Null termination + } + + char long_fname_buffer[208]; + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + + if ((inst->fileSys <= FAT16) && k == 0) { //root directory of FAT12 and FAT16 + uint32_t cur_index = 0; + uint8_t loopBreak = 0; + for (uint16_t j = 0; j < inst->maxRootDirEntries / 16; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + j, cur_sec_bytes, 512); + + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0x00) { + return 0; //Free from here on + } + if (cur_sec_bytes[i] == 0xE5) continue; //File was deleted + + if (cur_sec_bytes[i + 11] == 0x0F) { //Part of long filename + uint8_t cur_long_fname_temp[] = { cur_sec_bytes[i + 1], cur_sec_bytes[i + 3], cur_sec_bytes[i + 5], cur_sec_bytes[i + 7], cur_sec_bytes[i + 9], + cur_sec_bytes[i + 14], cur_sec_bytes[i + 16], cur_sec_bytes[i + 18], cur_sec_bytes[i + 20], cur_sec_bytes[i + 22], cur_sec_bytes[i + 24], + cur_sec_bytes[i + 28], cur_sec_bytes[i + 30] }; + for (uint8_t l = 0; l < /*Length of cur_long_fname_temp*/13; ++l) { + if ((/*if last long file name entry*/(cur_sec_bytes[i] & 0xF0) == 0x40) && (cur_long_fname_temp[l] == 0)) break; + long_fname_buffer[((cur_sec_bytes[i] & 0x0F) - 1) * 13 + l] = (char)cur_long_fname_temp[l]; + } + continue; + } + + char cur_filename[FAT_MAX_FNAME_LEN]; + char cur_ext[FAT_MAX_FNAME_LEN]; + + if (long_fname_buffer[0] == 0) { //if file name is short + for (uint8_t l = 0; l < 8; ++l) { + cur_filename[l] = (char)cur_sec_bytes[i + l]; + } + cur_filename[8] = 0; //Null termination + strtrimend(cur_filename); + for (uint8_t l = 0; l < 3; ++l) { + cur_ext[l] = (char)cur_sec_bytes[i + 8 + l]; + } + cur_ext[3] = 0; //Null termination + strtrimend(cur_ext); + } + else { //if file name is long + //Split the current file into name and extension + cur_file_len = strlen(long_fname_buffer); + lastDot = strrchr_new(long_fname_buffer, '.'); + if (lastDot == -1) lastDot = cur_file_len; + cur_filename[1] = 0; //Null termination if lastDot = 0 + for (uint32_t l = 0; l < lastDot; ++l) { + cur_filename[l] = long_fname_buffer[l]; + } + cur_filename[lastDot] = 0; //Null termination + for (uint32_t l = (lastDot + 1); l < cur_file_len; ++l) { + cur_ext[l - (lastDot + 1)] = long_fname_buffer[l]; + } + cur_ext[cur_file_len - lastDot - 1] = 0; //Null termination + + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + } + + if (k == path_size) { + if (cur_index != index) { + ++cur_index; + continue; + } + file_inst->size = cur_sec_bytes[i + 0x1C] + (cur_sec_bytes[i + 0x1D] << 8) + (cur_sec_bytes[i + 0x1E] << 16) + (cur_sec_bytes[i + 0x1F] << 24); + memset(file_inst->name, 0, 35); + strcpy(file_inst->name, cur_filename); + if (cur_ext[0] != 0) { + strcat(file_inst->name, "."); + strcat(file_inst->name, cur_ext); + } + file_inst->attribute = cur_sec_bytes[i + 11]; + return 1; + } + else { + strlwr(cur_filename); + strlwr(cur_file_name); + if (strcmp(cur_filename, cur_file_name) == 0) { //if the requested file name matches the file name of the current entry + if (*cur_file_ext == 0) { //if cur_file_ext is empty + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + strlwr(cur_ext); + strlwr(cur_file_ext); + if (strcmp(cur_ext, cur_file_ext) == 0) { //if the requested file extension matches the file extension of the current entry + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else continue; + } + + if (k == (path_size - 1)) { //if is final file + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + if ((ret[11] & FAT_ATTR_SUBDIR) == FAT_ATTR_SUBDIR) { //Subdirectory + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + return 0; + } + } + + } + } + } + if (loopBreak) break; + } + + } + else { + uint32_t cur_index = 0; + while (cur_clust != 0) { + uint8_t loopBreak = 0; + for (uint32_t j = 0; j < inst->sectorsPerCluster; ++j) { + //Read current sector + uint8_t cur_sec_bytes[512]; + storage_readSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16 + (cur_clust - 2)*inst->sectorsPerCluster + j, cur_sec_bytes, 512); + + for (uint32_t i = 0; i < 512; i += 32) { + if (cur_sec_bytes[i] == 0x00) { + return 0; //Free from here on + } + if (cur_sec_bytes[i] == 0xE5) continue; //File was deleted + + if (cur_sec_bytes[i + 11] == 0x0F) { //Part of long filename + uint8_t cur_long_fname_temp[] = { cur_sec_bytes[i + 1], cur_sec_bytes[i + 3], cur_sec_bytes[i + 5], cur_sec_bytes[i + 7], cur_sec_bytes[i + 9], + cur_sec_bytes[i + 14], cur_sec_bytes[i + 16], cur_sec_bytes[i + 18], cur_sec_bytes[i + 20], cur_sec_bytes[i + 22], cur_sec_bytes[i + 24], + cur_sec_bytes[i + 28], cur_sec_bytes[i + 30] }; + for (uint8_t l = 0; l < /*Length of cur_long_fname_temp*/13; ++l) { + if ((/*if last long file name entry*/(cur_sec_bytes[i] & 0xF0) == 0x40) && (cur_long_fname_temp[l] == 0)) break; + long_fname_buffer[((cur_sec_bytes[i] & 0x0F) - 1) * 13 + l] = (char)cur_long_fname_temp[l]; + } + continue; + } + + char cur_filename[FAT_MAX_FNAME_LEN]; + char cur_ext[FAT_MAX_FNAME_LEN] = { 0 }; + + if (long_fname_buffer[0] == 0) { //if file name is short + for (uint8_t l = 0; l < 8; ++l) { + cur_filename[l] = (char)cur_sec_bytes[i + l]; + } + cur_filename[8] = 0; //Null termination + strtrimend(cur_filename); + for (uint8_t l = 0; l < 3; ++l) { + cur_ext[l] = (char)cur_sec_bytes[i + 8 + l]; + } + cur_ext[3] = 0; //Null termination + strtrimend(cur_ext); + } + else { //if file name is long + //Split the current file into name and extension + cur_file_len = strlen(long_fname_buffer); + lastDot = strrchr_new(long_fname_buffer, '.'); + if (lastDot == -1) lastDot = cur_file_len; + cur_filename[1] = 0; //Null termination if lastDot = 0 + for (uint32_t l = 0; l < lastDot; ++l) { + cur_filename[l] = long_fname_buffer[l]; + } + cur_filename[lastDot] = 0; //Null termination + for (uint32_t l = (lastDot + 1); l < cur_file_len; ++l) { + cur_ext[l - (lastDot + 1)] = long_fname_buffer[l]; + } + cur_ext[cur_file_len - lastDot - 1] = 0; //Null termination + + //Clear long_fname_buffer + for (uint8_t l = 0; l < 208; ++l) { + long_fname_buffer[l] = 0; + } + } + + if (k == path_size) { + if (cur_index != index) { + ++cur_index; + continue; + } + file_inst->size = cur_sec_bytes[i + 0x1C] + (cur_sec_bytes[i + 0x1D] << 8) + (cur_sec_bytes[i + 0x1E] << 16) + (cur_sec_bytes[i + 0x1F] << 24); + memset(file_inst->name, 0, 35); + strcpy(file_inst->name, cur_filename); + if (cur_ext[0] != 0) { + strcat(file_inst->name, "."); + strcat(file_inst->name, cur_ext); + } + file_inst->attribute = cur_sec_bytes[i + 11]; + return 1; + } + else { + strlwr(cur_filename); + strlwr(cur_file_name); + if (strcmp(cur_filename, cur_file_name) == 0) { //if the requested file name matches the file name of the current entry + if (*cur_file_ext == 0) { //if cur_file_ext is empty + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else { + strlwr(cur_ext); + strlwr(cur_file_ext); + if (strcmp(cur_ext, cur_file_ext) == 0) { //if the requested file extension matches the file extension of the current entry + //Copy the current file entry to ret + for (uint8_t l = 0; l < 32; ++l) { + ret[l] = cur_sec_bytes[i + l]; + } + } + else continue; + } + + if (k == (path_size - 1)) { //if is final file + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + if ((ret[11] & FAT_ATTR_SUBDIR) == FAT_ATTR_SUBDIR) { //Subdirectory + cur_clust = ret[0x1A] + (ret[0x1B] << 8) + (ret[0x14] << 16) + (ret[0x15] << 24); + loopBreak = 1; + break; + } + else { + return 0; + } + } + + } + } + } + if (loopBreak) break; + } + if (loopBreak) break; + cur_clust = FAT_FATgetCluster(inst, cur_clust); + } + } + } + return 0; +} + +uint8_t FAT_format(FAT* inst, uint8_t fileSys, char* volumeLabel, uint16_t reservedSectors, uint8_t quick) { + switch (fileSys) { + case FAT12: + { + if (inst->lbaLength <= 4096) inst->sectorsPerCluster = 1; //0 Bytes - 2 MB + else if (inst->lbaLength <= 8192) inst->sectorsPerCluster = 2; //2 MB - 4 MB + else if (inst->lbaLength <= 16384) inst->sectorsPerCluster = 4; //4 MB - 8 MB + else if (inst->lbaLength <= 32768) inst->sectorsPerCluster = 8; //8 MB - 16 MB + else if (inst->lbaLength <= 65536) inst->sectorsPerCluster = 16; //16 MB - 32 MB + else if (inst->lbaLength <= 131072) inst->sectorsPerCluster = 32; //32 MB - 64 MB + else if (inst->lbaLength <= 262144) inst->sectorsPerCluster = 64; //64 MB - 128 MB + else inst->sectorsPerCluster = 128; //128 MB - 256 MB + inst->FATCopies = 2; + inst->maxRootDirEntries = 224; + inst->sectorsPerFAT = (uint32_t)((inst->lbaLength - reservedSectors - inst->maxRootDirEntries / 16) / ((512 / 1.5) * inst->sectorsPerCluster + 2) + 0.998 /*Makes it round up*/); + if ((reservedSectors == 0) || ((reservedSectors + inst->sectorsPerFAT*inst->FATCopies) > inst->lbaLength)) return false; //Not enough space in this partition + inst->reservedSectors = reservedSectors; + inst->startClustOfRootDir = 0; // unused in FAT12 + + //Bios Parameter Block + uint8_t cur_sec[] = { 0xEB, 0x58, 0x90, 0x43, 0x68, 0x61, 0x4F, 0x53, 0x31, 0x2E, 0x30, 0x00, 0x02, inst->sectorsPerCluster, (uint8_t)reservedSectors, (uint8_t)(reservedSectors >> 8), + inst->FATCopies, (uint8_t)inst->maxRootDirEntries, (uint8_t)(inst->maxRootDirEntries >> 8), 0x00, 0x00, 0xF8, (uint8_t)inst->sectorsPerFAT, (uint8_t)(inst->sectorsPerFAT >> 8), 0x3F, 0x00, 0x10, 0x00, (uint8_t)inst->lbaStart, (uint8_t)(inst->lbaStart >> 8), (uint8_t)(inst->lbaStart >> 16), (uint8_t)(inst->lbaStart >> 24), + (uint8_t)inst->lbaLength, (uint8_t)(inst->lbaLength >> 8), (uint8_t)(inst->lbaLength >> 16), (uint8_t)(inst->lbaLength >> 24), 0x00, 0x00, 0x29, /*(uint8_t)random.Next(0xFF), (uint8_t)random.Next(0xFF), (uint8_t)random.Next(0xFF), (uint8_t)random.Next(0xFF)*/0x12, 0x34, 0x56, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 'F', 'A', 'T', '1', '2', 0x20, 0x20, 0x20, /*Boot code start*/0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*Boot code end*/, 0x55, 0xAA }; + + storage_writeSector(inst->storageDev, inst->lbaStart, cur_sec, 512); + + //Clear FAT and root directory + memset(cur_sec, 0, 512); + for (uint32_t j = 0; j < (inst->sectorsPerFAT*inst->FATCopies + inst->maxRootDirEntries / 16); ++j) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + j, cur_sec, 512); + } + + //Write first two clusters into FAT + FAT_FATsetCluster(inst, 0, 0xFF8); + FAT_FATsetCluster(inst, 1, 0xFFF); + + //Volume label + if (strlen(volumeLabel) != 0) { + FAT_setVolumeLabel(inst, volumeLabel); + } + + //If not quick then clear all clusters + if (!quick) { + uint8_t nul_secs[512 * 16] = { 0 }; + uint32_t cur_time = clock(); + uint32_t prev_time; + uint32_t last_i_measure = 0; + for (uint32_t i = inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + inst->maxRootDirEntries / 16; i < inst->lbaLength; ++i) { + if ((i + 16) < inst->lbaLength) { + storage_writeSector(inst->storageDev, i, nul_secs, 512 * 16); + i += 15; + } + else { + storage_writeSector(inst->storageDev, i, cur_sec, 512); + } + if ((i % 128) == 0) { + if (clock() > (cur_time + 1000)) { + prev_time = cur_time; + cur_time = clock(); + //if((cur_time-prev_time) != 0){ + printf("%d KByte/s \r", (((i - last_i_measure) * 512) / (cur_time - prev_time))); + last_i_measure = i; + //} + } + } + } + putchar('\n'); + } + + return 1; + } + case FAT16: + return 1; //TODO: Formating for FAT16 + default: + { + if (inst->lbaLength <= 524288) inst->sectorsPerCluster = 1; //0 Bytes - 256 MB + else if (inst->lbaLength <= 1048576) inst->sectorsPerCluster = 2; //256 MB - 512 MB + else if (inst->lbaLength <= 2097152) inst->sectorsPerCluster = 4; //512 MB - 1 GB + else if (inst->lbaLength <= 16777216) inst->sectorsPerCluster = 8; //1 GB - 8 GB + else if (inst->lbaLength <= 33554432) inst->sectorsPerCluster = 16; //8 GB - 16 GB + else if (inst->lbaLength <= 67108864) inst->sectorsPerCluster = 32; //16 GB - 32 GB + else if (inst->lbaLength <= 4294967296) inst->sectorsPerCluster = 64; //32 GB - 2 TB + else inst->sectorsPerCluster = 128; //1 TB - 16 TB + inst->FATCopies = 2; + inst->sectorsPerFAT = (uint32_t)((inst->lbaLength - reservedSectors) / (128 * inst->sectorsPerCluster + 2) + 0.993 /*Makes it round up*/); + if ((reservedSectors < 9) || ((reservedSectors + inst->sectorsPerFAT*inst->FATCopies) > inst->lbaLength)) return false; //Not enough space in this partition + inst->reservedSectors = reservedSectors; + inst->startClustOfRootDir = 2; + + //Bios Parameter Block + uint8_t cur_sec[] = { 0xEB, 0x58, 0x90, 0x43, 0x68, 0x61, 0x4F, 0x53, 0x31, 0x2E, 0x30, 0x00, 0x02, inst->sectorsPerCluster, (uint8_t)reservedSectors, (uint8_t)(reservedSectors >> 8), + inst->FATCopies, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3F, 0x00, 0x10, 0x00, (uint8_t)inst->lbaStart, (uint8_t)(inst->lbaStart >> 8), (uint8_t)(inst->lbaStart >> 16), (uint8_t)(inst->lbaStart >> 24), + (uint8_t)inst->lbaLength, (uint8_t)(inst->lbaLength >> 8), (uint8_t)(inst->lbaLength >> 16), (uint8_t)(inst->lbaLength >> 24), (uint8_t)inst->sectorsPerFAT, (uint8_t)(inst->sectorsPerFAT >> 8), (uint8_t)(inst->sectorsPerFAT >> 16), (uint8_t)(inst->sectorsPerFAT >> 24), 0x00, 0x00, 0x00, 0x00, (uint8_t)inst->startClustOfRootDir, (uint8_t)(inst->startClustOfRootDir >> 8), (uint8_t)(inst->startClustOfRootDir >> 16), (uint8_t)(inst->startClustOfRootDir >> 24), + /*FSInfo sector*/0x01, 0x00/**/, /*Backup boot sector*/0x06, 0x00/**/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x29, /*(uint8_t)random.Next(0xFF), (uint8_t)random.Next(0xFF), (uint8_t)random.Next(0xFF), (uint8_t)random.Next(0xFF)*/0x12, 0x34, 0x56, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20, /*Boot code start*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*Boot code end*/, 0x55, 0xAA }; + + storage_writeSector(inst->storageDev, inst->lbaStart, cur_sec, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + 6, cur_sec, 512); + + //FSInfo sector + cur_sec[0] = 0x52; + cur_sec[1] = 0x52; + cur_sec[2] = 0x61; + cur_sec[3] = 0x41; + uint16_t i; + for (i = 4; i < 484; ++i) + { + cur_sec[i] = 0; + } + cur_sec[0x1E4] = 0x72; + cur_sec[0x1E5] = 0x72; + cur_sec[0x1E6] = 0x41; + cur_sec[0x1E7] = 0x61; + //Number of free clusters + cur_sec[0x1E8] = 0xFF; + cur_sec[0x1E9] = 0xFF; + cur_sec[0x1EA] = 0xFF; + cur_sec[0x1EB] = 0xFF; + //The most recent free cluster + cur_sec[0x1EC] = 0xFF; + cur_sec[0x1ED] = 0xFF; + cur_sec[0x1EE] = 0xFF; + cur_sec[0x1EF] = 0xFF; + for (i = 0x1F0; i < 0x1FE; ++i) + { + cur_sec[i] = 0; + } + //FSInfo sector signature + cur_sec[0x1FE] = 0x55; + cur_sec[0x1FF] = 0xAA; + + storage_writeSector(inst->storageDev, inst->lbaStart + 1, cur_sec, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + 7, cur_sec, 512); + + for (i = 0; i < 0x1FE; ++i) + { + cur_sec[i] = 0; + } + storage_writeSector(inst->storageDev, inst->lbaStart + 2, cur_sec, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + 8, cur_sec, 512); + + cur_sec[0x1FE] = 0; + cur_sec[0x1FF] = 0; + + storage_writeSector(inst->storageDev, inst->lbaStart + 3, cur_sec, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + 4, cur_sec, 512); + storage_writeSector(inst->storageDev, inst->lbaStart + 5, cur_sec, 512); + for (i = 9; i < inst->reservedSectors; ++i) + { + storage_writeSector(inst->storageDev, inst->lbaStart + i, cur_sec, 512); + } + + //Clear FAT + for (uint32_t j = 0; j < inst->sectorsPerFAT*inst->FATCopies; ++j) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + j, cur_sec, 512); + } + + //Write first two clusters into FAT + FAT_FATsetCluster(inst, 0, 0x0FFFFFF8); + FAT_FATsetCluster(inst, 1, 0x0FFFFFFF); + + //Write first root directory cluster into FAT + FAT_FATsetCluster(inst, inst->startClustOfRootDir, 0x0FFFFFFF); + + //Clear first root directory cluster + for (uint8_t j = 0; j < inst->sectorsPerCluster; ++j) { + storage_writeSector(inst->storageDev, inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT*inst->FATCopies + (inst->startClustOfRootDir - 2) * inst->sectorsPerCluster + j, cur_sec, 512); + } + + //Volume label + if (strlen(volumeLabel) != 0) { + FAT_setVolumeLabel(inst, volumeLabel); + } + + //If not quick then clear all clusters + if (!quick) { + uint32_t cur_time = clock(); + uint32_t prev_time; + uint32_t last_i_measure = 0; + for (uint32_t i = inst->lbaStart + inst->reservedSectors + inst->sectorsPerFAT * inst->FATCopies + (inst->startClustOfRootDir - 1) * inst->sectorsPerCluster; i < inst->lbaLength; ++i) { + storage_writeSector(inst->storageDev, i, cur_sec, 512); + /*if((i % 1024) == 0){ + uint32_t prev_time = cur_time; + cur_time = timer_getMilliseconds(); + if((cur_time-prev_time) != 0){ + printf("%d KByte/s ",(512000/(cur_time-prev_time))); + move_cursor_home(); + } + }*/ + if ((i % 128) == 0) { + if (clock() > (cur_time + 1000)) { + prev_time = cur_time; + cur_time = clock(); + //if((cur_time-prev_time) != 0){ + printf("%d KByte/s \r", (((i - last_i_measure) * 512) / (cur_time - prev_time))); + last_i_measure = i; + //} + } + } + } + putchar('\n'); + } + + return 1; + } + } +} + +uint8_t FAT_abstract_createFile(FAT* inst, char* filepath, file_t* file_inst) { + uint8_t* entry = FAT_createFile(inst, filepath, FAT_ATTR_ARCHIVE); + file_inst->size = 0; + if (entry == 0) { + memset(file_inst->data, 0, 32); + file_inst->attribute = 0; + return 0; // Operation failed + } + memcpy(file_inst->data, entry, 32); + file_inst->attribute = entry[0x11]; + free(entry); + return 1; // Operation succeeded +} + +uint8_t FAT_abstract_findFile(FAT* inst, char* filepath, file_t* file_inst) { + uint8_t* entry = FAT_readFileEntry(inst, filepath); + if (entry == 0) { + memset(file_inst->data, 0, 32); + file_inst->size = 0; + file_inst->attribute = 0; + return 0; // Operation failed + } + memcpy(file_inst->data, entry, 32); + file_inst->size = FAT_getFilesize(entry); + file_inst->attribute = entry[0x11]; + return 1; // Operation succeeded +} + +void FAT_abstract_readFileContents(FAT* inst, file_t* file_inst, uint8_t* buffer, uint32_t start, uint32_t len) { + FAT_readFileContents(inst, file_inst->data, buffer, start, len); +} + +uint8_t FAT_abstract_isDirectory(FAT* inst, char* filepath) { + if (filepath[0] == 0) return 1; // Root directory + uint8_t* entry = FAT_readFileEntry(inst, filepath); + if (entry == 0) return 0; + if (entry[11] & FAT_ATTR_SUBDIR) return 1; + return 0; +} + +uint8_t FAT_abstract_createDirectory(FAT* inst, char* filepath) { + return FAT_createDirectory(inst, filepath); +} diff --git a/tools/src/imgtools/src/fat.h b/tools/src/imgtools/src/fat.h new file mode 100755 index 0000000..ea765f4 --- /dev/null +++ b/tools/src/imgtools/src/fat.h @@ -0,0 +1,53 @@ +#ifndef FAT_H +#define FAT_H + +#include +#include "storage_devManager.h" +#include "fileManager.h" + +typedef struct FAT { + storage_dev_t* storageDev; + uint32_t lbaStart; + uint32_t lbaLength; + uint16_t reservedSectors; + uint32_t sectorsPerFAT; + uint8_t FATCopies; + uint8_t sectorsPerCluster; + uint32_t startClustOfRootDir; + uint8_t fileSys; + uint16_t maxRootDirEntries; +}FAT; + +#define FAT12 0 +#define FAT16 1 +#define FAT32 2 +#define FAT_ATTR_ARCHIVE 0x20 +#define FAT_ATTR_VOLLABEL 0x08 +#define FAT_ATTR_SUBDIR 0x10 +#define FAT_MAX_PATH_FILES 16 +#define FAT_MAX_FNAME_LEN 34 + +FAT* FAT_create(storage_dev_t* storageDev, uint32_t lbaStart, uint32_t lbaLength, uint8_t fileSys); +void FAT_destroy(FAT* inst); +uint8_t FAT_writeFileContents(FAT* inst, char* filepath, uint8_t* contents, uint32_t length); +char* FAT_readVolumeLabel(FAT* inst); +char* FAT_formatFilePath(char* filepath); +uint8_t* FAT_readFileEntry(FAT* inst, char* filepath); +uint32_t FAT_getFilesize(uint8_t* entry); +uint8_t FAT_readFileByte(FAT* inst, uint8_t* entry); +void FAT_readFileContents(FAT* inst, uint8_t* entry, uint8_t* buffer, uint32_t start, uint32_t len); +uint8_t FAT_format(FAT* inst, uint8_t fileSys, char* volumeLabel, uint16_t reservedSectors, uint8_t quick); +uint8_t* FAT_createFile(FAT* inst, char* filepath, uint8_t attribute); +void FAT_setVolumeLabel(FAT* inst, char* volumeLabel); +uint8_t FAT_createDirectory(FAT* inst, char* filepath); +void FAT_deleteFile(FAT* inst, char* filepath); + +uint8_t FAT_readFileEntryByIndex(FAT* inst, file_t* file_inst, char* filepath, uint32_t index); + +uint8_t FAT_abstract_createFile(FAT* inst, char* filepath, file_t* file_inst); +uint8_t FAT_abstract_findFile(FAT* inst, char* filepath, file_t* file_inst); +void FAT_abstract_readFileContents(FAT* inst, file_t* file_inst, uint8_t* buffer, uint32_t start, uint32_t len); +uint8_t FAT_abstract_isDirectory(FAT* inst, char* filepath); +uint8_t FAT_abstract_createDirectory(FAT* inst, char* filepath); + +#endif diff --git a/tools/src/imgtools/src/fileManager.h b/tools/src/imgtools/src/fileManager.h new file mode 100755 index 0000000..333f512 --- /dev/null +++ b/tools/src/imgtools/src/fileManager.h @@ -0,0 +1,15 @@ +#ifndef FILE_MANAGER_H +#define FILE_MANAGER_H + +#include + +struct Partition_t; +typedef struct file_t { + char name[35]; + uint8_t data[32]; + uint32_t size; + uint8_t attribute; + struct Partition_t* partition; // Partition the file belongs to +} file_t; + +#endif diff --git a/tools/src/imgtools/src/imgtools.c b/tools/src/imgtools/src/imgtools.c new file mode 100755 index 0000000..40f0ba3 --- /dev/null +++ b/tools/src/imgtools/src/imgtools.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include "fat.h" + +uint8_t partition = 1; +char* imagefile = NULL; +char* fatfile = NULL; +char* filetocopy = NULL; +char* volumelabel = NULL; +char* fatdir = NULL; + +char *strrpbrk(const char *szString, const char *szChars) { + const char *p; + const char *p1; + const char *p0; + + for (p = szChars, p0 = p1 = NULL; p && *p; ++p) { + p1 = strrchr(szString, *p); + + if (p1 && p1 > p0) + p0 = p1; + } + return (char*) p0; +} + +int get_params(int args, char* argv[]); + +int main(int argc, char* argv[]) { + get_params(argc, argv); + + if (imagefile == NULL) { + puts("No image file given"); + exit(1); + } + + if (volumelabel == NULL && fatdir == NULL) { + if (filetocopy == NULL) { + puts("No filetocopy given"); + exit(1); + } + + if (fatfile == NULL) { + fatfile = strrpbrk(filetocopy, "/\\"); + + if (fatfile == NULL) + fatfile = filetocopy; + } + } + + storage_devManager_init(imagefile); + + uint8_t bootsector[512]; + storage_readSector(NULL, 0, bootsector, 512); + + uint32_t lbaStart = 0; + uint32_t lbaLength = storage_size() / 512; + + if (strncmp((char*)&bootsector + 0x36, "FAT12 ", 8) != 0 && + strncmp((char*)&bootsector + 0x36, "FAT16 ", 8) != 0 && + strncmp((char*)&bootsector + 0x52, "FAT32 ", 8) != 0) + { + lbaStart = *((uint32_t*)(bootsector + 0x1AE + partition * 16 + 0x08)); + lbaLength = *((uint32_t*)(bootsector + 0x1AE + partition * 16 + 0x0C)); + } + + FAT* fat = FAT_create(NULL, lbaStart, lbaLength, FAT12); + + if (volumelabel == NULL) { + if (fatdir == NULL) { + FILE* fp = fopen(filetocopy, "rb"); + if (fp == NULL) { + fprintf(stderr, "cannot open file %s\n", filetocopy); + exit(1); + } + + fseek(fp, 0L, SEEK_END); + uint32_t sz = ftell(fp); + fseek(fp, 0L, SEEK_SET); + uint8_t* contents = (uint8_t*)malloc(sz); + fread(contents, 1, sz, fp); + fclose(fp); + + file_t file = { { 0 },{ 0 }, 0, 0, NULL }; + FAT_abstract_createFile(fat, fatfile, &file); + FAT_writeFileContents(fat, fatfile, contents, sz); + } else { + FAT_abstract_createDirectory(fat, fatdir); + } + } else { + FAT_setVolumeLabel(fat, volumelabel); + } + + storage_bye(); + FAT_destroy(fat); + exit(0); + + return 0; +} + +int get_params(int argc, char *argv[]) { + int i; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-help")) { + printf(" Help Screen:\n" + " -help prints this info\n" + " -i imagefile the image file\n" + " -l volumelabel the new volume label\n" + " -d directory the new directory to create\n" + " -f fatfile the target file on the image\n" + " -p partition the number of the partition (1 - 4)\n" + " filetocopy the file to copy\n"); + exit(1); + } else if (!memcmp(argv[i], "-p", 2) && isdigit(argv[i][2])) { + partition = atoi(&argv[i][2]); + if (partition < 1 && partition > 4) { + printf("Invalid partition %d. Only 1 - 4 would be valid", partition); + exit(1); + } + continue; + } else if (!memcmp(argv[i], "-i", 2)) { + if (strlen(argv[i]) > 2) { + uint32_t len = strlen(&argv[i][2]); + imagefile = (char*) malloc(len + 1); + strcpy(imagefile, &argv[i][2]); + imagefile[len] = 0; + } else { + if ((i + 1) < argc) { + uint32_t len = strlen(argv[++i]); + imagefile = (char*)malloc(len + 1); + strcpy(imagefile, argv[i]); + imagefile[len] = 0; + } else { + printf("\n No imagefile given..."); + return 1; + } + } + continue; + } else if (!memcmp(argv[i], "-f", 2)) { + if (strlen(argv[i]) > 2) { + uint32_t len = strlen(&argv[i][2]); + fatfile = (char*)malloc(len + 1); + strcpy(fatfile, &argv[i][2]); + fatfile[len] = 0; + } else { + if ((i + 1) < argc) { + uint32_t len = strlen(argv[++i]); + fatfile = (char*)malloc(len + 1); + strcpy(fatfile, argv[i]); + fatfile[len] = 0; + } else { + printf("\n No file on the image given..."); + return 1; + } + } + continue; + } else if (!memcmp(argv[i], "-l", 2)) { + if (strlen(argv[i]) > 2) { + uint32_t len = strlen(&argv[i][2]); + volumelabel = (char*)malloc(len + 1); + strcpy(volumelabel, &argv[i][2]); + volumelabel[len] = 0; + } else { + if ((i + 1) < argc) { + uint32_t len = strlen(argv[++i]); + volumelabel = (char*)malloc(len + 1); + strcpy(volumelabel, argv[i]); + volumelabel[len] = 0; + } + } + continue; + } else if (!memcmp(argv[i], "-d", 2)) { + if (strlen(argv[i]) > 2) { + uint32_t len = strlen(&argv[i][2]); + fatdir = (char*)malloc(len + 1); + strcpy(fatdir, &argv[i][2]); + fatdir[len] = 0; + } else { + if ((i + 1) < argc) { + uint32_t len = strlen(argv[++i]); + fatdir = (char*)malloc(len + 1); + strcpy(fatdir, argv[i]); + fatdir[len] = 0; + } + } + continue; + } else if (argv[i][0] == '-') { + printf("\n Unknown Parameter: '%s'", argv[i]); + exit(1); + } + + // else, it must be the filename + uint32_t len = strlen(argv[i]); + filetocopy = (char*)malloc(len + 1); + strcpy(filetocopy, argv[i]); + filetocopy[len] = 0; + } + + return 0; +} diff --git a/tools/src/imgtools/src/storage_devManager.c b/tools/src/imgtools/src/storage_devManager.c new file mode 100755 index 0000000..b36103e --- /dev/null +++ b/tools/src/imgtools/src/storage_devManager.c @@ -0,0 +1,34 @@ +#include "storage_devManager.h" +#include +#include +#include + +FILE* ft = NULL; + +void storage_devManager_init(const char* filename) { + ft = fopen(filename, "rb+"); + if (ft == NULL) + { + fprintf(stderr, "cannot open target file %s\n", filename); + exit(1); + } +} + +void storage_bye() { + fclose(ft); //!!! MEMORY LEAK !!! +} + +uint32_t storage_size() { + fseek(ft, 0L, SEEK_END); + return ftell(ft); +} + +void storage_readSector(storage_dev_t* dev, uint32_t sector, uint8_t* data, size_t count) { + fseek(ft, sector * 512, SEEK_SET); + fread(data, count, 1, ft); +} + +void storage_writeSector(storage_dev_t* dev, uint32_t sector, uint8_t* data, size_t count) { + fseek(ft, sector * 512, SEEK_SET); + fwrite(data, 1, count, ft); +} diff --git a/tools/src/imgtools/src/storage_devManager.h b/tools/src/imgtools/src/storage_devManager.h new file mode 100755 index 0000000..75598c9 --- /dev/null +++ b/tools/src/imgtools/src/storage_devManager.h @@ -0,0 +1,26 @@ +#ifndef STORAGE_DEVMANAGER_H +#define STORAGE_DEVMANAGER_H + +#include +#include + +#define STORAGE_DEVMANAGER_TYPE_FLOPPY 0 +#define STORAGE_DEVMANAGER_TYPE_HDD 1 + +typedef struct { + uint8_t type; + void* inst; + // Parameters: inst, sector, data, count + uint8_t(*readSector) (void*, uint32_t, uint8_t*, size_t); + uint8_t(*writeSector)(void*, uint32_t, uint8_t*, size_t); + void* partitions; +} storage_dev_t; + +void storage_devManager_init(const char* filename); +void storage_readSector(storage_dev_t* dev, uint32_t sector, uint8_t* data, size_t count); +void storage_writeSector(storage_dev_t* dev, uint32_t sector, uint8_t* data, size_t count); + +void storage_bye(); +uint32_t storage_size(); + +#endif diff --git a/tools/src/mkdosfs/build-win.sh b/tools/src/mkdosfs/build-win.sh new file mode 100755 index 0000000..5d99bd9 --- /dev/null +++ b/tools/src/mkdosfs/build-win.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +printf "\033[1;34mCompiling\033[1;97m\t==> mkdosfs.c...\033[0m" +x86_64-w64-mingw32-gcc -s -o mkdosfs.exe src/mkdosfs.c +mv mkdosfs.exe ../../ +printf "\033[1;32mdone\033[0m\n" diff --git a/tools/src/mkdosfs/build.sh b/tools/src/mkdosfs/build.sh new file mode 100755 index 0000000..090be93 --- /dev/null +++ b/tools/src/mkdosfs/build.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +cd "$(dirname "$(readlink -f "$0")")" + +printf "\033[1;34mCompiling\033[1;97m\t==> mkdosfs.c...\033[0m" +gcc -s -o mkdosfs src/mkdosfs.c +mv mkdosfs ../../ +printf "\033[1;32mdone\033[0m\n" diff --git a/tools/src/mkdosfs/src/mkdosfs.c b/tools/src/mkdosfs/src/mkdosfs.c new file mode 100644 index 0000000..3db8612 --- /dev/null +++ b/tools/src/mkdosfs/src/mkdosfs.c @@ -0,0 +1,817 @@ +#include +#include +#include +#include +#include +#include + +#include "mkdosfs.h" + +#define FAT12 0 +#define FAT16 1 +#define FAT32 2 + +#define ROOT_SECTS 14 + +FILE *fp, *sfp, *mfp; + +uint8_t buffer[512]; // a temp buffer +char strbuff[80]; // a temp str buffer +char filename[80]; // filename +char bootname[80]; // boot filename +char mbrfile[80]; +char volumelabel[11]; + +int sec_res = -1; // reserved sectors +int bpbz = 0; // size of used BPB +int spfat; // sectors per fat +uint32_t sectors = 2880; // total sectors +bool make_mbr = false; // do as a MBR and a partition? +bool make_hd = false; // make hard drive image +bool make_fd = false; // make floppy drive image +int image_size = -1; // image size in megabytes (if hd used) +int spt = -1; // spt (if fd used) +int heads = -1; // heads " +int cyl = -1; // cyliders " +int spc = -1; // sectors per cluster +int fatz = -1; // fat size (12, 16, 32) +int fats = -1; // fats (1 or 2) +bool filenamegiven = false; // was a filename given on the command line +bool bootnamegiven = false; // was a boot filename given on the command line +bool mbrfilegiven = false; +bool volumelabelgiven = false; +bool make_mbr_given = false; + +bool verbose = true; + +uint8_t media_descriptor(bool ishd, int heads, int spt, int cylinders); +int get_params(int argc, char *argv[]); +void write_sector(FILE *fp, void *ptr); +void putdot(); + +int main(int argc, char *argv[]) { + + int i, j, r; + uint32_t last_cnt; + uint8_t boot_sector[512]; + + // get the command line parameters + if (get_params(argc, argv) != 0) + return 1; + + if (!make_hd && !make_fd) { + do { + printf("Make Floppy or Hard Drive image? (fd/hd) [fd]: "); + fgets(strbuff, sizeof(strbuff), stdin); + if (!strlen(strbuff)) { + make_fd = true; + make_hd = false; + break; + } + } while (strcmp(strbuff, "fd") && strcmp(strbuff, "hd")); + if (strlen(strbuff)) + if (!strcmp(strbuff, "fd")) { + make_fd = true; + make_hd = false; + } else { + make_fd = false; + make_hd = true; + } + } + + if (!make_mbr_given && make_hd) { + do { + printf("Create MBR and separate partition? (y/n) [y]: "); + fgets(strbuff, sizeof(strbuff), stdin); + if (!strlen(strbuff)) { + make_mbr = true; + break; + } + } while (strcmp(strbuff, "y") && strcmp(strbuff, "n")); + if (!strcmp(strbuff, "y")) + make_mbr = true; + } + + if (!filenamegiven) { + printf(" As filename [%c.img]: ", (make_hd) ? 'c' : 'a'); + fgets(filename, sizeof(filename), stdin); + if (!strlen(filename)) + strcpy(filename, (make_hd) ? "c.img" : "a.img"); + if (!strchr(filename, '.')) + strcat(filename, ".img"); + } + + if (make_hd) { + if (image_size == -1) { + do { + printf(" Size (meg) (1 - 1024) [10]: "); + fgets(strbuff, sizeof(strbuff), stdin); + if (!strlen(strbuff)) + i = 10; + else + i = atoi(strbuff); + } while ((i < 1) || (i > 1024)); + cyl = (i << 1); // very close at 16 heads and 63 spt + } + else { + if ((image_size > 0) && (image_size <= 1024)) + cyl = (image_size << 1); + else { + printf("Illegal value for Image Size: %i\n", image_size); + return 1; + } + } + heads = 16; + spt = 63; + } + else { + if (spt == -1) { + do { + printf(" Sectors per track (8, 9, 15, 18, 21, 36) [18]: "); + fgets(strbuff, sizeof(strbuff), stdin); + if (!strlen(strbuff)) + i = 18; + else + i = atoi(strbuff); + } while ((i != 8) && (i != 9) && (i != 15) && (i != 18) && (i != 21) && (i != 36)); + + if (i == 36) + spc = 2; // default + + spt = i; + } + else { + if ((spt != 8) && (spt != 9) && (spt != 15) && (spt != 18) && (spt != 21) && (spt != 36)) { + printf(" Illegal value for SPT: %i\n", spt); + return 1; + } + } + if (heads == -1) { + do { + printf(" Heads: (1, 2) [2]: "); + fgets(strbuff, sizeof(strbuff), stdin); + + if (!strlen(strbuff)) + i = 2; + else + i = atoi(strbuff); + } while ((i != 1) && (i != 2)); + heads = i; + } + else { + if ((heads != 1) && (heads != 2)) { + printf(" Illegal value for heads: %i\n", heads); + return 1; + } + } + if (cyl == -1) { + do { + if ((spt < 9) || (heads == 1)) { + printf(" Cylinders: (40, 80) [40]: "); + fgets(strbuff, sizeof(strbuff), stdin); + + if (!strlen(strbuff)) + i = 40; + else + i = atoi(strbuff); + } else { + printf(" Cylinders: (40, 80) [80]: "); + fgets(strbuff, sizeof(strbuff), stdin); + + if (!strlen(strbuff)) + i = 80; + else + i = atoi(strbuff); + } + } while ((i != 40) && (i != 80)); + cyl = i; + } + else { + if ((cyl != 40) && (cyl != 80)) { + printf(" Illegal value for cylinders: %i\n", cyl); + return 1; + } + } + } + sectors = (cyl * heads * spt); + + if (spc == -1) { + do { + printf(" Sectors per Cluster [1]: "); + fgets(strbuff, sizeof(strbuff), stdin); + + if (!strlen(strbuff)) + i = 1; + else + i = atoi(strbuff); + } while (i > 255); + spc = i; + } + else { + if ((spc != 1) && (spc != 2) && (spc != 4) && (spc != 8) && (spc != 16)) { + printf(" Illegal value for SPC: %i\n", spc); + return 1; + } + } + + if (fats == -1) { + do { + printf(" Number of FAT's [2]: "); + fgets(strbuff, sizeof(strbuff), stdin); + + if (!strlen(strbuff)) + fats = 2; + else + fats = atoi(strbuff); + } while ((fats < 1) || (fats > 2)); + } + else { + if ((fats != 1) && (fats != 2)) { + printf(" Illegal value for FATs: %i\n", fats); + return 1; + } + } + + if (fatz == -1) { + do { + printf(" FAT Size: [12]: "); + fgets(strbuff, sizeof(strbuff), stdin); + + if (!strlen(strbuff)) + i = 12; + else + i = atoi(strbuff); + } while ((i != 12) && (i != 16) && (i != 32)); + fatz = i; + } + else { + if ((fatz != 12) && (fatz != 16) && (fatz != 32)) { + printf(" Illegal value for FAT size: %i\n", fatz); + return 1; + } + } + + switch (fatz) { + case 12: + if ((sectors / (uint32_t)spc) > 4086L) { + printf(" *** Illegal Size disk with FAT 12 *** \n"); + return 1; + } + spfat = (int)((int)((float)sectors * 1.5) / (512 * spc)) + 1; + + // actual count bytes on last fat sector needed as zeros (???) + last_cnt = ((sectors - ((fats * spfat) + 17)) / spc); + last_cnt = ((uint32_t)((float)last_cnt * 1.5) % 512); + + break; + case 16: + if ((sectors / (uint32_t)spc) > 65526UL) { + printf(" *** Illegal Size disk with FAT 16 *** \n"); + return 1; + } + spfat = (int)((sectors << 1) / (512 * spc)) + 1; + + // actual count bytes on last fat sector needed as zeros (???) + last_cnt = ((sectors - ((fats * spfat) + 17)) / spc); + last_cnt = ((uint32_t)(last_cnt << 1) % 512); + + break; + default: + spfat = (int)((sectors << 2) / (512 * spc)) + 1; + + // actual count bytes on last fat sector needed as zeros (???) + last_cnt = ((sectors - ((fats * spfat) + 17)) / spc); + last_cnt = ((uint32_t)(last_cnt << 2) % 512); + } + + if (verbose) + printf(" Creating file: %s\n" + " Cylinders: %i\n" + " Sides: %i\n" + " Sectors/Track: %i\n" + " Total Sectors: %lu\n" + " Size: %3.2f (megs)\n" + " Sectors/Cluster: %i\n" + " FAT's: %i\n" + " Sectors/FAT: %i\n" + " FAT size: %i\n", + filename, cyl, heads, spt, sectors, + (float)((float)sectors / 2000.0), spc, fats, spfat, fatz); + + if (bootnamegiven) { + if ((sfp = fopen(bootname, "rb")) == NULL) { + printf("\nError opening file [%s]", bootname); + return 1; + } + + fseek(sfp, 0, SEEK_END); + sec_res = ftell(sfp); + fclose(sfp); + + if (sec_res % 512) + sec_res = ((sec_res + 511) / 512); + else + sec_res /= 512; + + if (verbose) + printf("\n Using Boot file %s of %i sectors", bootname, sec_res); + } + + if (mbrfilegiven) { + if ((mfp = fopen(mbrfile, "rb")) == NULL) { + printf("\nError opening file [%s]", mbrfile); + return 1; + } + + fclose(mfp); + + if (verbose) + printf("\n Using MBR file %s", mbrfile); + } + + if ((fp = fopen(filename, "wb")) == NULL) { + printf("\nError creating file [%s]", filename); + return 1; + } + + if (verbose) + printf("\n\nWorking["); + + if (make_mbr) { + // Make a simple MBR that points to the partition 63 sectors away. + if (mbrfilegiven) { + mfp = fopen(mbrfile, "rb"); + fseek(mfp, 0, SEEK_SET); + fread(boot_sector, 1, 512, mfp); + fclose(mfp); + } else { + memcpy(boot_sector, empty_mbr, 512); + } + + struct PART_TBLE *part_tble = (struct PART_TBLE *) (boot_sector + 446); + memset(part_tble, 0, 4 * sizeof(struct PART_TBLE)); + part_tble->bi = 0x80; + part_tble->s_sector = 1; // sectors are 1 based + part_tble->s_head = 1; + part_tble->s_cyl = 0; + + if (fatz == 12) + part_tble->si = 0x01; + else if (fatz == 16) + part_tble->si = (sectors < 65536) ? 0x04 : 0x06; // System ID + else + part_tble->si = 0x0B; + + if ((sectors - 1 + 63) <= 16450560UL) { // 16450560 = 1024 cyl, 255 heads, 63 spt + const uint8_t sects = (uint8_t)(((sectors - 1 + 63) % spt) + 1) & 0x3F; + const uint16_t cyls = (uint16_t)(((sectors - 1 + 63) / spt) / heads); + part_tble->e_sector = (uint8_t)(((cyl & 0x300) >> 2) | sects); + part_tble->e_head = (uint8_t)(((sectors - 1 + 63) / spt) % heads); + part_tble->e_cyl = (uint8_t)(cyls & 0xFF); + } else { + part_tble->e_sector = 0xFF; + part_tble->e_head = 0xFF; + part_tble->e_cyl = 0xFF; + } + part_tble->startlba = 63; + part_tble->size = sectors; + + // Write the MBR and padding sectors + if (verbose) + putchar('.'); + + write_sector(fp, boot_sector); + memset(boot_sector, 0, 512); + + for (i = 1; i < 63; i++) + write_sector(fp, boot_sector); + } + + // Create BPB/boot block + + if (sec_res == -1) { + memset(boot_sector, 0, 512); // first, clear it out + } else { + sfp = fopen(bootname, "rb"); + fread(boot_sector, 512, 1, sfp); + } + + switch (fatz) { + case 12: + case 16: { + struct S_FAT1216_BPB *bpb = (struct S_FAT1216_BPB *) boot_sector; + bpb->nBytesPerSec = 512; + bpb->nSecPerClust = spc; + bpb->nSecRes = (sec_res > 0) ? sec_res : 1; + bpb->nFATs = fats; + bpb->nRootEnts = (sectors >= 1440) ? 224 : 64; + + if (sectors < 65536) { + bpb->nSecs = (uint16_t)sectors; + bpb->nSecsExt = 0; + } else { + bpb->nSecs = 0; + bpb->nSecsExt = sectors; + } + + bpb->mDesc = media_descriptor(make_hd, heads, spt, cyl); + bpb->nSecPerFat = spfat; + bpb->nSecPerTrack = spt; + bpb->nHeads = heads; + bpb->nSecHidden = (make_mbr) ? 63 : 0; + bpb->DriveNum = make_hd << 7; + bpb->nResByte = 0; + + if (sec_res == -1) { + bpb->jmps[0] = 0xEB; bpb->jmps[1] = 0x3C; + bpb->nop = 0x90; + memcpy(bpb->oemname, "MKFATIMG", 8); + + bpb->sig = 0x29; + bpb->SerNum = 0; + memcpy(bpb->VolName, " ", 11); + sprintf(strbuff, "FAT%2i ", fatz); + memcpy(bpb->FSType, strbuff, 8); + + memcpy(bpb->filler, boot_code, sizeof(boot_code)); + memcpy(bpb->filler + sizeof(boot_code), boot_data, sizeof(boot_data)); + memset(bpb->part_tble, 0, 4 * sizeof(struct PART_TBLE)); + + if (make_hd && !make_mbr) { + bpb->part_tble[0].bi = 0x80; + bpb->part_tble[0].s_sector = 1; + bpb->part_tble[0].si = (sectors < 65536) ? 0x04 : 0x06; + // TODO: lba -> chs for ending CHS entries. + bpb->part_tble[0].startlba = 0; + bpb->part_tble[0].size = sectors; + } + + bpb->boot_sig = 0xAA55; + } + + bpbz = (void*)bpb->filler - (void*)bpb; + break; + } + + case 32: { + struct S_FAT32_BPB *bpb = (struct S_FAT32_BPB *) boot_sector; + bpb->nBytesPerSec = 512; + bpb->nSecPerClust = spc; + bpb->nSecRes = SECT_RES32; + bpb->nFATs = fats; + bpb->nRootEnts = 0; + bpb->nSecs = 0; + bpb->nSecsExt = sectors; + bpb->mDesc = media_descriptor(make_hd, heads, spt, cyl); + bpb->nSecPerFat = 0; + bpb->nSecPerTrack = spt; + bpb->nHeads = heads; + bpb->nSecHidden = (make_mbr) ? 63 : 0; + bpb->sect_per_fat32 = spfat; + bpb->DriveNum = make_hd << 7; + bpb->ext_flags = 0x00; + bpb->fs_version = 0; + bpb->root_base_cluster = 0x02; + bpb->fs_info_sec = 1; + bpb->backup_boot_sec = 6; + bpb->nResByte = 0; + + if (sec_res == -1) { + bpb->jmps[0] = 0xEB; bpb->jmps[1] = 0x3C; + bpb->nop = 0x90; + memcpy(bpb->oemname, "MKFATIMG", 8); + bpb->sig = 0x29; + bpb->SerNum = rand(); + memcpy(bpb->VolName, " ", 11); // Volume Label + memcpy(bpb->FSType, "FAT32 ", 8); // File system type + memcpy(bpb->filler, boot_code, sizeof(boot_code)); + memcpy(bpb->filler + sizeof(boot_code), boot_data, sizeof(boot_data)); + memset(bpb->part_tble, 0, 4 * sizeof(struct PART_TBLE)); + + if (make_hd && !make_mbr) { + bpb->part_tble[0].bi = 0x80; + bpb->part_tble[0].s_sector = 1; // sectors are 1 based + bpb->part_tble[0].si = (sectors < 65536) ? 0x04 : 0x06; // System ID + // TODO: lba -> chs for ending CHS entries. + bpb->part_tble[0].startlba = 0; + bpb->part_tble[0].size = sectors; + } + + bpb->boot_sig = 0xAA55; + } + + bpbz = (void*)bpb->filler - (void*)bpb; + break; + } + } + + // Write the BPB + putdot(); + + if (sec_res == -1) { + write_sector(fp, boot_sector); + sectors--; + sfp = NULL; + } else { + sfp = fopen(bootname, "rb"); + fread(buffer, 512, 1, sfp); + memcpy(buffer, boot_sector, bpbz); + write_sector(fp, buffer); + sectors--; + if ((fatz == 12) || (fatz == 16)) { + while (--sec_res) { + fread(buffer, 512, 1, sfp); + write_sector(fp, buffer); + sectors--; + } + } + } + + // if fat32, write the info sector + if (fatz == 32) { + struct S_FAT32_FSINFO fsInfo; + memset(&fsInfo, 0, 512); + fsInfo.sig0 = 0x41615252; + fsInfo.sig1 = 0x61417272; + fsInfo.free_clust_fnt = /* 0xFFFFFFFF;*/ (sectors - spfat - ROOT_SECTS) / spc; // a good approximation + fsInfo.next_free_clust = 2; + fsInfo.trail_sig = 0xAA550000; + putdot(); + write_sector(fp, &fsInfo); // LBA 1 + + // if the bootfile is larger than 1 sector, skip over the + // info sector part and copy the rest to this area, up to + // LBA 6. + sec_res -= 2; // subtract LBA 0 and LBA 1 + if (sec_res > 0) { + r = 4; // (for LBA 2 -> LBA 5) + fseek(sfp, (2 * 512), SEEK_SET); + + while (sec_res--) { + r--; + fread(buffer, 512, 1, sfp); + write_sector(fp, buffer); + } + + memset(buffer, 0, 512); + + while (r--) + write_sector(fp, buffer); + } else { + memset(buffer, 0, 512); + buffer[510] = 0x55; + buffer[511] = 0xAA; + write_sector(fp, buffer); // LBA 2 + + memset(buffer, 0, 512); + write_sector(fp, buffer); // LBA 3 + write_sector(fp, buffer); // LBA 4 + write_sector(fp, buffer); // LBA 5 + } + + write_sector(fp, boot_sector); // LBA 6 + write_sector(fp, &fsInfo); // LBA 7 + buffer[510] = 0x55; + buffer[511] = 0xAA; + write_sector(fp, buffer); // LBA 8 + + memset(buffer, 0, 512); + + for (r = 9; r 2) { + strcpy(bootname, &argv[i][2]); + bootnamegiven = true; + } else { + if ((i + 1) < argc) { + strcpy(bootname, argv[++i]); + bootnamegiven = true; + } else { + printf("\n No filepath given for -b..."); + return 1; + } + } + continue; + } else if (!memcmp(argv[i], "-m", 2)) { + if (strlen(argv[i]) > 2) { + strcpy(mbrfile, &argv[i][2]); + mbrfilegiven = true; + } else { + if ((i + 1) < argc) { + strcpy(mbrfile, argv[++i]); + mbrfilegiven = true; + } else { + printf("\n No filepath given for -m..."); + return 1; + } + } + continue; + } else if (!memcmp(argv[i], "-l", 2)) { + if (strlen(argv[i]) > 2) { + strcpy(volumelabel, &argv[i][2]); + volumelabelgiven = true; + } else { + if ((i + 1) < argc) { + strcpy(volumelabel, argv[++i]); + volumelabelgiven = true; + } else { + printf("\n No volume label given..."); + return 1; + } + } + continue; + } else if (argv[i][0] == '-') { + printf("\n Unknown Parameter: '%s'", argv[i]); + return 1; + } + + // else, it must be the filename + strcpy(filename, argv[i]); + filenamegiven = true; + } + + return 0; +} diff --git a/tools/src/mkdosfs/src/mkdosfs.h b/tools/src/mkdosfs/src/mkdosfs.h new file mode 100644 index 0000000..a53f021 --- /dev/null +++ b/tools/src/mkdosfs/src/mkdosfs.h @@ -0,0 +1,156 @@ +#include + +struct PART_TBLE { + uint8_t bi; + uint8_t s_head; // 8 bit head count + uint8_t s_sector; // hi 2 bits is hi 2 bits of cyl, bottom 6 bits is sector + uint8_t s_cyl; // bottom 8 bits + uint8_t si; + uint8_t e_head; // 8 bit head count + uint8_t e_sector; // hi 2 bits is hi 2 bits of cyl, bottom 6 bits is sector + uint8_t e_cyl; // bottom 8 bits + uint32_t startlba; + uint32_t size; +} __attribute__((packed)); + +struct S_FAT1216_BPB { + uint8_t jmps[2]; // The jump short instruction + uint8_t nop; // nop instruction; + char oemname[8]; // OEM name + uint16_t nBytesPerSec; // Bytes per sector + uint8_t nSecPerClust; // Sectors per cluster + uint16_t nSecRes; // Sectors reserved for Boot Record + uint8_t nFATs; // Number of FATs + uint16_t nRootEnts; // Max Root Directory Entries allowed + uint16_t nSecs; // Number of Logical Sectors (0B40h) + uint8_t mDesc; // Medium Descriptor Byte + uint16_t nSecPerFat; // Sectors per FAT + uint16_t nSecPerTrack; // Sectors per Track + uint16_t nHeads; // Number of Heads + uint32_t nSecHidden; // Number of Hidden Sectors + uint32_t nSecsExt; // This value used when there are more + uint8_t DriveNum; // Physical drive number + uint8_t nResByte; // Reserved (we use for FAT type (12- 16-bit) + uint8_t sig; // Signature for Extended Boot Record + uint32_t SerNum; // Volume Serial Number + char VolName[11]; // Volume Label + char FSType[8]; // File system type + uint8_t filler[384]; + struct PART_TBLE part_tble[4]; // partition table + uint16_t boot_sig; +} __attribute__((packed)); + +#define SECT_RES32 32 // sectors reserved + +struct S_FAT32_BPB { + uint8_t jmps[2]; + uint8_t nop; // nop instruction; + char oemname[8]; + uint16_t nBytesPerSec; + uint8_t nSecPerClust; + uint16_t nSecRes; + uint8_t nFATs; + uint16_t nRootEnts; + uint16_t nSecs; + uint8_t mDesc; + uint16_t nSecPerFat; + uint16_t nSecPerTrack; + uint16_t nHeads; + uint32_t nSecHidden; + uint32_t nSecsExt; + uint32_t sect_per_fat32; // offset 36 (24h) + uint16_t ext_flags; // bit 8 = write to all copies of FAT(s). bit0:3 = which fat is active + uint16_t fs_version; + uint32_t root_base_cluster; // + uint16_t fs_info_sec; + uint16_t backup_boot_sec; + uint8_t reserved[12]; + uint8_t DriveNum; // not FAT specific + uint8_t nResByte; + uint8_t sig; + uint32_t SerNum; + char VolName[11]; + char FSType[8]; + uint8_t filler[356]; + struct PART_TBLE part_tble[4]; // partition table + uint16_t boot_sig; +} __attribute__((packed)); + +struct S_FAT32_FSINFO { + uint32_t sig0; // 0x41615252 ("RRaA") + uint8_t resv[480]; + uint32_t sig1; // 0x61417272 ("rrAa") + uint32_t free_clust_fnt; // 0xFFFFFFFF when the count is unknown + uint32_t next_free_clust; // most recent allocated cluster + 1 + uint8_t resv1[12]; + uint32_t trail_sig; // 0xAA550000 +} __attribute__((packed)); + + +unsigned char boot_code[] = { + 0xFA, //CLI + 0xB8,0xC0,0x07, //MOV AX,07C0 + 0x8E,0xD8, //MOV DS,AX + 0x8E,0xD0, //MOV SS,AX + 0xBC,0x00,0x40, //MOV SP,4000 + 0xFB, //STI + 0xBE,0x6B,0x00, //MOV SI,006B + 0xE8,0x06,0x00, //CALL 0156 + 0x30,0xE4, //XOR AH,AH + 0xCD,0x16, //INT 16 + 0xCD,0x18, //INT 18 + 0x50, //PUSH AX + 0x53, //PUSH BX + 0x56, //PUSH SI + 0xB4,0x0E, //MOV AH,0E + 0x31,0xDB, //XOR BX,BX + 0xFC, //CLD + 0xAC, //LODSB + 0x08,0xC0, //OR AL,AL + 0x74,0x04, //JZ 0167 + 0xCD,0x10, //INT 10 + 0xEB,0xF6, //JMP 015D + 0x5E, //POP SI + 0x5B, //POP BX + 0x58, //POP AX + 0xC3, //RET + 13,10 +}; +unsigned char boot_data[] = "Error reading disk or Non-System Disk" +"\x0D\x0A" +"Press a key to reboot\x00"; + +unsigned char empty_mbr[] = { + 0xFA, 0xB8, 0xC0, 0x07, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC, 0x00, 0x40, 0xFB, 0xBE, 0x24, 0x00, 0xE8, + 0x03, 0x00, 0xF4, 0xEB, 0xFD, 0xB4, 0x0E, 0x31, 0xDB, 0xFC, 0xAC, 0x08, 0xC0, 0x74, 0x04, 0xCD, + 0x10, 0xEB, 0xF6, 0xC3, 0x03, 0x0A, 0x07, 0x49, 0x20, 0x61, 0x6D, 0x20, 0x61, 0x6E, 0x20, 0x65, + 0x6D, 0x70, 0x74, 0x79, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x20, 0x73, 0x65, 0x63, 0x74, 0x6F, 0x72, + 0x2E, 0x20, 0x20, 0x49, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x68, + 0x61, 0x6C, 0x74, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x55, 0xAA +};

Mc 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