summaryrefslogtreecommitdiff
path: root/src/core/arm/nce/patch.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm/nce/patch.h')
-rw-r--r--src/core/arm/nce/patch.h107
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 @@
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
10#pragma clang diagnostic push
11#pragma clang diagnostic ignored "-Wshorten-64-to-32"
12#include <oaknut/code_block.hpp>
13#include <oaknut/oaknut.hpp>
14#pragma clang diagnostic pop
15
16#include "common/common_types.h"
17#include "core/hle/kernel/code_set.h"
18#include "core/hle/kernel/k_typed_address.h"
19#include "core/hle/kernel/physical_memory.h"
20
21#include <signal.h>
22
23namespace Core {
24struct GuestContext;
25}
26
27namespace Core::NCE {
28
29enum class PatchMode : u32 {
30 None,
31 PreText, ///< Patch section is inserted before .text
32 PostData, ///< Patch section is inserted after .data
33};
34
35using ModuleTextAddress = u64;
36using PatchTextAddress = u64;
37using EntryTrampolines = std::unordered_map<ModuleTextAddress, PatchTextAddress>;
38
39class Patcher {
40public:
41 explicit Patcher();
42 ~Patcher();
43
44 void PatchText(const Kernel::PhysicalMemory& program_image,
45 const Kernel::CodeSet::Segment& code);
46 void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code,
47 Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines);
48 size_t SectionSize() const noexcept;
49
50 [[nodiscard]] PatchMode Mode() const noexcept {
51 return mode;
52 }
53
54private:
55 using ModuleDestLabel = uintptr_t;
56
57 struct Trampoline {
58 ptrdiff_t patch_offset;
59 uintptr_t module_offset;
60 };
61
62 void WriteLoadContext();
63 void WriteSaveContext();
64 void LockContext();
65 void UnlockContext();
66 void WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id);
67 void WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg,
68 oaknut::SystemReg src_reg);
69 void WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg);
70 void WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg);
71
72private:
73 void BranchToPatch(uintptr_t module_dest) {
74 m_branch_to_patch_relocations.push_back({c.offset(), module_dest});
75 }
76
77 void BranchToModule(uintptr_t module_dest) {
78 m_branch_to_module_relocations.push_back({c.offset(), module_dest});
79 c.dw(0);
80 }
81
82 void WriteModulePc(uintptr_t module_dest) {
83 m_write_module_pc_relocations.push_back({c.offset(), module_dest});
84 c.dx(0);
85 }
86
87private:
88 // List of patch instructions we have generated.
89 std::vector<u32> m_patch_instructions{};
90
91 // Relocation type for relative branch from module to patch.
92 struct Relocation {
93 ptrdiff_t patch_offset; ///< Offset in bytes from the start of the patch section.
94 uintptr_t module_offset; ///< Offset in bytes from the start of the text section.
95 };
96
97 oaknut::VectorCodeGenerator c;
98 std::vector<Trampoline> m_trampolines;
99 std::vector<Relocation> m_branch_to_patch_relocations{};
100 std::vector<Relocation> m_branch_to_module_relocations{};
101 std::vector<Relocation> m_write_module_pc_relocations{};
102 oaknut::Label m_save_context{};
103 oaknut::Label m_load_context{};
104 PatchMode mode{PatchMode::None};
105};
106
107} // namespace Core::NCE