aboutsummaryrefslogtreecommitdiff
path: root/externals/libadrenotools/src/bcenabler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'externals/libadrenotools/src/bcenabler.cpp')
-rw-r--r--externals/libadrenotools/src/bcenabler.cpp135
1 files changed, 0 insertions, 135 deletions
diff --git a/externals/libadrenotools/src/bcenabler.cpp b/externals/libadrenotools/src/bcenabler.cpp
deleted file mode 100644
index 1deb41df40..0000000000
--- a/externals/libadrenotools/src/bcenabler.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-// SPDX-License-Identifier: BSD-2-Clause
-// Copyright © 2021 Billy Laws
-
-#include <fstream>
-#include <string>
-#include <cstring>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <adrenotools/bcenabler.h>
-#include "gen/bcenabler_patch.h"
-
-enum adrenotools_bcn_type adrenotools_get_bcn_type(uint32_t major, uint32_t minor, uint32_t vendorId) {
- if (vendorId != 0x5143 || major != 512)
- return ADRENOTOOLS_BCN_INCOMPATIBLE;
-
- if (minor >= 514)
- return ADRENOTOOLS_BCN_BLOB;
-
- return ADRENOTOOLS_BCN_PATCH;
-}
-
-// Searches /proc/self/maps for the first free page after the given address
-static void *find_free_page(uintptr_t address) {
- std::ifstream procMaps("/proc/self/maps");
-
- uintptr_t end{};
-
- for (std::string line; std::getline(procMaps, line); ) {
- std::size_t addressSeparator{line.find('-')};
- uintptr_t start{std::strtoull(line.substr(0, addressSeparator).c_str(), nullptr, 16)};
-
- if (end > address && start != end)
- return reinterpret_cast<void *>(end);
-
- end = std::strtoull(line.substr(addressSeparator + 1, line.find( ' ')).c_str(), nullptr, 16);
- }
-
- return nullptr;
-}
-
-static void *align_ptr(void *ptr) {
- return reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(ptr) & ~(getpagesize() - 1));
-}
-
-bool adrenotools_patch_bcn(void *vkGetPhysicalDeviceFormatPropertiesFn) {
- union Branch {
- struct {
- int32_t offset : 26; //!< 26-bit branch offset
- uint8_t sig : 6; //!< 6-bit signature (0x25 for linked, 0x5 for jump)
- };
-
- uint32_t raw{};
- };
- static_assert(sizeof(Branch) == 4, "Branch size is invalid");
-
- // Find the nearest unmapped page where we can place patch code
- void *patchPage{find_free_page(reinterpret_cast<uintptr_t>(vkGetPhysicalDeviceFormatPropertiesFn))};
- if (!patchPage)
- return false;
-
- // Map patch region
- void *ptr{mmap(patchPage, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0)};
- if (ptr != patchPage)
- return false;
-
- // Allow reading from the blob's .text section since some devices enable ---X
- // Protect two pages just in case we happen to land on a page boundary
- if (mprotect(align_ptr(vkGetPhysicalDeviceFormatPropertiesFn), getpagesize() * 2, PROT_WRITE | PROT_READ | PROT_EXEC))
- return false;
-
- // First branch in this function is targeted at the function we want to patch
- Branch *blInst{reinterpret_cast<Branch *>(vkGetPhysicalDeviceFormatPropertiesFn)};
-
- constexpr uint8_t BranchLinkSignature{0x25};
-
- // Search for first instruction with the BL signature
- while (blInst->sig != BranchLinkSignature)
- blInst++;
-
- // Internal QGL format conversion function that we need to patch
- uint32_t *convFormatFn{reinterpret_cast<uint32_t *>(blInst) + blInst->offset};
-
- // See mprotect call above
- // This time we also set PROT_WRITE so we can write our patch to the page
- if (mprotect(align_ptr(convFormatFn), getpagesize() * 2, PROT_WRITE | PROT_READ | PROT_EXEC))
- return false;
-
- // This would normally set the default result to 0 (error) in the format not found case
- constexpr uint32_t ClearResultSignature{0x2a1f03e0};
-
- // We replace it with a branch to our own extended if statement which adds in the extra things for BCn
- uint32_t *clearResultPtr{convFormatFn};
- while (*clearResultPtr != ClearResultSignature)
- clearResultPtr++;
-
- // Ensure we don't write out of bounds
- if (PatchRawData_size > getpagesize())
- return false;
-
- // Copy the patch function to our mapped page
- memcpy(patchPage, PatchRawData, PatchRawData_size);
-
- // Fixup the patch code so it correctly returns back to the driver after running
- constexpr uint32_t PatchReturnFixupMagic{0xffffffff};
- constexpr uint8_t BranchSignature{0x5};
-
- uint32_t *fixupTargetPtr{clearResultPtr + 1};
- auto *fixupPtr{reinterpret_cast<uint32_t *>(patchPage)};
- for (long unsigned int i{}; i < (PatchRawData_size / sizeof(uint32_t)); i++, fixupPtr++) {
- if (*fixupPtr == PatchReturnFixupMagic) {
- Branch branchToDriver{
- {
- .offset = static_cast<int32_t>((reinterpret_cast<intptr_t>(fixupTargetPtr) - reinterpret_cast<intptr_t>(fixupPtr)) / sizeof(int32_t)),
- .sig = BranchSignature,
- }
- };
-
- *fixupPtr = branchToDriver.raw;
- }
- }
-
- Branch branchToPatch{
- {
- .offset = static_cast<int32_t>((reinterpret_cast<intptr_t>(patchPage) - reinterpret_cast<intptr_t>(clearResultPtr)) / sizeof(int32_t)),
- .sig = BranchSignature,
- }
- };
-
- *clearResultPtr = branchToPatch.raw;
-
- asm volatile("ISB");
-
- // Done!
- return true;
-}