summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/svc.cpp70
-rw-r--r--src/core/hle/kernel/svc_wrap.h7
-rw-r--r--src/core/hle/kernel/vm_manager.cpp29
-rw-r--r--src/core/hle/kernel/vm_manager.h26
4 files changed, 131 insertions, 1 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index e5d4d6b55..0aa2e358e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1189,6 +1189,74 @@ static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address,
1189 query_address); 1189 query_address);
1190} 1190}
1191 1191
1192static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
1193 u64 src_address, u64 size) {
1194 LOG_DEBUG(Kernel_SVC,
1195 "called. process_handle=0x{:08X}, dst_address=0x{:016X}, "
1196 "src_address=0x{:016X}, size=0x{:016X}",
1197 process_handle, dst_address, src_address, size);
1198
1199 if (!Common::Is4KBAligned(src_address)) {
1200 LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
1201 src_address);
1202 return ERR_INVALID_ADDRESS;
1203 }
1204
1205 if (!Common::Is4KBAligned(dst_address)) {
1206 LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
1207 dst_address);
1208 return ERR_INVALID_ADDRESS;
1209 }
1210
1211 if (size == 0 || !Common::Is4KBAligned(size)) {
1212 LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
1213 return ERR_INVALID_SIZE;
1214 }
1215
1216 if (!IsValidAddressRange(dst_address, size)) {
1217 LOG_ERROR(Kernel_SVC,
1218 "Destination address range overflows the address space (dst_address=0x{:016X}, "
1219 "size=0x{:016X}).",
1220 dst_address, size);
1221 return ERR_INVALID_ADDRESS_STATE;
1222 }
1223
1224 if (!IsValidAddressRange(src_address, size)) {
1225 LOG_ERROR(Kernel_SVC,
1226 "Source address range overflows the address space (src_address=0x{:016X}, "
1227 "size=0x{:016X}).",
1228 src_address, size);
1229 return ERR_INVALID_ADDRESS_STATE;
1230 }
1231
1232 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1233 auto process = handle_table.Get<Process>(process_handle);
1234 if (!process) {
1235 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1236 process_handle);
1237 return ERR_INVALID_HANDLE;
1238 }
1239
1240 auto& vm_manager = process->VMManager();
1241 if (!vm_manager.IsWithinAddressSpace(src_address, size)) {
1242 LOG_ERROR(Kernel_SVC,
1243 "Source address range is not within the address space (src_address=0x{:016X}, "
1244 "size=0x{:016X}).",
1245 src_address, size);
1246 return ERR_INVALID_ADDRESS_STATE;
1247 }
1248
1249 if (!vm_manager.IsWithinASLRRegion(dst_address, size)) {
1250 LOG_ERROR(Kernel_SVC,
1251 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1252 "size=0x{:016X}).",
1253 dst_address, size);
1254 return ERR_INVALID_MEMORY_RANGE;
1255 }
1256
1257 return vm_manager.MapCodeMemory(dst_address, src_address, size);
1258}
1259
1192/// Exits the current process 1260/// Exits the current process
1193static void ExitProcess(Core::System& system) { 1261static void ExitProcess(Core::System& system) {
1194 auto* current_process = system.Kernel().CurrentProcess(); 1262 auto* current_process = system.Kernel().CurrentProcess();
@@ -2217,7 +2285,7 @@ static const FunctionDef SVC_Table[] = {
2217 {0x74, nullptr, "MapProcessMemory"}, 2285 {0x74, nullptr, "MapProcessMemory"},
2218 {0x75, nullptr, "UnmapProcessMemory"}, 2286 {0x75, nullptr, "UnmapProcessMemory"},
2219 {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"}, 2287 {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"},
2220 {0x77, nullptr, "MapProcessCodeMemory"}, 2288 {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"},
2221 {0x78, nullptr, "UnmapProcessCodeMemory"}, 2289 {0x78, nullptr, "UnmapProcessCodeMemory"},
2222 {0x79, nullptr, "CreateProcess"}, 2290 {0x79, nullptr, "CreateProcess"},
2223 {0x7A, nullptr, "StartProcess"}, 2291 {0x7A, nullptr, "StartProcess"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index b3690b5f3..865473c6f 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -44,6 +44,13 @@ void SvcWrap(Core::System& system) {
44 func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw); 44 func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
45} 45}
46 46
47template <ResultCode func(Core::System&, u32, u64, u64, u64)>
48void SvcWrap(Core::System& system) {
49 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
50 Param(system, 2), Param(system, 3))
51 .raw);
52}
53
47template <ResultCode func(Core::System&, u32*)> 54template <ResultCode func(Core::System&, u32*)>
48void SvcWrap(Core::System& system) { 55void SvcWrap(Core::System& system) {
49 u32 param = 0; 56 u32 param = 0;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index ec0a480ce..76b491c47 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -302,6 +302,35 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
302 return MakeResult<VAddr>(heap_region_base); 302 return MakeResult<VAddr>(heap_region_base);
303} 303}
304 304
305ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) {
306 constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped;
307 const auto src_check_result = CheckRangeState(
308 src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::All,
309 VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
310
311 if (src_check_result.Failed()) {
312 return src_check_result.Code();
313 }
314
315 const auto mirror_result =
316 MirrorMemory(dst_address, src_address, size, MemoryState::ModuleCode);
317 if (mirror_result.IsError()) {
318 return mirror_result;
319 }
320
321 // Ensure we lock the source memory region.
322 const auto src_vma_result = CarveVMARange(src_address, size);
323 if (src_vma_result.Failed()) {
324 return src_vma_result.Code();
325 }
326 auto src_vma_iter = *src_vma_result;
327 src_vma_iter->second.attribute = MemoryAttribute::Locked;
328 Reprotect(src_vma_iter, VMAPermission::Read);
329
330 // The destination memory region is fine as is, however we need to make it read-only.
331 return ReprotectRange(dst_address, size, VMAPermission::Read);
332}
333
305MemoryInfo VMManager::QueryMemory(VAddr address) const { 334MemoryInfo VMManager::QueryMemory(VAddr address) const {
306 const auto vma = FindVMA(address); 335 const auto vma = FindVMA(address);
307 MemoryInfo memory_info{}; 336 MemoryInfo memory_info{};
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 6f484b7bf..27120d3b1 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -43,6 +43,9 @@ enum class VMAPermission : u8 {
43 ReadExecute = Read | Execute, 43 ReadExecute = Read | Execute,
44 WriteExecute = Write | Execute, 44 WriteExecute = Write | Execute,
45 ReadWriteExecute = Read | Write | Execute, 45 ReadWriteExecute = Read | Write | Execute,
46
47 // Used as a wildcard when checking permissions across memory ranges
48 All = 0xFF,
46}; 49};
47 50
48constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) { 51constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) {
@@ -152,6 +155,9 @@ enum class MemoryState : u32 {
152 FlagUncached = 1U << 24, 155 FlagUncached = 1U << 24,
153 FlagCodeMemory = 1U << 25, 156 FlagCodeMemory = 1U << 25,
154 157
158 // Wildcard used in range checking to indicate all states.
159 All = 0xFFFFFFFF,
160
155 // Convenience flag sets to reduce repetition 161 // Convenience flag sets to reduce repetition
156 IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1, 162 IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1,
157 163
@@ -415,6 +421,26 @@ public:
415 /// 421 ///
416 ResultVal<VAddr> SetHeapSize(u64 size); 422 ResultVal<VAddr> SetHeapSize(u64 size);
417 423
424 /// Maps a region of memory as code memory.
425 ///
426 /// @param dst_address The base address of the region to create the aliasing memory region.
427 /// @param src_address The base address of the region to be aliased.
428 /// @param size The total amount of memory to map in bytes.
429 ///
430 /// @pre Both memory regions lie within the actual addressable address space.
431 ///
432 /// @post After this function finishes execution, assuming success, then the address range
433 /// [dst_address, dst_address+size) will alias the memory region,
434 /// [src_address, src_address+size).
435 /// <p>
436 /// What this also entails is as follows:
437 /// 1. The aliased region gains the Locked memory attribute.
438 /// 2. The aliased region becomes read-only.
439 /// 3. The aliasing region becomes read-only.
440 /// 4. The aliasing region is created with a memory state of MemoryState::CodeModule.
441 ///
442 ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size);
443
418 /// Queries the memory manager for information about the given address. 444 /// Queries the memory manager for information about the given address.
419 /// 445 ///
420 /// @param address The address to query the memory manager about for information. 446 /// @param address The address to query the memory manager about for information.