diff options
| author | liamwhite <liamwhite@users.noreply.github.com> | 2023-11-30 09:20:55 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-30 09:20:55 -0500 |
| commit | 57a391e71db13ade7a3d96f59d53781eff18d2ac (patch) | |
| tree | 0b4223de40a2d77598ac9095b1374353c2e9da7c /src/core/arm/nce/patcher.h | |
| parent | 9dc9aaf4af1c3c846c9cd46a9433dcf0684da19b (diff) | |
| parent | 4a3abba16d9821ed163aab427d4c7bc9ef7acb32 (diff) | |
Merge pull request #12074 from GPUCode/yuwu-on-the-metal
Implement Native Code Execution (NCE)
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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <span> +#include <unordered_map> +#include <vector> +#include <oaknut/code_block.hpp> +#include <oaknut/oaknut.hpp> + +#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" + +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 GetSectionSize() const noexcept; + + [[nodiscard]] PatchMode GetPatchMode() 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{}; + std::vector<ModuleTextAddress> m_exclusives{}; + oaknut::Label m_save_context{}; + oaknut::Label m_load_context{}; + PatchMode mode{PatchMode::None}; +}; + +} // namespace Core::NCE |
