summaryrefslogtreecommitdiff
path: root/src/core/arm/nce/patcher.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm/nce/patcher.h')
-rw-r--r--src/core/arm/nce/patcher.h98
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
17namespace Core::NCE {
18
19enum class PatchMode : u32 {
20 None,
21 PreText, ///< Patch section is inserted before .text
22 PostData, ///< Patch section is inserted after .data
23};
24
25using ModuleTextAddress = u64;
26using PatchTextAddress = u64;
27using EntryTrampolines = std::unordered_map<ModuleTextAddress, PatchTextAddress>;
28
29class Patcher {
30public:
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
44private:
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
62private:
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
77private:
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