diff options
author | Liam <byteslice@airmail.cc> | 2023-11-17 22:44:53 +0100 |
---|---|---|
committer | t895 <clombardo169@gmail.com> | 2023-11-25 06:46:47 +0100 |
commit | 9f91ba1f7357c61dd2c7c3b437ea203d467fd400 (patch) | |
tree | 3cfe55acf5d2f8a0d75373934b4c22a4e9bb2a09 /src/core/arm/nce/patch.h | |
parent | device_memory: Enable direct mapped addresses for nce (diff) | |
download | yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.gz yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.bz2 yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.lz yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.xz yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.tar.zst yuzu-9f91ba1f7357c61dd2c7c3b437ea203d467fd400.zip |
Diffstat (limited to 'src/core/arm/nce/patch.h')
-rw-r--r-- | src/core/arm/nce/patch.h | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/src/core/arm/nce/patch.h b/src/core/arm/nce/patch.h new file mode 100644 index 000000000..b727d4e48 --- /dev/null +++ b/src/core/arm/nce/patch.h @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <span> +#include <unordered_map> +#include <vector> + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#include <oaknut/code_block.hpp> +#include <oaknut/oaknut.hpp> +#pragma clang diagnostic pop + +#include "common/common_types.h" +#include "core/hle/kernel/code_set.h" +#include "core/hle/kernel/k_typed_address.h" +#include "core/hle/kernel/physical_memory.h" + +#include <signal.h> + +namespace Core { +struct GuestContext; +} + +namespace Core::NCE { + +enum class PatchMode : u32 { + None, + PreText, ///< Patch section is inserted before .text + PostData, ///< Patch section is inserted after .data +}; + +using ModuleTextAddress = u64; +using PatchTextAddress = u64; +using EntryTrampolines = std::unordered_map<ModuleTextAddress, PatchTextAddress>; + +class Patcher { +public: + explicit Patcher(); + ~Patcher(); + + void PatchText(const Kernel::PhysicalMemory& program_image, + const Kernel::CodeSet::Segment& code); + void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, + Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); + size_t SectionSize() const noexcept; + + [[nodiscard]] PatchMode Mode() const noexcept { + return mode; + } + +private: + using ModuleDestLabel = uintptr_t; + + struct Trampoline { + ptrdiff_t patch_offset; + uintptr_t module_offset; + }; + + void WriteLoadContext(); + void WriteSaveContext(); + void LockContext(); + void UnlockContext(); + void WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id); + void WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg, + oaknut::SystemReg src_reg); + void WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg); + void WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg); + +private: + void BranchToPatch(uintptr_t module_dest) { + m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); + } + + void BranchToModule(uintptr_t module_dest) { + m_branch_to_module_relocations.push_back({c.offset(), module_dest}); + c.dw(0); + } + + void WriteModulePc(uintptr_t module_dest) { + m_write_module_pc_relocations.push_back({c.offset(), module_dest}); + c.dx(0); + } + +private: + // List of patch instructions we have generated. + std::vector<u32> m_patch_instructions{}; + + // Relocation type for relative branch from module to patch. + struct Relocation { + ptrdiff_t patch_offset; ///< Offset in bytes from the start of the patch section. + uintptr_t module_offset; ///< Offset in bytes from the start of the text section. + }; + + oaknut::VectorCodeGenerator c; + std::vector<Trampoline> m_trampolines; + std::vector<Relocation> m_branch_to_patch_relocations{}; + std::vector<Relocation> m_branch_to_module_relocations{}; + std::vector<Relocation> m_write_module_pc_relocations{}; + oaknut::Label m_save_context{}; + oaknut::Label m_load_context{}; + PatchMode mode{PatchMode::None}; +}; + +} // namespace Core::NCE |