summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/common_types.h8
-rw-r--r--src/core/CMakeLists.txt12
-rw-r--r--src/core/arm/arm_interface.h43
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp163
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h15
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp28
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h12
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/file_sys/archive_savedata.cpp9
-rw-r--r--src/core/file_sys/archive_selfncch.cpp7
-rw-r--r--src/core/gdbstub/gdbstub.h4
-rw-r--r--src/core/hle/function_wrappers.h72
-rw-r--r--src/core/hle/kernel/mutex.cpp3
-rw-r--r--src/core/hle/kernel/mutex.h3
-rw-r--r--src/core/hle/kernel/process.cpp47
-rw-r--r--src/core/hle/kernel/process.h17
-rw-r--r--src/core/hle/kernel/semaphore.cpp3
-rw-r--r--src/core/hle/kernel/semaphore.h3
-rw-r--r--src/core/hle/kernel/thread.cpp9
-rw-r--r--src/core/hle/kernel/thread.h8
-rw-r--r--src/core/hle/kernel/vm_manager.cpp28
-rw-r--r--src/core/hle/kernel/vm_manager.h20
-rw-r--r--src/core/hle/service/apt/apt.cpp12
-rw-r--r--src/core/hle/service/csnd_snd.cpp2
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.cpp2
-rw-r--r--src/core/hle/service/sm/srv.cpp2
-rw-r--r--src/core/hle/svc.cpp158
-rw-r--r--src/core/hw/gpu.cpp18
-rw-r--r--src/core/loader/3dsx.cpp6
-rw-r--r--src/core/loader/elf.cpp16
-rw-r--r--src/core/loader/linker.cpp151
-rw-r--r--src/core/loader/linker.h37
-rw-r--r--src/core/loader/loader.cpp12
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/core/loader/ncch.cpp5
-rw-r--r--src/core/loader/nro.cpp162
-rw-r--r--src/core/loader/nro.h42
-rw-r--r--src/core/loader/nso.cpp185
-rw-r--r--src/core/loader/nso.h43
-rw-r--r--src/core/memory.cpp10
-rw-r--r--src/core/memory.h11
-rw-r--r--src/tests/core/arm/arm_test_common.cpp2
-rw-r--r--src/tests/core/hle/kernel/hle_ipc.cpp4
-rw-r--r--src/tests/core/memory/memory.cpp8
44 files changed, 1055 insertions, 351 deletions
diff --git a/src/common/common_types.h b/src/common/common_types.h
index ee18eac81..844d34965 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -24,6 +24,7 @@
24 24
25#pragma once 25#pragma once
26 26
27#include <array>
27#include <cstdint> 28#include <cstdint>
28 29
29#ifdef _MSC_VER 30#ifdef _MSC_VER
@@ -47,8 +48,11 @@ typedef double f64; ///< 64-bit floating point
47 48
48// TODO: It would be nice to eventually replace these with strong types that prevent accidental 49// TODO: It would be nice to eventually replace these with strong types that prevent accidental
49// conversion between each other. 50// conversion between each other.
50typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. 51typedef u64 VAddr; ///< Represents a pointer in the userspace virtual address space.
51typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. 52typedef u64 PAddr; ///< Represents a pointer in the ARM11 physical address space.
53
54using u128 = std::array<std::uint64_t, 2>;
55static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
52 56
53// An inheritable class to disallow the copy constructor and operator= functions 57// An inheritable class to disallow the copy constructor and operator= functions
54class NonCopyable { 58class NonCopyable {
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2618da18c..8b25eaf0a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -6,6 +6,8 @@ set(SRCS
6 arm/dyncom/arm_dyncom_interpreter.cpp 6 arm/dyncom/arm_dyncom_interpreter.cpp
7 arm/dyncom/arm_dyncom_thumb.cpp 7 arm/dyncom/arm_dyncom_thumb.cpp
8 arm/dyncom/arm_dyncom_trans.cpp 8 arm/dyncom/arm_dyncom_trans.cpp
9 arm/unicorn/arm_unicorn.cpp
10 arm/unicorn/unicorn_dynload.c
9 arm/skyeye_common/armstate.cpp 11 arm/skyeye_common/armstate.cpp
10 arm/skyeye_common/armsupp.cpp 12 arm/skyeye_common/armsupp.cpp
11 arm/skyeye_common/vfp/vfp.cpp 13 arm/skyeye_common/vfp/vfp.cpp
@@ -178,8 +180,11 @@ set(SRCS
178 hw/y2r.cpp 180 hw/y2r.cpp
179 loader/3dsx.cpp 181 loader/3dsx.cpp
180 loader/elf.cpp 182 loader/elf.cpp
183 loader/linker.cpp
181 loader/loader.cpp 184 loader/loader.cpp
182 loader/ncch.cpp 185 loader/ncch.cpp
186 loader/nro.cpp
187 loader/nso.cpp
183 loader/smdh.cpp 188 loader/smdh.cpp
184 tracer/recorder.cpp 189 tracer/recorder.cpp
185 memory.cpp 190 memory.cpp
@@ -199,6 +204,8 @@ set(HEADERS
199 arm/dyncom/arm_dyncom_run.h 204 arm/dyncom/arm_dyncom_run.h
200 arm/dyncom/arm_dyncom_thumb.h 205 arm/dyncom/arm_dyncom_thumb.h
201 arm/dyncom/arm_dyncom_trans.h 206 arm/dyncom/arm_dyncom_trans.h
207 arm/unicorn/arm_unicorn.h
208 arm/unicorn/unicorn_dynload.h
202 arm/skyeye_common/arm_regformat.h 209 arm/skyeye_common/arm_regformat.h
203 arm/skyeye_common/armstate.h 210 arm/skyeye_common/armstate.h
204 arm/skyeye_common/armsupp.h 211 arm/skyeye_common/armsupp.h
@@ -379,8 +386,11 @@ set(HEADERS
379 hw/y2r.h 386 hw/y2r.h
380 loader/3dsx.h 387 loader/3dsx.h
381 loader/elf.h 388 loader/elf.h
389 loader/linker.h
382 loader/loader.h 390 loader/loader.h
383 loader/ncch.h 391 loader/ncch.h
392 loader/nro.h
393 loader/nso.h
384 loader/smdh.h 394 loader/smdh.h
385 tracer/recorder.h 395 tracer/recorder.h
386 tracer/citrace.h 396 tracer/citrace.h
@@ -395,7 +405,7 @@ set(HEADERS
395create_directory_groups(${SRCS} ${HEADERS}) 405create_directory_groups(${SRCS} ${HEADERS})
396add_library(core STATIC ${SRCS} ${HEADERS}) 406add_library(core STATIC ${SRCS} ${HEADERS})
397target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core) 407target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
398target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt) 408target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt lz4_static)
399if (ENABLE_WEB_SERVICE) 409if (ENABLE_WEB_SERVICE)
400 target_link_libraries(core PUBLIC json-headers web_service) 410 target_link_libraries(core PUBLIC json-headers web_service)
401endif() 411endif()
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index ba528403c..0b3096347 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/vm_manager.h"
8#include "core/arm/skyeye_common/arm_regformat.h" 9#include "core/arm/skyeye_common/arm_regformat.h"
9#include "core/arm/skyeye_common/vfp/asm_vfp.h" 10#include "core/arm/skyeye_common/vfp/asm_vfp.h"
10 11
@@ -14,14 +15,18 @@ public:
14 virtual ~ARM_Interface() {} 15 virtual ~ARM_Interface() {}
15 16
16 struct ThreadContext { 17 struct ThreadContext {
17 u32 cpu_registers[13]; 18 u64 cpu_registers[30];
18 u32 sp; 19 u64 lr;
19 u32 lr; 20 u64 sp;
20 u32 pc; 21 u64 pc;
21 u32 cpsr; 22 u64 cpsr;
22 u32 fpu_registers[64]; 23 u128 fpu_registers[32];
23 u32 fpscr; 24 u64 fpscr;
24 u32 fpexc; 25 u64 fpexc;
26
27
28 // TODO(bunnei): Fix once we have proper support for tpidrro_el0, etc. in the JIT
29 VAddr tls_address;
25 }; 30 };
26 31
27 /** 32 /**
@@ -38,6 +43,8 @@ public:
38 Run(1); 43 Run(1);
39 } 44 }
40 45
46 virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) {}
47
41 /// Clear all instruction cache 48 /// Clear all instruction cache
42 virtual void ClearInstructionCache() = 0; 49 virtual void ClearInstructionCache() = 0;
43 50
@@ -48,27 +55,31 @@ public:
48 * Set the Program Counter to an address 55 * Set the Program Counter to an address
49 * @param addr Address to set PC to 56 * @param addr Address to set PC to
50 */ 57 */
51 virtual void SetPC(u32 addr) = 0; 58 virtual void SetPC(u64 addr) = 0;
52 59
53 /* 60 /*
54 * Get the current Program Counter 61 * Get the current Program Counter
55 * @return Returns current PC 62 * @return Returns current PC
56 */ 63 */
57 virtual u32 GetPC() const = 0; 64 virtual u64 GetPC() const = 0;
58 65
59 /** 66 /**
60 * Get an ARM register 67 * Get an ARM register
61 * @param index Register index (0-15) 68 * @param index Register index
62 * @return Returns the value in the register 69 * @return Returns the value in the register
63 */ 70 */
64 virtual u32 GetReg(int index) const = 0; 71 virtual u64 GetReg(int index) const = 0;
65 72
66 /** 73 /**
67 * Set an ARM register 74 * Set an ARM register
68 * @param index Register index (0-15) 75 * @param index Register index
69 * @param value Value to set register to 76 * @param value Value to set register to
70 */ 77 */
71 virtual void SetReg(int index, u32 value) = 0; 78 virtual void SetReg(int index, u64 value) = 0;
79
80 virtual const u128& GetExtReg(int index) const = 0;
81
82 virtual void SetExtReg(int index, u128& value) = 0;
72 83
73 /** 84 /**
74 * Gets the value of a VFP register 85 * Gets the value of a VFP register
@@ -124,6 +135,10 @@ public:
124 */ 135 */
125 virtual void SetCP15Register(CP15Register reg, u32 value) = 0; 136 virtual void SetCP15Register(CP15Register reg, u32 value) = 0;
126 137
138 virtual VAddr GetTlsAddress() const = 0;
139
140 virtual void SetTlsAddress(VAddr address) = 0;
141
127 /** 142 /**
128 * Saves the current CPU context 143 * Saves the current CPU context
129 * @param ctx Thread context to save 144 * @param ctx Thread context to save
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 2cb56d12f..6dcab5bab 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -14,98 +14,108 @@
14#include "core/hle/svc.h" 14#include "core/hle/svc.h"
15#include "core/memory.h" 15#include "core/memory.h"
16 16
17static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void* user_arg) { 17static void InterpreterFallback(u64 pc, Dynarmic::Jit* jit, void* user_arg) {
18 ARMul_State* state = static_cast<ARMul_State*>(user_arg); 18 UNIMPLEMENTED_MSG("InterpreterFallback for ARM64 JIT does not exist!");
19}
19 20
20 state->Reg = jit->Regs(); 21static bool IsReadOnlyMemory(u64 vaddr) {
21 state->Cpsr = jit->Cpsr(); 22 // TODO(bunnei): ImplementMe
22 state->Reg[15] = pc; 23 return false;
23 state->ExtReg = jit->ExtRegs(); 24}
24 state->VFP[VFP_FPSCR] = jit->Fpscr();
25 state->NumInstrsToExecute = 1;
26 25
27 InterpreterMainLoop(state); 26u8 MemoryRead8(const u64 addr) {
27 return Memory::Read8(static_cast<VAddr>(addr));
28}
28 29
29 bool is_thumb = (state->Cpsr & (1 << 5)) != 0; 30u16 MemoryRead16(const u64 addr) {
30 state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC); 31 return Memory::Read16(static_cast<VAddr>(addr));
32}
31 33
32 jit->Regs() = state->Reg; 34u32 MemoryRead32(const u64 addr) {
33 jit->Cpsr() = state->Cpsr; 35 return Memory::Read32(static_cast<VAddr>(addr));
34 jit->ExtRegs() = state->ExtReg;
35 jit->SetFpscr(state->VFP[VFP_FPSCR]);
36} 36}
37 37
38static bool IsReadOnlyMemory(u32 vaddr) { 38u64 MemoryRead64(const u64 addr) {
39 // TODO(bunnei): ImplementMe 39 return Memory::Read64(static_cast<VAddr>(addr));
40 return false; 40}
41
42void MemoryWrite8(const u64 addr, const u8 data) {
43 Memory::Write8(static_cast<VAddr>(addr), data);
44}
45
46void MemoryWrite16(const u64 addr, const u16 data) {
47 Memory::Write16(static_cast<VAddr>(addr), data);
48}
49
50void MemoryWrite32(const u64 addr, const u32 data) {
51 Memory::Write32(static_cast<VAddr>(addr), data);
52}
53
54void MemoryWrite64(const u64 addr, const u64 data) {
55 Memory::Write64(static_cast<VAddr>(addr), data);
41} 56}
42 57
43static Dynarmic::UserCallbacks GetUserCallbacks( 58static Dynarmic::UserCallbacks GetUserCallbacks(ARM_Dynarmic* this_) {
44 const std::shared_ptr<ARMul_State>& interpeter_state, Memory::PageTable* current_page_table) {
45 Dynarmic::UserCallbacks user_callbacks{}; 59 Dynarmic::UserCallbacks user_callbacks{};
46 user_callbacks.InterpreterFallback = &InterpreterFallback; 60 user_callbacks.InterpreterFallback = &InterpreterFallback;
47 user_callbacks.user_arg = static_cast<void*>(interpeter_state.get()); 61 user_callbacks.user_arg = static_cast<void*>(this_);
48 user_callbacks.CallSVC = &SVC::CallSVC; 62 user_callbacks.CallSVC = &SVC::CallSVC;
49 user_callbacks.memory.IsReadOnlyMemory = &IsReadOnlyMemory; 63 user_callbacks.memory.IsReadOnlyMemory = &IsReadOnlyMemory;
50 user_callbacks.memory.ReadCode = &Memory::Read32; 64 user_callbacks.memory.ReadCode = &MemoryRead32;
51 user_callbacks.memory.Read8 = &Memory::Read8; 65 user_callbacks.memory.Read8 = &MemoryRead8;
52 user_callbacks.memory.Read16 = &Memory::Read16; 66 user_callbacks.memory.Read16 = &MemoryRead16;
53 user_callbacks.memory.Read32 = &Memory::Read32; 67 user_callbacks.memory.Read32 = &MemoryRead32;
54 user_callbacks.memory.Read64 = &Memory::Read64; 68 user_callbacks.memory.Read64 = &MemoryRead64;
55 user_callbacks.memory.Write8 = &Memory::Write8; 69 user_callbacks.memory.Write8 = &MemoryWrite8;
56 user_callbacks.memory.Write16 = &Memory::Write16; 70 user_callbacks.memory.Write16 = &MemoryWrite16;
57 user_callbacks.memory.Write32 = &Memory::Write32; 71 user_callbacks.memory.Write32 = &MemoryWrite32;
58 user_callbacks.memory.Write64 = &Memory::Write64; 72 user_callbacks.memory.Write64 = &MemoryWrite64;
59 user_callbacks.page_table = &current_page_table->pointers; 73 //user_callbacks.page_table = Memory::GetCurrentPageTablePointers();
60 user_callbacks.coprocessors[15] = std::make_shared<DynarmicCP15>(interpeter_state);
61 return user_callbacks; 74 return user_callbacks;
62} 75}
63 76
64ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) { 77ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) {
65 interpreter_state = std::make_shared<ARMul_State>(initial_mode);
66 PageTableChanged();
67} 78}
68 79
69void ARM_Dynarmic::SetPC(u32 pc) { 80void ARM_Dynarmic::MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) {
70 jit->Regs()[15] = pc; 81}
82
83void ARM_Dynarmic::SetPC(u64 pc) {
84 jit->Regs64()[32] = pc;
85}
86
87u64 ARM_Dynarmic::GetPC() const {
88 return jit->Regs64()[32];
89}
90
91u64 ARM_Dynarmic::GetReg(int index) const {
92 return jit->Regs64()[index];
71} 93}
72 94
73u32 ARM_Dynarmic::GetPC() const { 95void ARM_Dynarmic::SetReg(int index, u64 value) {
74 return jit->Regs()[15]; 96 jit->Regs64()[index] = value;
75} 97}
76 98
77u32 ARM_Dynarmic::GetReg(int index) const { 99const u128& ARM_Dynarmic::GetExtReg(int index) const {
78 return jit->Regs()[index]; 100 return jit->ExtRegs64()[index];
79} 101}
80 102
81void ARM_Dynarmic::SetReg(int index, u32 value) { 103void ARM_Dynarmic::SetExtReg(int index, u128& value) {
82 jit->Regs()[index] = value; 104 jit->ExtRegs64()[index] = value;
83} 105}
84 106
85u32 ARM_Dynarmic::GetVFPReg(int index) const { 107u32 ARM_Dynarmic::GetVFPReg(int index) const {
86 return jit->ExtRegs()[index]; 108 return {};
87} 109}
88 110
89void ARM_Dynarmic::SetVFPReg(int index, u32 value) { 111void ARM_Dynarmic::SetVFPReg(int index, u32 value) {
90 jit->ExtRegs()[index] = value;
91} 112}
92 113
93u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const { 114u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const {
94 if (reg == VFP_FPSCR) { 115 return {};
95 return jit->Fpscr();
96 }
97
98 // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state
99 return interpreter_state->VFP[reg];
100} 116}
101 117
102void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { 118void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) {
103 if (reg == VFP_FPSCR) {
104 jit->SetFpscr(value);
105 }
106
107 // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state
108 interpreter_state->VFP[reg] = value;
109} 119}
110 120
111u32 ARM_Dynarmic::GetCPSR() const { 121u32 ARM_Dynarmic::GetCPSR() const {
@@ -117,11 +127,18 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) {
117} 127}
118 128
119u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) { 129u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) {
120 return interpreter_state->CP15[reg]; 130 return {};
121} 131}
122 132
123void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { 133void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {
124 interpreter_state->CP15[reg] = value; 134}
135
136VAddr ARM_Dynarmic::GetTlsAddress() const {
137 return jit->TlsAddr();
138}
139
140void ARM_Dynarmic::SetTlsAddress(VAddr address) {
141 jit->TlsAddr() = address;
125} 142}
126 143
127MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); 144MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
@@ -136,29 +153,29 @@ void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
136} 153}
137 154
138void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { 155void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
139 memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers)); 156 memcpy(ctx.cpu_registers, jit->Regs64().data(), sizeof(ctx.cpu_registers));
140 memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers)); 157 memcpy(ctx.fpu_registers, jit->ExtRegs64().data(), sizeof(ctx.fpu_registers));
141 158
142 ctx.sp = jit->Regs()[13]; 159 ctx.lr = jit->Regs64()[30];
143 ctx.lr = jit->Regs()[14]; 160 ctx.sp = jit->Regs64()[31];
144 ctx.pc = jit->Regs()[15]; 161 ctx.pc = jit->Regs64()[32];
145 ctx.cpsr = jit->Cpsr(); 162 ctx.cpsr = jit->Cpsr();
146 163
147 ctx.fpscr = jit->Fpscr(); 164 // TODO(bunnei): Fix once we have proper support for tpidrro_el0, etc. in the JIT
148 ctx.fpexc = interpreter_state->VFP[VFP_FPEXC]; 165 ctx.tls_address = jit->TlsAddr();
149} 166}
150 167
151void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { 168void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
152 memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); 169 memcpy(jit->Regs64().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
153 memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); 170 memcpy(jit->ExtRegs64().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
154 171
155 jit->Regs()[13] = ctx.sp; 172 jit->Regs64()[30] = ctx.lr;
156 jit->Regs()[14] = ctx.lr; 173 jit->Regs64()[31] = ctx.sp;
157 jit->Regs()[15] = ctx.pc; 174 jit->Regs64()[32] = ctx.pc;
158 jit->Cpsr() = ctx.cpsr; 175 jit->Cpsr() = ctx.cpsr;
159 176
160 jit->SetFpscr(ctx.fpscr); 177 // TODO(bunnei): Fix once we have proper support for tpidrro_el0, etc. in the JIT
161 interpreter_state->VFP[VFP_FPEXC] = ctx.fpexc; 178 jit->TlsAddr() = ctx.tls_address;
162} 179}
163 180
164void ARM_Dynarmic::PrepareReschedule() { 181void ARM_Dynarmic::PrepareReschedule() {
@@ -180,6 +197,6 @@ void ARM_Dynarmic::PageTableChanged() {
180 return; 197 return;
181 } 198 }
182 199
183 jit = new Dynarmic::Jit(GetUserCallbacks(interpreter_state, current_page_table)); 200 jit = new Dynarmic::Jit(GetUserCallbacks(this), Dynarmic::Arch::ARM64);
184 jits.emplace(current_page_table, std::unique_ptr<Dynarmic::Jit>(jit)); 201 jits.emplace(current_page_table, std::unique_ptr<Dynarmic::Jit>(jit));
185} 202}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 0b00158a5..6567359b0 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -19,10 +19,14 @@ class ARM_Dynarmic final : public ARM_Interface {
19public: 19public:
20 ARM_Dynarmic(PrivilegeMode initial_mode); 20 ARM_Dynarmic(PrivilegeMode initial_mode);
21 21
22 void SetPC(u32 pc) override; 22 void MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) override;
23 u32 GetPC() const override; 23
24 u32 GetReg(int index) const override; 24 void SetPC(u64 pc) override;
25 void SetReg(int index, u32 value) override; 25 u64 GetPC() const override;
26 u64 GetReg(int index) const override;
27 void SetReg(int index, u64 value) override;
28 const u128& GetExtReg(int index) const override;
29 void SetExtReg(int index, u128& value) override;
26 u32 GetVFPReg(int index) const override; 30 u32 GetVFPReg(int index) const override;
27 void SetVFPReg(int index, u32 value) override; 31 void SetVFPReg(int index, u32 value) override;
28 u32 GetVFPSystemReg(VFPSystemRegister reg) const override; 32 u32 GetVFPSystemReg(VFPSystemRegister reg) const override;
@@ -31,6 +35,8 @@ public:
31 void SetCPSR(u32 cpsr) override; 35 void SetCPSR(u32 cpsr) override;
32 u32 GetCP15Register(CP15Register reg) override; 36 u32 GetCP15Register(CP15Register reg) override;
33 void SetCP15Register(CP15Register reg, u32 value) override; 37 void SetCP15Register(CP15Register reg, u32 value) override;
38 VAddr GetTlsAddress() const override;
39 void SetTlsAddress(VAddr address) override;
34 40
35 void SaveContext(ThreadContext& ctx) override; 41 void SaveContext(ThreadContext& ctx) override;
36 void LoadContext(const ThreadContext& ctx) override; 42 void LoadContext(const ThreadContext& ctx) override;
@@ -45,5 +51,4 @@ private:
45 Dynarmic::Jit* jit = nullptr; 51 Dynarmic::Jit* jit = nullptr;
46 Memory::PageTable* current_page_table = nullptr; 52 Memory::PageTable* current_page_table = nullptr;
47 std::map<Memory::PageTable*, std::unique_ptr<Dynarmic::Jit>> jits; 53 std::map<Memory::PageTable*, std::unique_ptr<Dynarmic::Jit>> jits;
48 std::shared_ptr<ARMul_State> interpreter_state;
49}; 54};
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 4d72aef77..5ebf7a2f1 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -25,26 +25,33 @@ void ARM_DynCom::ClearInstructionCache() {
25 trans_cache_buf_top = 0; 25 trans_cache_buf_top = 0;
26} 26}
27 27
28void ARM_DynCom::PageTableChanged() { 28void ARM_DynCom::SetPC(u64 pc) {
29 ClearInstructionCache(); 29 state->Reg[15] = pc;
30} 30}
31 31
32void ARM_DynCom::SetPC(u32 pc) { 32void ARM_DynCom::PageTableChanged() {
33 state->Reg[15] = pc; 33 ClearInstructionCache();
34} 34}
35 35
36u32 ARM_DynCom::GetPC() const { 36u64 ARM_DynCom::GetPC() const {
37 return state->Reg[15]; 37 return state->Reg[15];
38} 38}
39 39
40u32 ARM_DynCom::GetReg(int index) const { 40u64 ARM_DynCom::GetReg(int index) const {
41 return state->Reg[index]; 41 return state->Reg[index];
42} 42}
43 43
44void ARM_DynCom::SetReg(int index, u32 value) { 44void ARM_DynCom::SetReg(int index, u64 value) {
45 state->Reg[index] = value; 45 state->Reg[index] = value;
46} 46}
47 47
48const u128& ARM_DynCom::GetExtReg(int index) const {
49 return {};
50}
51
52void ARM_DynCom::SetExtReg(int index, u128& value) {
53}
54
48u32 ARM_DynCom::GetVFPReg(int index) const { 55u32 ARM_DynCom::GetVFPReg(int index) const {
49 return state->ExtReg[index]; 56 return state->ExtReg[index];
50} 57}
@@ -77,6 +84,13 @@ void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) {
77 state->CP15[reg] = value; 84 state->CP15[reg] = value;
78} 85}
79 86
87VAddr ARM_DynCom::GetTlsAddress() const {
88 return {};
89}
90
91void ARM_DynCom::SetTlsAddress(VAddr /*address*/) {
92}
93
80void ARM_DynCom::ExecuteInstructions(int num_instructions) { 94void ARM_DynCom::ExecuteInstructions(int num_instructions) {
81 state->NumInstrsToExecute = num_instructions; 95 state->NumInstrsToExecute = num_instructions;
82 96
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index fc1ffed6a..cc3c0f3da 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -18,10 +18,12 @@ public:
18 void ClearInstructionCache() override; 18 void ClearInstructionCache() override;
19 void PageTableChanged() override; 19 void PageTableChanged() override;
20 20
21 void SetPC(u32 pc) override; 21 void SetPC(u64 pc) override;
22 u32 GetPC() const override; 22 u64 GetPC() const override;
23 u32 GetReg(int index) const override; 23 u64 GetReg(int index) const override;
24 void SetReg(int index, u32 value) override; 24 void SetReg(int index, u64 value) override;
25 const u128& GetExtReg(int index) const override;
26 void SetExtReg(int index, u128& value) override;
25 u32 GetVFPReg(int index) const override; 27 u32 GetVFPReg(int index) const override;
26 void SetVFPReg(int index, u32 value) override; 28 void SetVFPReg(int index, u32 value) override;
27 u32 GetVFPSystemReg(VFPSystemRegister reg) const override; 29 u32 GetVFPSystemReg(VFPSystemRegister reg) const override;
@@ -30,6 +32,8 @@ public:
30 void SetCPSR(u32 cpsr) override; 32 void SetCPSR(u32 cpsr) override;
31 u32 GetCP15Register(CP15Register reg) override; 33 u32 GetCP15Register(CP15Register reg) override;
32 void SetCP15Register(CP15Register reg, u32 value) override; 34 void SetCP15Register(CP15Register reg, u32 value) override;
35 VAddr GetTlsAddress() const override;
36 void SetTlsAddress(VAddr address) override;
33 37
34 void SaveContext(ThreadContext& ctx) override; 38 void SaveContext(ThreadContext& ctx) override;
35 void LoadContext(const ThreadContext& ctx) override; 39 void LoadContext(const ThreadContext& ctx) override;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0c7a72987..c5448630f 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -9,6 +9,7 @@
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
10#include "core/arm/dynarmic/arm_dynarmic.h" 10#include "core/arm/dynarmic/arm_dynarmic.h"
11#include "core/arm/dyncom/arm_dyncom.h" 11#include "core/arm/dyncom/arm_dyncom.h"
12#include "core/arm/unicorn/arm_unicorn.h"
12#include "core/core.h" 13#include "core/core.h"
13#include "core/core_timing.h" 14#include "core/core_timing.h"
14#include "core/gdbstub/gdbstub.h" 15#include "core/gdbstub/gdbstub.h"
@@ -115,7 +116,6 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
115 return ResultStatus::ErrorLoader; 116 return ResultStatus::ErrorLoader;
116 } 117 }
117 } 118 }
118 Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
119 status = ResultStatus::Success; 119 status = ResultStatus::Success;
120 return status; 120 return status;
121} 121}
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 61f7654f7..67076c73f 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -15,16 +15,19 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(
15 : sd_savedata_source(sd_savedata) {} 15 : sd_savedata_source(sd_savedata) {}
16 16
17ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { 17ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
18 return sd_savedata_source->Open(Kernel::g_current_process->codeset->program_id); 18 UNIMPLEMENTED();
19 return {}; //sd_savedata_source->Open(Kernel::g_current_process->codeset->program_id);
19} 20}
20 21
21ResultCode ArchiveFactory_SaveData::Format(const Path& path, 22ResultCode ArchiveFactory_SaveData::Format(const Path& path,
22 const FileSys::ArchiveFormatInfo& format_info) { 23 const FileSys::ArchiveFormatInfo& format_info) {
23 return sd_savedata_source->Format(Kernel::g_current_process->codeset->program_id, format_info); 24 UNIMPLEMENTED();
25 return RESULT_SUCCESS; //sd_savedata_source->Format(Kernel::g_current_process->codeset->program_id, format_info);
24} 26}
25 27
26ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const { 28ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
27 return sd_savedata_source->GetFormatInfo(Kernel::g_current_process->codeset->program_id); 29 UNIMPLEMENTED();
30 return {}; //sd_savedata_source->GetFormatInfo(Kernel::g_current_process->codeset->program_id);
28} 31}
29 32
30} // namespace FileSys 33} // namespace FileSys
diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp
index a16941c70..3222000cf 100644
--- a/src/core/file_sys/archive_selfncch.cpp
+++ b/src/core/file_sys/archive_selfncch.cpp
@@ -278,9 +278,10 @@ void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) {
278} 278}
279 279
280ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) { 280ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) {
281 auto archive = std::make_unique<SelfNCCHArchive>( 281 //auto archive = std::make_unique<SelfNCCHArchive>(
282 ncch_data[Kernel::g_current_process->codeset->program_id]); 282 // ncch_data[Kernel::g_current_process->codeset->program_id]);
283 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 283 //return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
284 return {};
284} 285}
285 286
286ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) { 287ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) {
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index 38177e32c..8f12c6a1d 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -69,7 +69,7 @@ void HandlePacket();
69 * @param addr Address to search from. 69 * @param addr Address to search from.
70 * @param type Type of breakpoint. 70 * @param type Type of breakpoint.
71 */ 71 */
72BreakpointAddress GetNextBreakpointFromAddress(u32 addr, GDBStub::BreakpointType type); 72BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointType type);
73 73
74/** 74/**
75 * Check if a breakpoint of the specified type exists at the given address. 75 * Check if a breakpoint of the specified type exists at the given address.
@@ -77,7 +77,7 @@ BreakpointAddress GetNextBreakpointFromAddress(u32 addr, GDBStub::BreakpointType
77 * @param addr Address of breakpoint. 77 * @param addr Address of breakpoint.
78 * @param type Type of breakpoint. 78 * @param type Type of breakpoint.
79 */ 79 */
80bool CheckBreakpoint(u32 addr, GDBStub::BreakpointType type); 80bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type);
81 81
82// If set to true, the CPU will halt at the beginning of the next CPU loop. 82// If set to true, the CPU will halt at the beginning of the next CPU loop.
83bool GetCpuHaltFlag(); 83bool GetCpuHaltFlag();
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index f93439f21..31fda6db3 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -20,23 +20,41 @@ namespace HLE {
20 * HLE a function return from the current ARM11 userland process 20 * HLE a function return from the current ARM11 userland process
21 * @param res Result to return 21 * @param res Result to return
22 */ 22 */
23static inline void FuncReturn(u32 res) { 23static inline void FuncReturn(u64 res) {
24 Core::CPU().SetReg(0, res); 24 Core::CPU().SetReg(0, res);
25} 25}
26 26
27/**
28 * HLE a function return (64-bit) from the current ARM11 userland process
29 * @param res Result to return (64-bit)
30 * @todo Verify that this function is correct
31 */
32static inline void FuncReturn64(u64 res) {
33 Core::CPU().SetReg(0, (u32)(res & 0xFFFFFFFF));
34 Core::CPU().SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF));
35}
36
37//////////////////////////////////////////////////////////////////////////////////////////////////// 27////////////////////////////////////////////////////////////////////////////////////////////////////
38// Function wrappers that return type ResultCode 28// Function wrappers that return type ResultCode
39 29
30template <ResultCode func(u64)>
31void Wrap() {
32 FuncReturn(func(PARAM(0)).raw);
33}
34
35template <ResultCode func(u32, u64, u32)>
36void Wrap() {
37 FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw);
38}
39
40template <ResultCode func(u64, u32)>
41void Wrap() {
42 FuncReturn(func(PARAM(0), PARAM(1)).raw);
43}
44
45template <ResultCode func(u64, u64, u64)>
46void Wrap() {
47 FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw);
48}
49
50template <ResultCode func(u64*, u64, u64, u64)>
51void Wrap() {
52 u64 param_1 = 0;
53 u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3)).raw;
54 Core::CPU().SetReg(1, param_1);
55 FuncReturn(retval);
56}
57
40template <ResultCode func(u32, u32, u32, u32)> 58template <ResultCode func(u32, u32, u32, u32)>
41void Wrap() { 59void Wrap() {
42 FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw); 60 FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw);
@@ -84,6 +102,14 @@ void Wrap() {
84 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw); 102 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw);
85} 103}
86 104
105template <ResultCode func(u32, u64*)>
106void Wrap() {
107 u64 param_1 = 0;
108 u32 retval = func(PARAM(0), &param_1).raw;
109 Core::CPU().SetReg(1, param_1);
110 FuncReturn(retval);
111}
112
87template <ResultCode func(u32*)> 113template <ResultCode func(u32*)>
88void Wrap() { 114void Wrap() {
89 u32 param_1 = 0; 115 u32 param_1 = 0;
@@ -99,16 +125,17 @@ void Wrap() {
99 FuncReturn(retval); 125 FuncReturn(retval);
100} 126}
101 127
102template <ResultCode func(MemoryInfo*, PageInfo*, u32)> 128template <ResultCode func(MemoryInfo*, PageInfo*, u64)>
103void Wrap() { 129void Wrap() {
104 MemoryInfo memory_info = {}; 130 MemoryInfo memory_info = {};
105 PageInfo page_info = {}; 131 PageInfo page_info = {};
106 u32 retval = func(&memory_info, &page_info, PARAM(2)).raw; 132 u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
107 Core::CPU().SetReg(1, memory_info.base_address); 133
108 Core::CPU().SetReg(2, memory_info.size); 134 Memory::Write64(PARAM(0), memory_info.base_address);
109 Core::CPU().SetReg(3, memory_info.permission); 135 Memory::Write64(PARAM(0) + 8, memory_info.size);
110 Core::CPU().SetReg(4, memory_info.state); 136 Memory::Write64(PARAM(0) + 16, memory_info.permission);
111 Core::CPU().SetReg(5, page_info.flags); 137 Memory::Write64(PARAM(0) + 24, memory_info.state);
138
112 FuncReturn(retval); 139 FuncReturn(retval);
113} 140}
114 141
@@ -138,7 +165,7 @@ void Wrap() {
138 FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw); 165 FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw);
139} 166}
140 167
141template <ResultCode func(u32*, u32)> 168template <ResultCode func(u32*, u64)>
142void Wrap() { 169void Wrap() {
143 u32 param_1 = 0; 170 u32 param_1 = 0;
144 u32 retval = func(&param_1, PARAM(1)).raw; 171 u32 retval = func(&param_1, PARAM(1)).raw;
@@ -226,6 +253,11 @@ void Wrap() {
226 FuncReturn(retval); 253 FuncReturn(retval);
227} 254}
228 255
256template <ResultCode func(u32, u32, u32)>
257void Wrap() {
258 FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw);
259}
260
229//////////////////////////////////////////////////////////////////////////////////////////////////// 261////////////////////////////////////////////////////////////////////////////////////////////////////
230// Function wrappers that return type u32 262// Function wrappers that return type u32
231 263
@@ -255,9 +287,9 @@ void Wrap() {
255 func(PARAM(0), PARAM(1)); 287 func(PARAM(0), PARAM(1));
256} 288}
257 289
258template <void func(u8)> 290template <void func(u64, u64, u64)>
259void Wrap() { 291void Wrap() {
260 func((u8)PARAM(0)); 292 func(PARAM(0), PARAM(1), PARAM(2));
261} 293}
262 294
263#undef PARAM 295#undef PARAM
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 2cbca5e5b..30dade552 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -25,10 +25,11 @@ void ReleaseThreadMutexes(Thread* thread) {
25Mutex::Mutex() {} 25Mutex::Mutex() {}
26Mutex::~Mutex() {} 26Mutex::~Mutex() {}
27 27
28SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { 28SharedPtr<Mutex> Mutex::Create(bool initial_locked, VAddr addr, std::string name) {
29 SharedPtr<Mutex> mutex(new Mutex); 29 SharedPtr<Mutex> mutex(new Mutex);
30 30
31 mutex->lock_count = 0; 31 mutex->lock_count = 0;
32 mutex->addr = addr;
32 mutex->name = std::move(name); 33 mutex->name = std::move(name);
33 mutex->holding_thread = nullptr; 34 mutex->holding_thread = nullptr;
34 35
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index bacacd690..503d3ee75 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -21,7 +21,7 @@ public:
21 * @param name Optional name of mutex 21 * @param name Optional name of mutex
22 * @return Pointer to new Mutex object 22 * @return Pointer to new Mutex object
23 */ 23 */
24 static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown"); 24 static SharedPtr<Mutex> Create(bool initial_locked, VAddr addr, std::string name = "Unknown");
25 25
26 std::string GetTypeName() const override { 26 std::string GetTypeName() const override {
27 return "Mutex"; 27 return "Mutex";
@@ -39,6 +39,7 @@ public:
39 u32 priority; ///< The priority of the mutex, used for priority inheritance. 39 u32 priority; ///< The priority of the mutex, used for priority inheritance.
40 std::string name; ///< Name of mutex (optional) 40 std::string name; ///< Name of mutex (optional)
41 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex 41 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
42 VAddr addr;
42 43
43 /** 44 /**
44 * Elevate the mutex priority to the best priority 45 * Elevate the mutex priority to the best priority
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index cf3163e0f..9e145866f 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -30,10 +30,10 @@ CodeSet::~CodeSet() {}
30 30
31u32 Process::next_process_id; 31u32 Process::next_process_id;
32 32
33SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) { 33SharedPtr<Process> Process::Create(std::string&& name) {
34 SharedPtr<Process> process(new Process); 34 SharedPtr<Process> process(new Process);
35 35
36 process->codeset = std::move(code_set); 36 process->name = std::move(name);
37 process->flags.raw = 0; 37 process->flags.raw = 0;
38 process->flags.memory_region.Assign(MemoryRegion::APPLICATION); 38 process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
39 39
@@ -112,25 +112,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
112 } 112 }
113} 113}
114 114
115void Process::Run(s32 main_thread_priority, u32 stack_size) { 115void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
116 memory_region = GetMemoryRegion(flags.memory_region);
117
118 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
119 MemoryState memory_state) {
120 auto vma = vm_manager
121 .MapMemoryBlock(segment.addr, codeset->memory, segment.offset, segment.size,
122 memory_state)
123 .Unwrap();
124 vm_manager.Reprotect(vma, permissions);
125 misc_memory_used += segment.size;
126 memory_region->used += segment.size;
127 };
128
129 // Map CodeSet segments
130 MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
131 MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
132 MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
133
134 // Allocate and map stack 116 // Allocate and map stack
135 vm_manager 117 vm_manager
136 .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, 118 .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
@@ -147,7 +129,28 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
147 } 129 }
148 130
149 vm_manager.LogLayout(Log::Level::Debug); 131 vm_manager.LogLayout(Log::Level::Debug);
150 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority, this); 132
133 Kernel::SetupMainThread(entry_point, main_thread_priority, this);
134}
135
136void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
137 memory_region = GetMemoryRegion(flags.memory_region);
138
139 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
140 MemoryState memory_state) {
141 auto vma = vm_manager
142 .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, segment.size,
143 memory_state)
144 .Unwrap();
145 vm_manager.Reprotect(vma, permissions);
146 misc_memory_used += segment.size;
147 memory_region->used += segment.size;
148 };
149
150 // Map CodeSet segments
151 MapSegment(module_->code, VMAPermission::ReadWrite, MemoryState::Private);
152 MapSegment(module_->rodata, VMAPermission::Read, MemoryState::Static);
153 MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::Static);
151} 154}
152 155
153VAddr Process::GetLinearHeapAreaAddress() const { 156VAddr Process::GetLinearHeapAreaAddress() const {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index b52211d2a..f05f2703e 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -79,7 +79,11 @@ struct CodeSet final : public Object {
79 u32 size = 0; 79 u32 size = 0;
80 }; 80 };
81 81
82 Segment code, rodata, data; 82 Segment segments[3];
83 Segment& code = segments[0];
84 Segment& rodata = segments[1];
85 Segment& data = segments[2];
86
83 VAddr entrypoint; 87 VAddr entrypoint;
84 88
85private: 89private:
@@ -89,13 +93,13 @@ private:
89 93
90class Process final : public Object { 94class Process final : public Object {
91public: 95public:
92 static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set); 96 static SharedPtr<Process> Create(std::string&& name);
93 97
94 std::string GetTypeName() const override { 98 std::string GetTypeName() const override {
95 return "Process"; 99 return "Process";
96 } 100 }
97 std::string GetName() const override { 101 std::string GetName() const override {
98 return codeset->name; 102 return name;
99 } 103 }
100 104
101 static const HandleType HANDLE_TYPE = HandleType::Process; 105 static const HandleType HANDLE_TYPE = HandleType::Process;
@@ -105,7 +109,6 @@ public:
105 109
106 static u32 next_process_id; 110 static u32 next_process_id;
107 111
108 SharedPtr<CodeSet> codeset;
109 /// Resource limit descriptor for this process 112 /// Resource limit descriptor for this process
110 SharedPtr<ResourceLimit> resource_limit; 113 SharedPtr<ResourceLimit> resource_limit;
111 114
@@ -134,7 +137,9 @@ public:
134 /** 137 /**
135 * Applies address space changes and launches the process main thread. 138 * Applies address space changes and launches the process main thread.
136 */ 139 */
137 void Run(s32 main_thread_priority, u32 stack_size); 140 void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
141
142 void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr);
138 143
139 /////////////////////////////////////////////////////////////////////////////////////////////// 144 ///////////////////////////////////////////////////////////////////////////////////////////////
140 // Memory Management 145 // Memory Management
@@ -160,6 +165,8 @@ public:
160 /// This vector will grow as more pages are allocated for new threads. 165 /// This vector will grow as more pages are allocated for new threads.
161 std::vector<std::bitset<8>> tls_slots; 166 std::vector<std::bitset<8>> tls_slots;
162 167
168 std::string name;
169
163 VAddr GetLinearHeapAreaAddress() const; 170 VAddr GetLinearHeapAreaAddress() const;
164 VAddr GetLinearHeapBase() const; 171 VAddr GetLinearHeapBase() const;
165 VAddr GetLinearHeapLimit() const; 172 VAddr GetLinearHeapLimit() const;
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index fcf586728..2605b2595 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -13,7 +13,7 @@ namespace Kernel {
13Semaphore::Semaphore() {} 13Semaphore::Semaphore() {}
14Semaphore::~Semaphore() {} 14Semaphore::~Semaphore() {}
15 15
16ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, 16ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, VAddr address,
17 std::string name) { 17 std::string name) {
18 18
19 if (initial_count > max_count) 19 if (initial_count > max_count)
@@ -25,6 +25,7 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou
25 // and the rest is reserved for the caller thread 25 // and the rest is reserved for the caller thread
26 semaphore->max_count = max_count; 26 semaphore->max_count = max_count;
27 semaphore->available_count = initial_count; 27 semaphore->available_count = initial_count;
28 semaphore->address = address;
28 semaphore->name = std::move(name); 29 semaphore->name = std::move(name);
29 30
30 return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); 31 return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore));
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index 7b0cacf2e..77c491a24 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -22,7 +22,7 @@ public:
22 * @param name Optional name of semaphore 22 * @param name Optional name of semaphore
23 * @return The created semaphore 23 * @return The created semaphore
24 */ 24 */
25 static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, 25 static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, VAddr address,
26 std::string name = "Unknown"); 26 std::string name = "Unknown");
27 27
28 std::string GetTypeName() const override { 28 std::string GetTypeName() const override {
@@ -39,6 +39,7 @@ public:
39 39
40 s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have 40 s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
41 s32 available_count; ///< Number of free slots left in the semaphore 41 s32 available_count; ///< Number of free slots left in the semaphore
42 VAddr address;
42 std::string name; ///< Name of semaphore (optional) 43 std::string name; ///< Name of semaphore (optional)
43 44
44 bool ShouldWait(Thread* thread) const override; 45 bool ShouldWait(Thread* thread) const override;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 0f7970ebe..75df49ac2 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -358,8 +358,8 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
358 * @param entry_point Address of entry point for execution 358 * @param entry_point Address of entry point for execution
359 * @param arg User argument for thread 359 * @param arg User argument for thread
360 */ 360 */
361static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top, 361static void ResetThreadContext(ARM_Interface::ThreadContext& context, VAddr stack_top,
362 u32 entry_point, u32 arg) { 362 VAddr entry_point, u64 arg) {
363 memset(&context, 0, sizeof(ARM_Interface::ThreadContext)); 363 memset(&context, 0, sizeof(ARM_Interface::ThreadContext));
364 364
365 context.cpu_registers[0] = arg; 365 context.cpu_registers[0] = arg;
@@ -446,7 +446,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
446 // Map the page to the current process' address space. 446 // Map the page to the current process' address space.
447 // TODO(Subv): Find the correct MemoryState for this region. 447 // TODO(Subv): Find the correct MemoryState for this region.
448 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, 448 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
449 linheap_memory, offset, Memory::PAGE_SIZE, MemoryState::Private); 449 linheap_memory, offset, Memory::PAGE_SIZE, MemoryState::Static);
450 } 450 }
451 451
452 // Mark the slot as used 452 // Mark the slot as used
@@ -495,6 +495,9 @@ void Thread::BoostPriority(u32 priority) {
495} 495}
496 496
497SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Process> owner_process) { 497SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Process> owner_process) {
498 // Setup page table so we can write to memory
499 SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
500
498 // Initialize new "main" thread 501 // Initialize new "main" thread
499 auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, 502 auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
500 Memory::HEAP_VADDR_END, owner_process); 503 Memory::HEAP_VADDR_END, owner_process);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 314fba81f..fafcab156 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -184,8 +184,8 @@ public:
184 u32 thread_id; 184 u32 thread_id;
185 185
186 u32 status; 186 u32 status;
187 u32 entry_point; 187 VAddr entry_point;
188 u32 stack_top; 188 VAddr stack_top;
189 189
190 u32 nominal_priority; ///< Nominal thread priority, as set by the emulated application 190 u32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
191 u32 current_priority; ///< Current thread priority, can be temporarily changed 191 u32 current_priority; ///< Current thread priority, can be temporarily changed
@@ -250,13 +250,13 @@ void Reschedule();
250 * Arbitrate the highest priority thread that is waiting 250 * Arbitrate the highest priority thread that is waiting
251 * @param address The address for which waiting threads should be arbitrated 251 * @param address The address for which waiting threads should be arbitrated
252 */ 252 */
253Thread* ArbitrateHighestPriorityThread(u32 address); 253Thread* ArbitrateHighestPriorityThread(VAddr address);
254 254
255/** 255/**
256 * Arbitrate all threads currently waiting. 256 * Arbitrate all threads currently waiting.
257 * @param address The address for which waiting threads should be arbitrated 257 * @param address The address for which waiting threads should be arbitrated
258 */ 258 */
259void ArbitrateAllThreads(u32 address); 259void ArbitrateAllThreads(VAddr address);
260 260
261/** 261/**
262 * Gets the current thread 262 * Gets the current thread
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 7a007c065..9762ef535 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -4,8 +4,10 @@
4 4
5#include <iterator> 5#include <iterator>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/arm/arm_interface.h"
7#include "core/hle/kernel/errors.h" 8#include "core/hle/kernel/errors.h"
8#include "core/hle/kernel/vm_manager.h" 9#include "core/hle/kernel/vm_manager.h"
10#include "core/core.h"
9#include "core/memory.h" 11#include "core/memory.h"
10#include "core/memory_setup.h" 12#include "core/memory_setup.h"
11#include "core/mmio.h" 13#include "core/mmio.h"
@@ -60,7 +62,7 @@ void VMManager::Reset() {
60 page_table.attributes.fill(Memory::PageType::Unmapped); 62 page_table.attributes.fill(Memory::PageType::Unmapped);
61 page_table.cached_res_count.fill(0); 63 page_table.cached_res_count.fill(0);
62 64
63 UpdatePageTableForVMA(initial_vma); 65 //UpdatePageTableForVMA(initial_vma);
64} 66}
65 67
66VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { 68VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
@@ -73,7 +75,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
73 75
74ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, 76ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
75 std::shared_ptr<std::vector<u8>> block, 77 std::shared_ptr<std::vector<u8>> block,
76 size_t offset, u32 size, 78 size_t offset, u64 size,
77 MemoryState state) { 79 MemoryState state) {
78 ASSERT(block != nullptr); 80 ASSERT(block != nullptr);
79 ASSERT(offset + size <= block->size()); 81 ASSERT(offset + size <= block->size());
@@ -83,6 +85,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
83 VirtualMemoryArea& final_vma = vma_handle->second; 85 VirtualMemoryArea& final_vma = vma_handle->second;
84 ASSERT(final_vma.size == size); 86 ASSERT(final_vma.size == size);
85 87
88 Core::CPU().MapBackingMemory(target, size, block->data() + offset, VMAPermission::ReadWriteExecute);
89
86 final_vma.type = VMAType::AllocatedMemoryBlock; 90 final_vma.type = VMAType::AllocatedMemoryBlock;
87 final_vma.permissions = VMAPermission::ReadWrite; 91 final_vma.permissions = VMAPermission::ReadWrite;
88 final_vma.meminfo_state = state; 92 final_vma.meminfo_state = state;
@@ -93,7 +97,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
93 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); 97 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
94} 98}
95 99
96ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size, 100ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u64 size,
97 MemoryState state) { 101 MemoryState state) {
98 ASSERT(memory != nullptr); 102 ASSERT(memory != nullptr);
99 103
@@ -102,6 +106,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
102 VirtualMemoryArea& final_vma = vma_handle->second; 106 VirtualMemoryArea& final_vma = vma_handle->second;
103 ASSERT(final_vma.size == size); 107 ASSERT(final_vma.size == size);
104 108
109 Core::CPU().MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
110
105 final_vma.type = VMAType::BackingMemory; 111 final_vma.type = VMAType::BackingMemory;
106 final_vma.permissions = VMAPermission::ReadWrite; 112 final_vma.permissions = VMAPermission::ReadWrite;
107 final_vma.meminfo_state = state; 113 final_vma.meminfo_state = state;
@@ -111,7 +117,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
111 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); 117 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
112} 118}
113 119
114ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, 120ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size,
115 MemoryState state, 121 MemoryState state,
116 Memory::MMIORegionPointer mmio_handler) { 122 Memory::MMIORegionPointer mmio_handler) {
117 // This is the appropriately sized VMA that will turn into our allocation. 123 // This is the appropriately sized VMA that will turn into our allocation.
@@ -145,7 +151,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
145 return MergeAdjacent(vma_handle); 151 return MergeAdjacent(vma_handle);
146} 152}
147 153
148ResultCode VMManager::UnmapRange(VAddr target, u32 size) { 154ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
149 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size)); 155 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
150 VAddr target_end = target + size; 156 VAddr target_end = target + size;
151 157
@@ -170,7 +176,7 @@ VMManager::VMAHandle VMManager::Reprotect(VMAHandle vma_handle, VMAPermission ne
170 return MergeAdjacent(iter); 176 return MergeAdjacent(iter);
171} 177}
172 178
173ResultCode VMManager::ReprotectRange(VAddr target, u32 size, VMAPermission new_perms) { 179ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_perms) {
174 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size)); 180 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
175 VAddr target_end = target + size; 181 VAddr target_end = target + size;
176 182
@@ -213,7 +219,7 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) {
213 return vma_map.erase(iter, iter); // Erases an empty range of elements 219 return vma_map.erase(iter, iter); // Erases an empty range of elements
214} 220}
215 221
216ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { 222ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) {
217 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%8X", size); 223 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%8X", size);
218 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%08X", base); 224 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%08X", base);
219 225
@@ -229,8 +235,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
229 return ERR_INVALID_ADDRESS_STATE; 235 return ERR_INVALID_ADDRESS_STATE;
230 } 236 }
231 237
232 u32 start_in_vma = base - vma.base; 238 u64 start_in_vma = base - vma.base;
233 u32 end_in_vma = start_in_vma + size; 239 u64 end_in_vma = start_in_vma + size;
234 240
235 if (end_in_vma > vma.size) { 241 if (end_in_vma > vma.size) {
236 // Requested allocation doesn't fit inside VMA 242 // Requested allocation doesn't fit inside VMA
@@ -249,7 +255,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
249 return MakeResult<VMAIter>(vma_handle); 255 return MakeResult<VMAIter>(vma_handle);
250} 256}
251 257
252ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) { 258ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
253 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%8X", size); 259 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%8X", size);
254 ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%08X", target); 260 ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%08X", target);
255 261
@@ -278,7 +284,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
278 return MakeResult<VMAIter>(begin_vma); 284 return MakeResult<VMAIter>(begin_vma);
279} 285}
280 286
281VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) { 287VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u64 offset_in_vma) {
282 VirtualMemoryArea& old_vma = vma_handle->second; 288 VirtualMemoryArea& old_vma = vma_handle->second;
283 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA 289 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
284 290
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 1302527bb..cb5bb8243 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -64,7 +64,7 @@ struct VirtualMemoryArea {
64 /// Virtual base address of the region. 64 /// Virtual base address of the region.
65 VAddr base = 0; 65 VAddr base = 0;
66 /// Size of the region. 66 /// Size of the region.
67 u32 size = 0; 67 u64 size = 0;
68 68
69 VMAType type = VMAType::Free; 69 VMAType type = VMAType::Free;
70 VMAPermission permissions = VMAPermission::None; 70 VMAPermission permissions = VMAPermission::None;
@@ -109,7 +109,7 @@ public:
109 * used. 109 * used.
110 * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000. 110 * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
111 */ 111 */
112 static const u32 MAX_ADDRESS = 0x40000000; 112 static const VAddr MAX_ADDRESS = 0x8000000000;
113 113
114 /** 114 /**
115 * A map covering the entirety of the managed address space, keyed by the `base` field of each 115 * A map covering the entirety of the managed address space, keyed by the `base` field of each
@@ -142,7 +142,7 @@ public:
142 * @param state MemoryState tag to attach to the VMA. 142 * @param state MemoryState tag to attach to the VMA.
143 */ 143 */
144 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, 144 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
145 size_t offset, u32 size, MemoryState state); 145 size_t offset, u64 size, MemoryState state);
146 146
147 /** 147 /**
148 * Maps an unmanaged host memory pointer at a given address. 148 * Maps an unmanaged host memory pointer at a given address.
@@ -152,7 +152,7 @@ public:
152 * @param size Size of the mapping. 152 * @param size Size of the mapping.
153 * @param state MemoryState tag to attach to the VMA. 153 * @param state MemoryState tag to attach to the VMA.
154 */ 154 */
155 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state); 155 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);
156 156
157 /** 157 /**
158 * Maps a memory-mapped IO region at a given address. 158 * Maps a memory-mapped IO region at a given address.
@@ -163,17 +163,17 @@ public:
163 * @param state MemoryState tag to attach to the VMA. 163 * @param state MemoryState tag to attach to the VMA.
164 * @param mmio_handler The handler that will implement read and write for this MMIO region. 164 * @param mmio_handler The handler that will implement read and write for this MMIO region.
165 */ 165 */
166 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, 166 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u64 size, MemoryState state,
167 Memory::MMIORegionPointer mmio_handler); 167 Memory::MMIORegionPointer mmio_handler);
168 168
169 /// Unmaps a range of addresses, splitting VMAs as necessary. 169 /// Unmaps a range of addresses, splitting VMAs as necessary.
170 ResultCode UnmapRange(VAddr target, u32 size); 170 ResultCode UnmapRange(VAddr target, u64 size);
171 171
172 /// Changes the permissions of the given VMA. 172 /// Changes the permissions of the given VMA.
173 VMAHandle Reprotect(VMAHandle vma, VMAPermission new_perms); 173 VMAHandle Reprotect(VMAHandle vma, VMAPermission new_perms);
174 174
175 /// Changes the permissions of a range of addresses, splitting VMAs as necessary. 175 /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
176 ResultCode ReprotectRange(VAddr target, u32 size, VMAPermission new_perms); 176 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
177 177
178 /** 178 /**
179 * Scans all VMAs and updates the page table range of any that use the given vector as backing 179 * Scans all VMAs and updates the page table range of any that use the given vector as backing
@@ -201,19 +201,19 @@ private:
201 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing 201 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
202 * the appropriate error checking. 202 * the appropriate error checking.
203 */ 203 */
204 ResultVal<VMAIter> CarveVMA(VAddr base, u32 size); 204 ResultVal<VMAIter> CarveVMA(VAddr base, u64 size);
205 205
206 /** 206 /**
207 * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each 207 * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
208 * end of the range. 208 * end of the range.
209 */ 209 */
210 ResultVal<VMAIter> CarveVMARange(VAddr base, u32 size); 210 ResultVal<VMAIter> CarveVMARange(VAddr base, u64 size);
211 211
212 /** 212 /**
213 * Splits a VMA in two, at the specified offset. 213 * Splits a VMA in two, at the specified offset.
214 * @returns the right side of the split, with the original iterator becoming the left side. 214 * @returns the right side of the split, with the original iterator becoming the left side.
215 */ 215 */
216 VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma); 216 VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma);
217 217
218 /** 218 /**
219 * Checks for and merges the specified VMA with adjacent ones if possible. 219 * Checks for and merges the specified VMA with adjacent ones if possible.
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 59ea9823d..912ab550d 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -1073,7 +1073,17 @@ void Init() {
1073 MemoryPermission::ReadWrite, MemoryPermission::Read, 0, 1073 MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
1074 Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); 1074 Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
1075 1075
1076 lock = Kernel::Mutex::Create(false, "APT_U:Lock"); 1076 if (LoadSharedFont()) {
1077 shared_font_loaded = true;
1078 } else if (LoadLegacySharedFont()) {
1079 LOG_WARNING(Service_APT, "Loaded shared font by legacy method");
1080 shared_font_loaded = true;
1081 } else {
1082 LOG_WARNING(Service_APT, "Unable to load shared font");
1083 shared_font_loaded = false;
1084 }
1085
1086 lock = Kernel::Mutex::Create(false, 0, "APT_U:Lock");
1077 1087
1078 cpu_percent = 0; 1088 cpu_percent = 0;
1079 unknown_ns_state_field = 0; 1089 unknown_ns_state_field = 0;
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 9471ec1ef..aac903ccb 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -47,7 +47,7 @@ static void Initialize(Interface* self) {
47 MemoryPermission::ReadWrite, 0, 47 MemoryPermission::ReadWrite, 0,
48 Kernel::MemoryRegion::BASE, "CSND:SharedMemory"); 48 Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
49 49
50 mutex = Kernel::Mutex::Create(false, "CSND:mutex"); 50 mutex = Kernel::Mutex::Create(false, 0, "CSND:mutex");
51 51
52 cmd_buff[1] = RESULT_SUCCESS.raw; 52 cmd_buff[1] = RESULT_SUCCESS.raw;
53 cmd_buff[2] = IPC::CopyHandleDesc(2); 53 cmd_buff[2] = IPC::CopyHandleDesc(2);
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp
index f78545f37..6128f8a6c 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.cpp
+++ b/src/core/hle/service/ldr_ro/cro_helper.cpp
@@ -274,7 +274,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
274 } 274 }
275 SetEntry(i, segment); 275 SetEntry(i, segment);
276 } 276 }
277 return MakeResult<u32>(prev_data_segment + module_address); 277 return MakeResult<VAddr>(prev_data_segment + module_address);
278} 278}
279 279
280ResultCode CROHelper::RebaseExportNamedSymbolTable() { 280ResultCode CROHelper::RebaseExportNamedSymbolTable() {
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp
index 5c955cf54..fb873981c 100644
--- a/src/core/hle/service/sm/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -62,7 +62,7 @@ void SRV::EnableNotification(Kernel::HLERequestContext& ctx) {
62 IPC::RequestParser rp(ctx, 0x2, 0, 0); 62 IPC::RequestParser rp(ctx, 0x2, 0, 0);
63 63
64 notification_semaphore = 64 notification_semaphore =
65 Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); 65 Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, 0, "SRV:Notification").Unwrap();
66 66
67 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); 67 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
68 rb.Push(RESULT_SUCCESS); 68 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index e8ca419d5..e4b803046 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -31,7 +31,6 @@
31#include "core/hle/kernel/timer.h" 31#include "core/hle/kernel/timer.h"
32#include "core/hle/kernel/vm_manager.h" 32#include "core/hle/kernel/vm_manager.h"
33#include "core/hle/kernel/wait_object.h" 33#include "core/hle/kernel/wait_object.h"
34#include "core/hle/lock.h"
35#include "core/hle/result.h" 34#include "core/hle/result.h"
36#include "core/hle/service/service.h" 35#include "core/hle/service/service.h"
37 36
@@ -201,21 +200,17 @@ static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) {
201} 200}
202 201
203/// Connect to an OS service given the port name, returns the handle to the port to out 202/// Connect to an OS service given the port name, returns the handle to the port to out
204static ResultCode ConnectToPort(Kernel::Handle* out_handle, VAddr port_name_address) { 203static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) {
205 if (!Memory::IsValidVirtualAddress(port_name_address)) 204 if (port_name == nullptr)
206 return Kernel::ERR_NOT_FOUND; 205 return Kernel::ERR_NOT_FOUND;
207 206 if (std::strlen(port_name) > 11)
208 static constexpr std::size_t PortNameMaxLength = 11;
209 // Read 1 char beyond the max allowed port name to detect names that are too long.
210 std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
211 if (port_name.size() > PortNameMaxLength)
212 return Kernel::ERR_PORT_NAME_TOO_LONG; 207 return Kernel::ERR_PORT_NAME_TOO_LONG;
213 208
214 LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name.c_str()); 209 LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name);
215 210
216 auto it = Service::g_kernel_named_ports.find(port_name); 211 auto it = Service::g_kernel_named_ports.find(port_name);
217 if (it == Service::g_kernel_named_ports.end()) { 212 if (it == Service::g_kernel_named_ports.end()) {
218 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name.c_str()); 213 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name);
219 return Kernel::ERR_NOT_FOUND; 214 return Kernel::ERR_NOT_FOUND;
220 } 215 }
221 216
@@ -275,24 +270,6 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds)
275 // Create an event to wake the thread up after the specified nanosecond delay has passed 270 // Create an event to wake the thread up after the specified nanosecond delay has passed
276 thread->WakeAfterDelay(nano_seconds); 271 thread->WakeAfterDelay(nano_seconds);
277 272
278 thread->wakeup_callback = [](ThreadWakeupReason reason,
279 Kernel::SharedPtr<Kernel::Thread> thread,
280 Kernel::SharedPtr<Kernel::WaitObject> object) {
281
282 ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
283
284 if (reason == ThreadWakeupReason::Timeout) {
285 thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
286 return;
287 }
288
289 ASSERT(reason == ThreadWakeupReason::Signal);
290 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
291
292 // WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
293 // don't have to do anything else here.
294 };
295
296 Core::System::GetInstance().PrepareReschedule(); 273 Core::System::GetInstance().PrepareReschedule();
297 274
298 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread 275 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread
@@ -307,11 +284,12 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds)
307} 284}
308 285
309/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 286/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
310static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, 287static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count,
311 bool wait_all, s64 nano_seconds) { 288 bool wait_all, s64 nano_seconds) {
312 Kernel::Thread* thread = Kernel::GetCurrentThread(); 289 Kernel::Thread* thread = Kernel::GetCurrentThread();
313 290
314 if (!Memory::IsValidVirtualAddress(handles_address)) 291 // Check if 'handles' is invalid
292 if (handles == nullptr)
315 return Kernel::ERR_INVALID_POINTER; 293 return Kernel::ERR_INVALID_POINTER;
316 294
317 // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If 295 // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
@@ -326,8 +304,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
326 std::vector<ObjectPtr> objects(handle_count); 304 std::vector<ObjectPtr> objects(handle_count);
327 305
328 for (int i = 0; i < handle_count; ++i) { 306 for (int i = 0; i < handle_count; ++i) {
329 Kernel::Handle handle = Memory::Read32(handles_address + i * sizeof(Kernel::Handle)); 307 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
330 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle);
331 if (object == nullptr) 308 if (object == nullptr)
332 return ERR_INVALID_HANDLE; 309 return ERR_INVALID_HANDLE;
333 objects[i] = object; 310 objects[i] = object;
@@ -366,23 +343,6 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
366 // Create an event to wake the thread up after the specified nanosecond delay has passed 343 // Create an event to wake the thread up after the specified nanosecond delay has passed
367 thread->WakeAfterDelay(nano_seconds); 344 thread->WakeAfterDelay(nano_seconds);
368 345
369 thread->wakeup_callback = [](ThreadWakeupReason reason,
370 Kernel::SharedPtr<Kernel::Thread> thread,
371 Kernel::SharedPtr<Kernel::WaitObject> object) {
372
373 ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ALL);
374
375 if (reason == ThreadWakeupReason::Timeout) {
376 thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
377 return;
378 }
379
380 ASSERT(reason == ThreadWakeupReason::Signal);
381
382 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
383 // The wait_all case does not update the output index.
384 };
385
386 Core::System::GetInstance().PrepareReschedule(); 346 Core::System::GetInstance().PrepareReschedule();
387 347
388 // This value gets set to -1 by default in this case, it is not modified after this. 348 // This value gets set to -1 by default in this case, it is not modified after this.
@@ -400,7 +360,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
400 // We found a ready object, acquire it and set the result value 360 // We found a ready object, acquire it and set the result value
401 Kernel::WaitObject* object = itr->get(); 361 Kernel::WaitObject* object = itr->get();
402 object->Acquire(thread); 362 object->Acquire(thread);
403 *out = static_cast<s32>(std::distance(objects.begin(), itr)); 363 *out = std::distance(objects.begin(), itr);
404 return RESULT_SUCCESS; 364 return RESULT_SUCCESS;
405 } 365 }
406 366
@@ -428,37 +388,22 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand
428 // Create an event to wake the thread up after the specified nanosecond delay has passed 388 // Create an event to wake the thread up after the specified nanosecond delay has passed
429 thread->WakeAfterDelay(nano_seconds); 389 thread->WakeAfterDelay(nano_seconds);
430 390
431 thread->wakeup_callback = [](ThreadWakeupReason reason,
432 Kernel::SharedPtr<Kernel::Thread> thread,
433 Kernel::SharedPtr<Kernel::WaitObject> object) {
434
435 ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
436
437 if (reason == ThreadWakeupReason::Timeout) {
438 thread->SetWaitSynchronizationResult(Kernel::RESULT_TIMEOUT);
439 return;
440 }
441
442 ASSERT(reason == ThreadWakeupReason::Signal);
443
444 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
445 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
446 };
447
448 Core::System::GetInstance().PrepareReschedule(); 391 Core::System::GetInstance().PrepareReschedule();
449 392
450 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a 393 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
451 // signal in one of its wait objects. 394 // signal in one of its wait objects.
452 // Otherwise we retain the default value of timeout, and -1 in the out parameter 395 // Otherwise we retain the default value of timeout, and -1 in the out parameter
396 thread->wait_set_output = true;
453 *out = -1; 397 *out = -1;
454 return Kernel::RESULT_TIMEOUT; 398 return Kernel::RESULT_TIMEOUT;
455 } 399 }
456} 400}
457 401
458/// In a single operation, sends a IPC reply and waits for a new request. 402/// In a single operation, sends a IPC reply and waits for a new request.
459static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, 403static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count,
460 Kernel::Handle reply_target) { 404 Kernel::Handle reply_target) {
461 if (!Memory::IsValidVirtualAddress(handles_address)) 405 // 'handles' has to be a valid pointer even if 'handle_count' is 0.
406 if (handles == nullptr)
462 return Kernel::ERR_INVALID_POINTER; 407 return Kernel::ERR_INVALID_POINTER;
463 408
464 // Check if 'handle_count' is invalid 409 // Check if 'handle_count' is invalid
@@ -469,8 +414,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
469 std::vector<ObjectPtr> objects(handle_count); 414 std::vector<ObjectPtr> objects(handle_count);
470 415
471 for (int i = 0; i < handle_count; ++i) { 416 for (int i = 0; i < handle_count; ++i) {
472 Kernel::Handle handle = Memory::Read32(handles_address + i * sizeof(Kernel::Handle)); 417 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
473 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle);
474 if (object == nullptr) 418 if (object == nullptr)
475 return ERR_INVALID_HANDLE; 419 return ERR_INVALID_HANDLE;
476 objects[i] = object; 420 objects[i] = object;
@@ -524,7 +468,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
524 // We found a ready object, acquire it and set the result value 468 // We found a ready object, acquire it and set the result value
525 Kernel::WaitObject* object = itr->get(); 469 Kernel::WaitObject* object = itr->get();
526 object->Acquire(thread); 470 object->Acquire(thread);
527 *index = static_cast<s32>(std::distance(objects.begin(), itr)); 471 *index = std::distance(objects.begin(), itr);
528 472
529 if (object->GetHandleType() == Kernel::HandleType::ServerSession) { 473 if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
530 auto server_session = static_cast<Kernel::ServerSession*>(object); 474 auto server_session = static_cast<Kernel::ServerSession*>(object);
@@ -538,6 +482,8 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
538 482
539 // No objects were ready to be acquired, prepare to suspend the thread. 483 // No objects were ready to be acquired, prepare to suspend the thread.
540 484
485 // TODO(Subv): Perform IPC translation upon wakeup.
486
541 // Put the thread to sleep 487 // Put the thread to sleep
542 thread->status = THREADSTATUS_WAIT_SYNCH_ANY; 488 thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
543 489
@@ -549,24 +495,12 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_
549 495
550 thread->wait_objects = std::move(objects); 496 thread->wait_objects = std::move(objects);
551 497
552 thread->wakeup_callback = [](ThreadWakeupReason reason,
553 Kernel::SharedPtr<Kernel::Thread> thread,
554 Kernel::SharedPtr<Kernel::WaitObject> object) {
555
556 ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
557 ASSERT(reason == ThreadWakeupReason::Signal);
558
559 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
560 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
561
562 // TODO(Subv): Perform IPC translation upon wakeup.
563 };
564
565 Core::System::GetInstance().PrepareReschedule(); 498 Core::System::GetInstance().PrepareReschedule();
566 499
567 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a 500 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
568 // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error. 501 // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error.
569 // By default the index is set to -1. 502 // By default the index is set to -1.
503 thread->wait_set_output = true;
570 *index = -1; 504 *index = -1;
571 return RESULT_SUCCESS; 505 return RESULT_SUCCESS;
572} 506}
@@ -623,10 +557,8 @@ static void Break(u8 break_reason) {
623} 557}
624 558
625/// Used to output a message on a debug hardware unit - does nothing on a retail unit 559/// Used to output a message on a debug hardware unit - does nothing on a retail unit
626static void OutputDebugString(VAddr address, int len) { 560static void OutputDebugString(const char* string, int len) {
627 std::vector<char> string(len); 561 LOG_DEBUG(Debug_Emulated, "%.*s", len, string);
628 Memory::ReadBlock(address, string.data(), len);
629 LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data());
630} 562}
631 563
632/// Get resource limit 564/// Get resource limit
@@ -644,9 +576,9 @@ static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handl
644} 576}
645 577
646/// Get resource limit current values 578/// Get resource limit current values
647static ResultCode GetResourceLimitCurrentValues(VAddr values, Kernel::Handle resource_limit_handle, 579static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle,
648 VAddr names, u32 name_count) { 580 u32* names, u32 name_count) {
649 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%08X, name_count=%d", 581 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
650 resource_limit_handle, names, name_count); 582 resource_limit_handle, names, name_count);
651 583
652 SharedPtr<Kernel::ResourceLimit> resource_limit = 584 SharedPtr<Kernel::ResourceLimit> resource_limit =
@@ -654,19 +586,16 @@ static ResultCode GetResourceLimitCurrentValues(VAddr values, Kernel::Handle res
654 if (resource_limit == nullptr) 586 if (resource_limit == nullptr)
655 return ERR_INVALID_HANDLE; 587 return ERR_INVALID_HANDLE;
656 588
657 for (unsigned int i = 0; i < name_count; ++i) { 589 for (unsigned int i = 0; i < name_count; ++i)
658 u32 name = Memory::Read32(names + i * sizeof(u32)); 590 values[i] = resource_limit->GetCurrentResourceValue(names[i]);
659 s64 value = resource_limit->GetCurrentResourceValue(name);
660 Memory::Write64(values + i * sizeof(u64), value);
661 }
662 591
663 return RESULT_SUCCESS; 592 return RESULT_SUCCESS;
664} 593}
665 594
666/// Get resource limit max values 595/// Get resource limit max values
667static ResultCode GetResourceLimitLimitValues(VAddr values, Kernel::Handle resource_limit_handle, 596static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle,
668 VAddr names, u32 name_count) { 597 u32* names, u32 name_count) {
669 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%08X, name_count=%d", 598 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
670 resource_limit_handle, names, name_count); 599 resource_limit_handle, names, name_count);
671 600
672 SharedPtr<Kernel::ResourceLimit> resource_limit = 601 SharedPtr<Kernel::ResourceLimit> resource_limit =
@@ -674,11 +603,8 @@ static ResultCode GetResourceLimitLimitValues(VAddr values, Kernel::Handle resou
674 if (resource_limit == nullptr) 603 if (resource_limit == nullptr)
675 return ERR_INVALID_HANDLE; 604 return ERR_INVALID_HANDLE;
676 605
677 for (unsigned int i = 0; i < name_count; ++i) { 606 for (unsigned int i = 0; i < name_count; ++i)
678 u32 name = Memory::Read32(names + i * sizeof(u32)); 607 values[i] = resource_limit->GetMaxResourceValue(names[i]);
679 s64 value = resource_limit->GetMaxResourceValue(names);
680 Memory::Write64(values + i * sizeof(u64), value);
681 }
682 608
683 return RESULT_SUCCESS; 609 return RESULT_SUCCESS;
684} 610}
@@ -729,9 +655,8 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, u32 priority, u32 ent
729 "Newly created thread must run in the SysCore (Core1), unimplemented."); 655 "Newly created thread must run in the SysCore (Core1), unimplemented.");
730 } 656 }
731 657
732 CASCADE_RESULT(SharedPtr<Thread> thread, 658 CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority,
733 Kernel::Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, 659 arg, processor_id, stack_top));
734 Kernel::g_current_process));
735 660
736 thread->context.fpscr = 661 thread->context.fpscr =
737 FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 662 FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000
@@ -756,7 +681,7 @@ static void ExitThread() {
756} 681}
757 682
758/// Gets the priority for the specified thread 683/// Gets the priority for the specified thread
759static ResultCode GetThreadPriority(u32* priority, Kernel::Handle handle) { 684static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) {
760 const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); 685 const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
761 if (thread == nullptr) 686 if (thread == nullptr)
762 return ERR_INVALID_HANDLE; 687 return ERR_INVALID_HANDLE;
@@ -766,7 +691,7 @@ static ResultCode GetThreadPriority(u32* priority, Kernel::Handle handle) {
766} 691}
767 692
768/// Sets the priority for the specified thread 693/// Sets the priority for the specified thread
769static ResultCode SetThreadPriority(Kernel::Handle handle, u32 priority) { 694static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) {
770 if (priority > THREADPRIO_LOWEST) { 695 if (priority > THREADPRIO_LOWEST) {
771 return Kernel::ERR_OUT_OF_RANGE; 696 return Kernel::ERR_OUT_OF_RANGE;
772 } 697 }
@@ -1051,7 +976,7 @@ static void SleepThread(s64 nanoseconds) {
1051static s64 GetSystemTick() { 976static s64 GetSystemTick() {
1052 s64 result = CoreTiming::GetTicks(); 977 s64 result = CoreTiming::GetTicks();
1053 // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. 978 // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
1054 CoreTiming::AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b 979 Core::CPU().AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
1055 return result; 980 return result;
1056} 981}
1057 982
@@ -1110,9 +1035,9 @@ static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 si
1110} 1035}
1111 1036
1112static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port, 1037static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port,
1113 VAddr name_address, u32 max_sessions) { 1038 const char* name, u32 max_sessions) {
1114 // TODO(Subv): Implement named ports. 1039 // TODO(Subv): Implement named ports.
1115 ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented"); 1040 ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented");
1116 1041
1117 using Kernel::ServerPort; 1042 using Kernel::ServerPort;
1118 using Kernel::ClientPort; 1043 using Kernel::ClientPort;
@@ -1263,7 +1188,7 @@ struct FunctionDef {
1263 Func* func; 1188 Func* func;
1264 const char* name; 1189 const char* name;
1265}; 1190};
1266} // namespace 1191}
1267 1192
1268static const FunctionDef SVC_Table[] = { 1193static const FunctionDef SVC_Table[] = {
1269 {0x00, nullptr, "Unknown"}, 1194 {0x00, nullptr, "Unknown"},
@@ -1407,9 +1332,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
1407void CallSVC(u32 immediate) { 1332void CallSVC(u32 immediate) {
1408 MICROPROFILE_SCOPE(Kernel_SVC); 1333 MICROPROFILE_SCOPE(Kernel_SVC);
1409 1334
1410 // Lock the global kernel mutex when we enter the kernel HLE.
1411 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
1412
1413 const FunctionDef* info = GetSVCInfo(immediate); 1335 const FunctionDef* info = GetSVCInfo(immediate);
1414 if (info) { 1336 if (info) {
1415 if (info->func) { 1337 if (info->func) {
@@ -1420,4 +1342,4 @@ void CallSVC(u32 immediate) {
1420 } 1342 }
1421} 1343}
1422 1344
1423} // namespace SVC 1345} // namespace
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 83ad9d898..d1bfe51e6 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -515,15 +515,15 @@ template void Write<u8>(u32 addr, const u8 data);
515 515
516/// Update hardware 516/// Update hardware
517static void VBlankCallback(u64 userdata, int cycles_late) { 517static void VBlankCallback(u64 userdata, int cycles_late) {
518 VideoCore::g_renderer->SwapBuffers(); 518 //VideoCore::g_renderer->SwapBuffers();
519 519
520 // Signal to GSP that GPU interrupt has occurred 520 //// Signal to GSP that GPU interrupt has occurred
521 // TODO(yuriks): hwtest to determine if PDC0 is for the Top screen and PDC1 for the Sub 521 //// TODO(yuriks): hwtest to determine if PDC0 is for the Top screen and PDC1 for the Sub
522 // screen, or if both use the same interrupts and these two instead determine the 522 //// screen, or if both use the same interrupts and these two instead determine the
523 // beginning and end of the VBlank period. If needed, split the interrupt firing into 523 //// beginning and end of the VBlank period. If needed, split the interrupt firing into
524 // two different intervals. 524 //// two different intervals.
525 Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0); 525 //Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0);
526 Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1); 526 //Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1);
527 527
528 // Reschedule recurrent event 528 // Reschedule recurrent event
529 CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event); 529 CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event);
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 918038f1e..7b0342cc9 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -267,15 +267,15 @@ ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr<Kernel::Process>& proces
267 return ResultStatus::Error; 267 return ResultStatus::Error;
268 codeset->name = filename; 268 codeset->name = filename;
269 269
270 process = Kernel::Process::Create(std::move(codeset)); 270 process = Kernel::Process::Create("main");
271 process->LoadModule(codeset, codeset->entrypoint);
271 process->svc_access_mask.set(); 272 process->svc_access_mask.set();
272 process->address_mappings = default_address_mappings; 273 process->address_mappings = default_address_mappings;
273 274
274 // Attach the default resource limit (APPLICATION) to the process 275 // Attach the default resource limit (APPLICATION) to the process
275 process->resource_limit = 276 process->resource_limit =
276 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 277 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
277 278 process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE);
278 process->Run(48, Kernel::DEFAULT_STACK_SIZE);
279 279
280 Service::FS::RegisterSelfNCCH(*this); 280 Service::FS::RegisterSelfNCCH(*this);
281 281
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index e36e42120..9969a8c39 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -364,12 +364,19 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const
364namespace Loader { 364namespace Loader {
365 365
366FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) { 366FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) {
367 u32 magic; 367 static constexpr u16 ELF_MACHINE_ARM{0x28};
368
369 u32 magic = 0;
368 file.Seek(0, SEEK_SET); 370 file.Seek(0, SEEK_SET);
369 if (1 != file.ReadArray<u32>(&magic, 1)) 371 if (1 != file.ReadArray<u32>(&magic, 1))
370 return FileType::Error; 372 return FileType::Error;
371 373
372 if (MakeMagic('\x7f', 'E', 'L', 'F') == magic) 374 u16 machine = 0;
375 file.Seek(18, SEEK_SET);
376 if (1 != file.ReadArray<u16>(&machine, 1))
377 return FileType::Error;
378
379 if (MakeMagic('\x7f', 'E', 'L', 'F') == magic && ELF_MACHINE_ARM == machine)
373 return FileType::ELF; 380 return FileType::ELF;
374 381
375 return FileType::Error; 382 return FileType::Error;
@@ -394,7 +401,8 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
394 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); 401 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
395 codeset->name = filename; 402 codeset->name = filename;
396 403
397 process = Kernel::Process::Create(std::move(codeset)); 404 process = Kernel::Process::Create("main");
405 process->LoadModule(codeset, codeset->entrypoint);
398 process->svc_access_mask.set(); 406 process->svc_access_mask.set();
399 process->address_mappings = default_address_mappings; 407 process->address_mappings = default_address_mappings;
400 408
@@ -402,7 +410,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
402 process->resource_limit = 410 process->resource_limit =
403 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 411 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
404 412
405 process->Run(48, Kernel::DEFAULT_STACK_SIZE); 413 process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE);
406 414
407 is_loaded = true; 415 is_loaded = true;
408 return ResultStatus::Success; 416 return ResultStatus::Success;
diff --git a/src/core/loader/linker.cpp b/src/core/loader/linker.cpp
new file mode 100644
index 000000000..a265b9315
--- /dev/null
+++ b/src/core/loader/linker.cpp
@@ -0,0 +1,151 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "common/common_funcs.h"
8#include "common/logging/log.h"
9#include "common/swap.h"
10#include "core/loader/linker.h"
11#include "core/memory.h"
12
13namespace Loader {
14
15enum class RelocationType : u32 { ABS64 = 257, GLOB_DAT = 1025, JUMP_SLOT = 1026, RELATIVE = 1027 };
16
17enum DynamicType : u32 {
18 DT_NULL = 0,
19 DT_PLTRELSZ = 2,
20 DT_STRTAB = 5,
21 DT_SYMTAB = 6,
22 DT_RELA = 7,
23 DT_RELASZ = 8,
24 DT_STRSZ = 10,
25 DT_JMPREL = 23,
26};
27
28struct Elf64_Rela {
29 u64_le offset;
30 RelocationType type;
31 u32_le symbol;
32 s64_le addend;
33};
34static_assert(sizeof(Elf64_Rela) == 0x18, "Elf64_Rela has incorrect size.");
35
36struct Elf64_Dyn {
37 u64_le tag;
38 u64_le value;
39};
40static_assert(sizeof(Elf64_Dyn) == 0x10, "Elf64_Dyn has incorrect size.");
41
42struct Elf64_Sym {
43 u32_le name;
44 INSERT_PADDING_BYTES(0x2);
45 u16_le shndx;
46 u64_le value;
47 u64_le size;
48};
49static_assert(sizeof(Elf64_Sym) == 0x18, "Elf64_Sym has incorrect size.");
50
51void Linker::WriteRelocations(std::vector<u8>& program_image,
52 const std::vector<Symbol>& symbols, u64 relocation_offset,
53 u64 size, bool is_jump_relocation, VAddr load_base) {
54 for (u64 i = 0; i < size; i += sizeof(Elf64_Rela)) {
55 Elf64_Rela rela;
56 std::memcpy(&rela, &program_image[relocation_offset + i], sizeof(Elf64_Rela));
57
58 const Symbol& symbol = symbols[rela.symbol];
59 switch (rela.type) {
60 case RelocationType::RELATIVE: {
61 const u64 value = load_base + rela.addend;
62 if (!symbol.name.empty()) {
63 exports[symbol.name] = value;
64 }
65 std::memcpy(&program_image[rela.offset], &value, sizeof(u64));
66 break;
67 }
68 case RelocationType::JUMP_SLOT:
69 case RelocationType::GLOB_DAT:
70 if (!symbol.value) {
71 imports[symbol.name] = {rela.offset + load_base, 0};
72 } else {
73 exports[symbol.name] = symbol.value;
74 std::memcpy(&program_image[rela.offset], &symbol.value, sizeof(u64));
75 }
76 break;
77 case RelocationType::ABS64:
78 if (!symbol.value) {
79 imports[symbol.name] = {rela.offset + load_base, rela.addend};
80 } else {
81 const u64 value = symbol.value + rela.addend;
82 exports[symbol.name] = value;
83 std::memcpy(&program_image[rela.offset], &value, sizeof(u64));
84 }
85 break;
86 default:
87 LOG_CRITICAL(Loader, "Unknown relocation type: %d", rela.type);
88 break;
89 }
90 }
91}
92
93void Linker::Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset,
94 VAddr load_base) {
95 std::map<u64, u64> dynamic;
96 while (dynamic_section_offset < program_image.size()) {
97 Elf64_Dyn dyn;
98 std::memcpy(&dyn, &program_image[dynamic_section_offset], sizeof(Elf64_Dyn));
99 dynamic_section_offset += sizeof(Elf64_Dyn);
100
101 if (dyn.tag == DT_NULL) {
102 break;
103 }
104 dynamic[dyn.tag] = dyn.value;
105 }
106
107 u64 offset = dynamic[DT_SYMTAB];
108 std::vector<Symbol> symbols;
109 while (offset < program_image.size()) {
110 Elf64_Sym sym;
111 std::memcpy(&sym, &program_image[offset], sizeof(Elf64_Sym));
112 offset += sizeof(Elf64_Sym);
113
114 if (sym.name >= dynamic[DT_STRSZ]) {
115 break;
116 }
117
118 std::string name = reinterpret_cast<char*>(&program_image[dynamic[DT_STRTAB] + sym.name]);
119 if (sym.value) {
120 exports[name] = load_base + sym.value;
121 symbols.emplace_back(std::move(name), load_base + sym.value);
122 } else {
123 symbols.emplace_back(std::move(name), 0);
124 }
125 }
126
127 if (dynamic.find(DT_RELA) != dynamic.end()) {
128 WriteRelocations(program_image, symbols, dynamic[DT_RELA], dynamic[DT_RELASZ], false,
129 load_base);
130 }
131
132 if (dynamic.find(DT_JMPREL) != dynamic.end()) {
133 WriteRelocations(program_image, symbols, dynamic[DT_JMPREL], dynamic[DT_PLTRELSZ], true,
134 load_base);
135 }
136}
137
138void Linker::ResolveImports() {
139 // Resolve imports
140 for (const auto& import : imports) {
141 const auto& search = exports.find(import.first);
142 if (search != exports.end()) {
143 Memory::Write64(import.second.ea, search->second + import.second.addend);
144 }
145 else {
146 LOG_ERROR(Loader, "Unresolved import: %s", import.first.c_str());
147 }
148 }
149}
150
151} // namespace Loader
diff --git a/src/core/loader/linker.h b/src/core/loader/linker.h
new file mode 100644
index 000000000..d18155f0d
--- /dev/null
+++ b/src/core/loader/linker.h
@@ -0,0 +1,37 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <string>
9#include "common/common_types.h"
10
11namespace Loader {
12
13class Linker {
14protected:
15 struct Symbol {
16 Symbol(std::string&& name, u64 value) : name(std::move(name)), value(value) {}
17 std::string name;
18 u64 value;
19 };
20
21 struct Import {
22 VAddr ea;
23 s64 addend;
24 };
25
26 void WriteRelocations(std::vector<u8>& program_image, const std::vector<Symbol>& symbols,
27 u64 relocation_offset, u64 size, bool is_jump_relocation,
28 VAddr load_base);
29 void Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, VAddr load_base);
30
31 void ResolveImports();
32
33 std::map<std::string, Import> imports;
34 std::map<std::string, VAddr> exports;
35};
36
37} // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index be719d74c..73318c584 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -10,6 +10,8 @@
10#include "core/loader/3dsx.h" 10#include "core/loader/3dsx.h"
11#include "core/loader/elf.h" 11#include "core/loader/elf.h"
12#include "core/loader/ncch.h" 12#include "core/loader/ncch.h"
13#include "core/loader/nro.h"
14#include "core/loader/nso.h"
13 15
14//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
15 17
@@ -32,6 +34,8 @@ FileType IdentifyFile(FileUtil::IOFile& file) {
32 CHECK_TYPE(THREEDSX) 34 CHECK_TYPE(THREEDSX)
33 CHECK_TYPE(ELF) 35 CHECK_TYPE(ELF)
34 CHECK_TYPE(NCCH) 36 CHECK_TYPE(NCCH)
37 CHECK_TYPE(NSO)
38 CHECK_TYPE(NRO)
35 39
36#undef CHECK_TYPE 40#undef CHECK_TYPE
37 41
@@ -115,6 +119,14 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileTyp
115 case FileType::CCI: 119 case FileType::CCI:
116 return std::make_unique<AppLoader_NCCH>(std::move(file), filepath); 120 return std::make_unique<AppLoader_NCCH>(std::move(file), filepath);
117 121
122 // NX NSO file format.
123 case FileType::NSO:
124 return std::make_unique<AppLoader_NSO>(std::move(file), filepath);
125
126 // NX NRO file format.
127 case FileType::NRO:
128 return std::make_unique<AppLoader_NRO>(std::move(file), filepath);
129
118 default: 130 default:
119 return nullptr; 131 return nullptr;
120 } 132 }
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 82b2be6a3..311785d05 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -34,6 +34,8 @@ enum class FileType {
34 CIA, 34 CIA,
35 ELF, 35 ELF,
36 THREEDSX, // 3DSX 36 THREEDSX, // 3DSX
37 NSO,
38 NRO,
37}; 39};
38 40
39/** 41/**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 52686e364..e33a37b2e 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -118,7 +118,8 @@ ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr<Kernel::Process>& proces
118 codeset->entrypoint = codeset->code.addr; 118 codeset->entrypoint = codeset->code.addr;
119 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); 119 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code));
120 120
121 process = Kernel::Process::Create(std::move(codeset)); 121 process = Kernel::Process::Create("main");
122 process->LoadModule(codeset, codeset->entrypoint);
122 123
123 // Attach a resource limit to the process based on the resource limit category 124 // Attach a resource limit to the process based on the resource limit category
124 process->resource_limit = 125 process->resource_limit =
@@ -138,7 +139,7 @@ ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr<Kernel::Process>& proces
138 139
139 s32 priority = overlay_ncch->exheader_header.arm11_system_local_caps.priority; 140 s32 priority = overlay_ncch->exheader_header.arm11_system_local_caps.priority;
140 u32 stack_size = overlay_ncch->exheader_header.codeset_info.stack_size; 141 u32 stack_size = overlay_ncch->exheader_header.codeset_info.stack_size;
141 process->Run(priority, stack_size); 142 process->Run(codeset->entrypoint, priority, stack_size);
142 return ResultStatus::Success; 143 return ResultStatus::Success;
143 } 144 }
144 return ResultStatus::Error; 145 return ResultStatus::Error;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
new file mode 100644
index 000000000..24c2c55a9
--- /dev/null
+++ b/src/core/loader/nro.cpp
@@ -0,0 +1,162 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "common/logging/log.h"
8#include "common/swap.h"
9#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/resource_limit.h"
11#include "core/loader/nro.h"
12#include "core/memory.h"
13
14namespace Loader {
15
16struct NroSegmentHeader {
17 u32_le offset;
18 u32_le size;
19};
20static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect size.");
21
22struct NroHeader {
23 INSERT_PADDING_BYTES(0x4);
24 u32_le module_header_offset;
25 INSERT_PADDING_BYTES(0x8);
26 u32_le magic;
27 INSERT_PADDING_BYTES(0x4);
28 u32_le file_size;
29 INSERT_PADDING_BYTES(0x4);
30 std::array<NroSegmentHeader, 3> segments; // Text, RoData, Data (in that order)
31 u32_le bss_size;
32 INSERT_PADDING_BYTES(0x44);
33};
34static_assert(sizeof(NroHeader) == 0x80, "NroHeader has incorrect size.");
35
36struct ModHeader {
37 u32_le magic;
38 u32_le dynamic_offset;
39 u32_le bss_start_offset;
40 u32_le bss_end_offset;
41 u32_le unwind_start_offset;
42 u32_le unwind_end_offset;
43 u32_le module_offset; // Offset to runtime-generated module object. typically equal to .bss base
44};
45static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size.");
46
47FileType AppLoader_NRO::IdentifyType(FileUtil::IOFile& file) {
48 // Read NSO header
49 NroHeader nro_header{};
50 file.Seek(0, SEEK_SET);
51 if (sizeof(NroHeader) != file.ReadBytes(&nro_header, sizeof(NroHeader))) {
52 return FileType::Error;
53 }
54 if (nro_header.magic == MakeMagic('N', 'R', 'O', '0')) {
55 return FileType::NRO;
56 }
57 return FileType::Error;
58}
59
60static constexpr u32 PageAlignSize(u32 size) {
61 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
62}
63
64static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NroSegmentHeader& header) {
65 std::vector<u8> data;
66 data.resize(header.size);
67
68 file.Seek(header.offset + sizeof(NroHeader), SEEK_SET);
69 size_t bytes_read{file.ReadBytes(data.data(), header.size)};
70 if (header.size != PageAlignSize(static_cast<u32>(bytes_read))) {
71 LOG_CRITICAL(Loader, "Failed to read NRO segment bytes", header.size);
72 return {};
73 }
74
75 return data;
76}
77
78bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) {
79 FileUtil::IOFile file(path, "rb");
80 if (!file.IsOpen()) {
81 return {};
82 }
83
84 // Read NSO header
85 NroHeader nro_header{};
86 file.Seek(0, SEEK_SET);
87 if (sizeof(NroHeader) != file.ReadBytes(&nro_header, sizeof(NroHeader))) {
88 return {};
89 }
90 if (nro_header.magic != MakeMagic('N', 'R', 'O', '0')) {
91 return {};
92 }
93
94 // Build program image
95 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("", 0);
96 std::vector<u8> program_image;
97 program_image.resize(PageAlignSize(nro_header.file_size + nro_header.bss_size));
98 file.Seek(0, SEEK_SET);
99 file.ReadBytes(program_image.data(), nro_header.file_size);
100
101 for (int i = 0; i < nro_header.segments.size(); ++i) {
102 codeset->segments[i].addr = nro_header.segments[i].offset;
103 codeset->segments[i].offset = nro_header.segments[i].offset;
104 codeset->segments[i].size = PageAlignSize(nro_header.segments[i].size);
105 }
106
107 // Read MOD header
108 ModHeader mod_header{};
109 u32 bss_size{Memory::PAGE_SIZE}; // Default .bss to page size if MOD0 section doesn't exist
110 std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset,
111 sizeof(ModHeader));
112 const bool has_mod_header{mod_header.magic == MakeMagic('M', 'O', 'D', '0')};
113 if (has_mod_header) {
114 // Resize program image to include .bss section and page align each section
115 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
116 codeset->data.size += bss_size;
117 }
118 program_image.resize(PageAlignSize(static_cast<u32>(program_image.size()) + bss_size));
119
120 // Relocate symbols if there was a proper MOD header - This must happen after the image has been
121 // loaded into memory
122 if (has_mod_header) {
123 Relocate(program_image, nro_header.module_header_offset + mod_header.dynamic_offset,
124 load_base);
125 }
126
127 // Load codeset for current process
128 codeset->name = path;
129 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
130 Kernel::g_current_process->LoadModule(codeset, load_base);
131
132 return true;
133}
134
135ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
136 if (is_loaded) {
137 return ResultStatus::ErrorAlreadyLoaded;
138 }
139 if (!file.IsOpen()) {
140 return ResultStatus::Error;
141 }
142
143 // Load and relocate "main" and "sdk" NSO
144 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
145 process = Kernel::Process::Create("main");
146 if (!LoadNro(filepath, base_addr)) {
147 return ResultStatus::ErrorInvalidFormat;
148 }
149
150 process->svc_access_mask.set();
151 process->address_mappings = default_address_mappings;
152 process->resource_limit =
153 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
154 process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE);
155
156 ResolveImports();
157
158 is_loaded = true;
159 return ResultStatus::Success;
160}
161
162} // namespace Loader
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
new file mode 100644
index 000000000..c85768c5b
--- /dev/null
+++ b/src/core/loader/nro.h
@@ -0,0 +1,42 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <string>
9#include "common/common_types.h"
10#include "common/file_util.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/loader/linker.h"
13#include "core/loader/loader.h"
14
15namespace Loader {
16
17/// Loads an NRO file
18class AppLoader_NRO final : public AppLoader, Linker {
19public:
20 AppLoader_NRO(FileUtil::IOFile&& file, std::string filepath)
21 : AppLoader(std::move(file)), filepath(std::move(filepath)) {}
22
23 /**
24 * Returns the type of the file
25 * @param file FileUtil::IOFile open file
26 * @return FileType found, or FileType::Error if this loader doesn't know it
27 */
28 static FileType IdentifyType(FileUtil::IOFile& file);
29
30 FileType GetFileType() override {
31 return IdentifyType(file);
32 }
33
34 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
35
36private:
37 bool LoadNro(const std::string& path, VAddr load_base);
38
39 std::string filepath;
40};
41
42} // namespace Loader
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
new file mode 100644
index 000000000..b1b57d0c0
--- /dev/null
+++ b/src/core/loader/nso.cpp
@@ -0,0 +1,185 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6#include <lz4.h>
7
8#include "common/logging/log.h"
9#include "common/swap.h"
10#include "core/hle/kernel/process.h"
11#include "core/hle/kernel/resource_limit.h"
12#include "core/loader/nso.h"
13#include "core/memory.h"
14
15namespace Loader {
16
17struct NsoSegmentHeader {
18 u32_le offset;
19 u32_le location;
20 u32_le size;
21 u32_le alignment;
22};
23static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect size.");
24
25struct NsoHeader {
26 u32_le magic;
27 INSERT_PADDING_BYTES(0xc);
28 std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order)
29 u32_le bss_size;
30 INSERT_PADDING_BYTES(0x1c);
31 std::array<u32_le, 3> segments_compressed_size;
32};
33static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
34
35struct ModHeader {
36 u32_le magic;
37 u32_le dynamic_offset;
38 u32_le bss_start_offset;
39 u32_le bss_end_offset;
40 u32_le eh_frame_hdr_start_offset;
41 u32_le eh_frame_hdr_end_offset;
42 u32_le module_offset; // Offset to runtime-generated module object. typically equal to .bss base
43};
44static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size.");
45
46FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file) {
47 u32 magic = 0;
48 file.Seek(0, SEEK_SET);
49 if (1 != file.ReadArray<u32>(&magic, 1)) {
50 return FileType::Error;
51 }
52
53 if (MakeMagic('N', 'S', 'O', '0') == magic) {
54 return FileType::NSO;
55 }
56
57 return FileType::Error;
58}
59
60static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeader& header,
61 int compressed_size) {
62 std::vector<u8> compressed_data;
63 compressed_data.resize(compressed_size);
64
65 file.Seek(header.offset, SEEK_SET);
66 if (compressed_size != file.ReadBytes(compressed_data.data(), compressed_size)) {
67 LOG_CRITICAL(Loader, "Failed to read %d NSO LZ4 compressed bytes", compressed_size);
68 return {};
69 }
70
71 std::vector<u8> uncompressed_data;
72 uncompressed_data.resize(header.size);
73 const int bytes_uncompressed = LZ4_decompress_safe(
74 reinterpret_cast<const char*>(compressed_data.data()),
75 reinterpret_cast<char*>(uncompressed_data.data()), compressed_size, header.size);
76
77 ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(),
78 "%d != %d != %d", bytes_uncompressed, header.size, uncompressed_data.size());
79
80 return uncompressed_data;
81}
82
83static constexpr u32 PageAlignSize(u32 size) {
84 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
85}
86
87VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base, bool relocate) {
88 FileUtil::IOFile file(path, "rb");
89 if (!file.IsOpen()) {
90 return {};
91 }
92
93 // Read NSO header
94 NsoHeader nso_header{};
95 file.Seek(0, SEEK_SET);
96 if (sizeof(NsoHeader) != file.ReadBytes(&nso_header, sizeof(NsoHeader))) {
97 return {};
98 }
99 if (nso_header.magic != MakeMagic('N', 'S', 'O', '0')) {
100 return {};
101 }
102
103 // Build program image
104 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("", 0);
105 std::vector<u8> program_image;
106 for (int i = 0; i < nso_header.segments.size(); ++i) {
107 std::vector<u8> data =
108 ReadSegment(file, nso_header.segments[i], nso_header.segments_compressed_size[i]);
109 program_image.resize(nso_header.segments[i].location);
110 program_image.insert(program_image.end(), data.begin(), data.end());
111 codeset->segments[i].addr = nso_header.segments[i].location;
112 codeset->segments[i].offset = nso_header.segments[i].location;
113 codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
114 }
115
116 // MOD header pointer is at .text offset + 4
117 u32 module_offset;
118 std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32));
119
120 // Read MOD header
121 ModHeader mod_header{};
122 u32 bss_size{Memory::PAGE_SIZE}; // Default .bss to page size if MOD0 section doesn't exist
123 std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader));
124 const bool has_mod_header{mod_header.magic == MakeMagic('M', 'O', 'D', '0')};
125 if (has_mod_header) {
126 // Resize program image to include .bss section and page align each section
127 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
128 codeset->data.size += bss_size;
129 }
130 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
131 program_image.resize(image_size);
132
133 // Relocate symbols if there was a proper MOD header - This must happen after the image has been
134 // loaded into memory
135 if (has_mod_header && relocate) {
136 Relocate(program_image, module_offset + mod_header.dynamic_offset, load_base);
137 }
138
139 // Load codeset for current process
140 codeset->name = path;
141 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
142 Kernel::g_current_process->LoadModule(codeset, load_base);
143
144 return load_base + image_size;
145}
146
147ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
148 if (is_loaded) {
149 return ResultStatus::ErrorAlreadyLoaded;
150 }
151 if (!file.IsOpen()) {
152 return ResultStatus::Error;
153 }
154
155 // Load and relocate "rtld" NSO
156 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
157 process = Kernel::Process::Create("main");
158 VAddr next_base_addr{LoadNso(filepath, base_addr)};
159 if (!next_base_addr) {
160 return ResultStatus::ErrorInvalidFormat;
161 }
162
163 // Load and relocate remaining submodules
164 for (const auto& module_name : {"main", "sdk", "subsdk0", "subsdk1"}) {
165 const std::string module_path =
166 filepath.substr(0, filepath.find_last_of("/\\")) + "/" + module_name;
167 next_base_addr = LoadNso(module_path, next_base_addr);
168 if (!next_base_addr) {
169 LOG_WARNING(Loader, "failed to find load module: %s", module_name);
170 }
171 }
172
173 process->svc_access_mask.set();
174 process->address_mappings = default_address_mappings;
175 process->resource_limit =
176 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
177 process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE);
178
179 ResolveImports();
180
181 is_loaded = true;
182 return ResultStatus::Success;
183}
184
185} // namespace Loader
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
new file mode 100644
index 000000000..b6b86c209
--- /dev/null
+++ b/src/core/loader/nso.h
@@ -0,0 +1,43 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <string>
9#include "common/common_types.h"
10#include "common/file_util.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/loader/linker.h"
13#include "core/loader/loader.h"
14
15namespace Loader {
16
17/// Loads an NSO file
18class AppLoader_NSO final : public AppLoader, Linker {
19public:
20 AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath)
21 : AppLoader(std::move(file)), filepath(std::move(filepath)) {
22 }
23
24 /**
25 * Returns the type of the file
26 * @param file FileUtil::IOFile open file
27 * @return FileType found, or FileType::Error if this loader doesn't know it
28 */
29 static FileType IdentifyType(FileUtil::IOFile& file);
30
31 FileType GetFileType() override {
32 return IdentifyType(file);
33 }
34
35 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
36
37private:
38 VAddr LoadNso(const std::string& path, VAddr load_base, bool relocate = false);
39
40 std::string filepath;
41};
42
43} // namespace Loader
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 7f58be6de..462d68386 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -37,14 +37,14 @@ PageTable* GetCurrentPageTable() {
37 return current_page_table; 37 return current_page_table;
38} 38}
39 39
40static void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) { 40static void MapPages(PageTable& page_table, VAddr base, u32 size, u8* memory, PageType type) {
41 LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, 41 LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE,
42 (base + size) * PAGE_SIZE); 42 (base + size) * PAGE_SIZE);
43 43
44 RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, 44 RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
45 FlushMode::FlushAndInvalidate); 45 FlushMode::FlushAndInvalidate);
46 46
47 u32 end = base + size; 47 VAddr end = base + size;
48 while (base != end) { 48 while (base != end) {
49 ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); 49 ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base);
50 50
@@ -303,7 +303,7 @@ u8* GetPhysicalPointer(PAddr address) {
303 return nullptr; 303 return nullptr;
304 } 304 }
305 305
306 u32 offset_into_region = address - area->paddr_base; 306 u64 offset_into_region = address - area->paddr_base;
307 307
308 u8* target_pointer = nullptr; 308 u8* target_pointer = nullptr;
309 switch (area->paddr_base) { 309 switch (area->paddr_base) {
@@ -339,7 +339,7 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
339 return; 339 return;
340 } 340 }
341 341
342 u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; 342 u64 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1;
343 PAddr paddr = start; 343 PAddr paddr = start;
344 344
345 for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { 345 for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
@@ -443,7 +443,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) {
443 VAddr overlap_end = std::min(end, region_end); 443 VAddr overlap_end = std::min(end, region_end);
444 444
445 PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value(); 445 PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value();
446 u32 overlap_size = overlap_end - overlap_start; 446 u32 overlap_size = static_cast<u32>(overlap_end - overlap_start);
447 447
448 auto* rasterizer = VideoCore::g_renderer->Rasterizer(); 448 auto* rasterizer = VideoCore::g_renderer->Rasterizer();
449 switch (mode) { 449 switch (mode) {
diff --git a/src/core/memory.h b/src/core/memory.h
index dd599f73e..9a04b9a16 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <map>
9#include <string> 10#include <string>
10#include <vector> 11#include <vector>
11#include <boost/optional.hpp> 12#include <boost/optional.hpp>
@@ -22,10 +23,10 @@ namespace Memory {
22 * Page size used by the ARM architecture. This is the smallest granularity with which memory can 23 * Page size used by the ARM architecture. This is the smallest granularity with which memory can
23 * be mapped. 24 * be mapped.
24 */ 25 */
25const u32 PAGE_SIZE = 0x1000;
26const u32 PAGE_MASK = PAGE_SIZE - 1;
27const int PAGE_BITS = 12; 26const int PAGE_BITS = 12;
28const size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS); 27const u64 PAGE_SIZE = 1 << PAGE_BITS;
28const u64 PAGE_MASK = PAGE_SIZE - 1;
29const size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (32 - PAGE_BITS);
29 30
30enum class PageType { 31enum class PageType {
31 /// Page is unmapped and should cause an access error. 32 /// Page is unmapped and should cause an access error.
@@ -124,8 +125,8 @@ enum : PAddr {
124/// Virtual user-space memory regions 125/// Virtual user-space memory regions
125enum : VAddr { 126enum : VAddr {
126 /// Where the application text, data and bss reside. 127 /// Where the application text, data and bss reside.
127 PROCESS_IMAGE_VADDR = 0x00100000, 128 PROCESS_IMAGE_VADDR = 0x08000000,
128 PROCESS_IMAGE_MAX_SIZE = 0x03F00000, 129 PROCESS_IMAGE_MAX_SIZE = 0x08000000,
129 PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, 130 PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
130 131
131 /// Area where IPC buffers are mapped onto. 132 /// Area where IPC buffers are mapped onto.
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 484713a92..2339bdfb8 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -15,7 +15,7 @@ static Memory::PageTable* page_table = nullptr;
15TestEnvironment::TestEnvironment(bool mutable_memory_) 15TestEnvironment::TestEnvironment(bool mutable_memory_)
16 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { 16 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
17 17
18 Kernel::g_current_process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); 18 Kernel::g_current_process = Kernel::Process::Create("");
19 page_table = &Kernel::g_current_process->vm_manager.page_table; 19 page_table = &Kernel::g_current_process->vm_manager.page_table;
20 20
21 page_table->pointers.fill(nullptr); 21 page_table->pointers.fill(nullptr);
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index 52336d027..4143a3ab8 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -22,7 +22,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
22 auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair()); 22 auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair());
23 HLERequestContext context(std::move(session)); 23 HLERequestContext context(std::move(session));
24 24
25 auto process = Process::Create(CodeSet::Create("", 0)); 25 auto process = Process::Create("");
26 HandleTable handle_table; 26 HandleTable handle_table;
27 27
28 SECTION("works with empty cmdbuf") { 28 SECTION("works with empty cmdbuf") {
@@ -142,7 +142,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
142 auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair()); 142 auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair());
143 HLERequestContext context(std::move(session)); 143 HLERequestContext context(std::move(session));
144 144
145 auto process = Process::Create(CodeSet::Create("", 0)); 145 auto process = Process::Create("");
146 HandleTable handle_table; 146 HandleTable handle_table;
147 auto* input = context.CommandBuffer(); 147 auto* input = context.CommandBuffer();
148 u32_le output[IPC::COMMAND_BUFFER_LENGTH]; 148 u32_le output[IPC::COMMAND_BUFFER_LENGTH];
diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp
index a01b896f7..671afb702 100644
--- a/src/tests/core/memory/memory.cpp
+++ b/src/tests/core/memory/memory.cpp
@@ -9,7 +9,7 @@
9 9
10TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { 10TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
11 SECTION("these regions should not be mapped on an empty process") { 11 SECTION("these regions should not be mapped on an empty process") {
12 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); 12 auto process = Kernel::Process::Create("");
13 CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); 13 CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
14 CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); 14 CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false);
15 CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); 15 CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false);
@@ -20,14 +20,14 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
20 } 20 }
21 21
22 SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { 22 SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") {
23 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); 23 auto process = Kernel::Process::Create("");
24 Kernel::MapSharedPages(process->vm_manager); 24 Kernel::MapSharedPages(process->vm_manager);
25 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); 25 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true);
26 CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); 26 CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true);
27 } 27 }
28 28
29 SECTION("special regions should be valid after mapping them") { 29 SECTION("special regions should be valid after mapping them") {
30 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); 30 auto process = Kernel::Process::Create("");
31 SECTION("VRAM") { 31 SECTION("VRAM") {
32 Kernel::HandleSpecialMapping(process->vm_manager, 32 Kernel::HandleSpecialMapping(process->vm_manager,
33 {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); 33 {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
@@ -48,7 +48,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
48 } 48 }
49 49
50 SECTION("Unmapping a VAddr should make it invalid") { 50 SECTION("Unmapping a VAddr should make it invalid") {
51 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); 51 auto process = Kernel::Process::Create("");
52 Kernel::MapSharedPages(process->vm_manager); 52 Kernel::MapSharedPages(process->vm_manager);
53 process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); 53 process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
54 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); 54 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);