diff options
Diffstat (limited to 'src/core/arm/nce/patcher.h')
| -rw-r--r-- | src/core/arm/nce/patcher.h | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/core/arm/nce/patcher.h b/src/core/arm/nce/patcher.h new file mode 100644 index 000000000..c6d1608c1 --- /dev/null +++ b/src/core/arm/nce/patcher.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <span> | ||
| 7 | #include <unordered_map> | ||
| 8 | #include <vector> | ||
| 9 | #include <oaknut/code_block.hpp> | ||
| 10 | #include <oaknut/oaknut.hpp> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "core/hle/kernel/code_set.h" | ||
| 14 | #include "core/hle/kernel/k_typed_address.h" | ||
| 15 | #include "core/hle/kernel/physical_memory.h" | ||
| 16 | |||
| 17 | namespace Core::NCE { | ||
| 18 | |||
| 19 | enum class PatchMode : u32 { | ||
| 20 | None, | ||
| 21 | PreText, ///< Patch section is inserted before .text | ||
| 22 | PostData, ///< Patch section is inserted after .data | ||
| 23 | }; | ||
| 24 | |||
| 25 | using ModuleTextAddress = u64; | ||
| 26 | using PatchTextAddress = u64; | ||
| 27 | using EntryTrampolines = std::unordered_map<ModuleTextAddress, PatchTextAddress>; | ||
| 28 | |||
| 29 | class Patcher { | ||
| 30 | public: | ||
| 31 | explicit Patcher(); | ||
| 32 | ~Patcher(); | ||
| 33 | |||
| 34 | void PatchText(const Kernel::PhysicalMemory& program_image, | ||
| 35 | const Kernel::CodeSet::Segment& code); | ||
| 36 | void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, | ||
| 37 | Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); | ||
| 38 | size_t GetSectionSize() const noexcept; | ||
| 39 | |||
| 40 | [[nodiscard]] PatchMode GetPatchMode() const noexcept { | ||
| 41 | return mode; | ||
| 42 | } | ||
| 43 | |||
| 44 | private: | ||
| 45 | using ModuleDestLabel = uintptr_t; | ||
| 46 | |||
| 47 | struct Trampoline { | ||
| 48 | ptrdiff_t patch_offset; | ||
| 49 | uintptr_t module_offset; | ||
| 50 | }; | ||
| 51 | |||
| 52 | void WriteLoadContext(); | ||
| 53 | void WriteSaveContext(); | ||
| 54 | void LockContext(); | ||
| 55 | void UnlockContext(); | ||
| 56 | void WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id); | ||
| 57 | void WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg, | ||
| 58 | oaknut::SystemReg src_reg); | ||
| 59 | void WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg); | ||
| 60 | void WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg); | ||
| 61 | |||
| 62 | private: | ||
| 63 | void BranchToPatch(uintptr_t module_dest) { | ||
| 64 | m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); | ||
| 65 | } | ||
| 66 | |||
| 67 | void BranchToModule(uintptr_t module_dest) { | ||
| 68 | m_branch_to_module_relocations.push_back({c.offset(), module_dest}); | ||
| 69 | c.dw(0); | ||
| 70 | } | ||
| 71 | |||
| 72 | void WriteModulePc(uintptr_t module_dest) { | ||
| 73 | m_write_module_pc_relocations.push_back({c.offset(), module_dest}); | ||
| 74 | c.dx(0); | ||
| 75 | } | ||
| 76 | |||
| 77 | private: | ||
| 78 | // List of patch instructions we have generated. | ||
| 79 | std::vector<u32> m_patch_instructions{}; | ||
| 80 | |||
| 81 | // Relocation type for relative branch from module to patch. | ||
| 82 | struct Relocation { | ||
| 83 | ptrdiff_t patch_offset; ///< Offset in bytes from the start of the patch section. | ||
| 84 | uintptr_t module_offset; ///< Offset in bytes from the start of the text section. | ||
| 85 | }; | ||
| 86 | |||
| 87 | oaknut::VectorCodeGenerator c; | ||
| 88 | std::vector<Trampoline> m_trampolines; | ||
| 89 | std::vector<Relocation> m_branch_to_patch_relocations{}; | ||
| 90 | std::vector<Relocation> m_branch_to_module_relocations{}; | ||
| 91 | std::vector<Relocation> m_write_module_pc_relocations{}; | ||
| 92 | std::vector<ModuleTextAddress> m_exclusives{}; | ||
| 93 | oaknut::Label m_save_context{}; | ||
| 94 | oaknut::Label m_load_context{}; | ||
| 95 | PatchMode mode{PatchMode::None}; | ||
| 96 | }; | ||
| 97 | |||
| 98 | } // namespace Core::NCE | ||