summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/svc.cpp70
-rw-r--r--src/core/hle/kernel/vm_manager.cpp51
-rw-r--r--src/core/hle/kernel/vm_manager.h23
3 files changed, 143 insertions, 1 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 0aa2e358e..d48a2203a 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1257,6 +1257,74 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
1257 return vm_manager.MapCodeMemory(dst_address, src_address, size); 1257 return vm_manager.MapCodeMemory(dst_address, src_address, size);
1258} 1258}
1259 1259
1260ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
1261 u64 src_address, u64 size) {
1262 LOG_DEBUG(Kernel_SVC,
1263 "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, "
1264 "size=0x{:016X}",
1265 process_handle, dst_address, src_address, size);
1266
1267 if (!Common::Is4KBAligned(dst_address)) {
1268 LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
1269 dst_address);
1270 return ERR_INVALID_ADDRESS;
1271 }
1272
1273 if (!Common::Is4KBAligned(src_address)) {
1274 LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
1275 src_address);
1276 return ERR_INVALID_ADDRESS;
1277 }
1278
1279 if (size == 0 || Common::Is4KBAligned(size)) {
1280 LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
1281 return ERR_INVALID_SIZE;
1282 }
1283
1284 if (!IsValidAddressRange(dst_address, size)) {
1285 LOG_ERROR(Kernel_SVC,
1286 "Destination address range overflows the address space (dst_address=0x{:016X}, "
1287 "size=0x{:016X}).",
1288 dst_address, size);
1289 return ERR_INVALID_ADDRESS_STATE;
1290 }
1291
1292 if (!IsValidAddressRange(src_address, size)) {
1293 LOG_ERROR(Kernel_SVC,
1294 "Source address range overflows the address space (src_address=0x{:016X}, "
1295 "size=0x{:016X}).",
1296 src_address, size);
1297 return ERR_INVALID_ADDRESS_STATE;
1298 }
1299
1300 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1301 auto process = handle_table.Get<Process>(process_handle);
1302 if (!process) {
1303 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1304 process_handle);
1305 return ERR_INVALID_HANDLE;
1306 }
1307
1308 auto& vm_manager = process->VMManager();
1309 if (!vm_manager.IsWithinAddressSpace(src_address, size)) {
1310 LOG_ERROR(Kernel_SVC,
1311 "Source address range is not within the address space (src_address=0x{:016X}, "
1312 "size=0x{:016X}).",
1313 src_address, size);
1314 return ERR_INVALID_ADDRESS_STATE;
1315 }
1316
1317 if (!vm_manager.IsWithinASLRRegion(dst_address, size)) {
1318 LOG_ERROR(Kernel_SVC,
1319 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1320 "size=0x{:016X}).",
1321 dst_address, size);
1322 return ERR_INVALID_MEMORY_RANGE;
1323 }
1324
1325 return vm_manager.UnmapCodeMemory(dst_address, src_address, size);
1326}
1327
1260/// Exits the current process 1328/// Exits the current process
1261static void ExitProcess(Core::System& system) { 1329static void ExitProcess(Core::System& system) {
1262 auto* current_process = system.Kernel().CurrentProcess(); 1330 auto* current_process = system.Kernel().CurrentProcess();
@@ -2286,7 +2354,7 @@ static const FunctionDef SVC_Table[] = {
2286 {0x75, nullptr, "UnmapProcessMemory"}, 2354 {0x75, nullptr, "UnmapProcessMemory"},
2287 {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"}, 2355 {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"},
2288 {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"}, 2356 {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"},
2289 {0x78, nullptr, "UnmapProcessCodeMemory"}, 2357 {0x78, SvcWrap<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
2290 {0x79, nullptr, "CreateProcess"}, 2358 {0x79, nullptr, "CreateProcess"},
2291 {0x7A, nullptr, "StartProcess"}, 2359 {0x7A, nullptr, "StartProcess"},
2292 {0x7B, nullptr, "TerminateProcess"}, 2360 {0x7B, nullptr, "TerminateProcess"},
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 76b491c47..f0c0c12fc 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -331,6 +331,57 @@ ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 si
331 return ReprotectRange(dst_address, size, VMAPermission::Read); 331 return ReprotectRange(dst_address, size, VMAPermission::Read);
332} 332}
333 333
334ResultCode VMManager::UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) {
335 constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped;
336 const auto src_check_result = CheckRangeState(
337 src_address, size, MemoryState::All, MemoryState::Heap, VMAPermission::None,
338 VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, ignore_attribute);
339
340 if (src_check_result.Failed()) {
341 return src_check_result.Code();
342 }
343
344 // Yes, the kernel only checks the first page of the region.
345 const auto dst_check_result =
346 CheckRangeState(dst_address, Memory::PAGE_SIZE, MemoryState::FlagModule,
347 MemoryState::FlagModule, VMAPermission::None, VMAPermission::None,
348 MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
349
350 if (dst_check_result.Failed()) {
351 return dst_check_result.Code();
352 }
353
354 const auto dst_memory_state = std::get<MemoryState>(*dst_check_result);
355 const auto dst_contiguous_check_result = CheckRangeState(
356 dst_address, size, MemoryState::All, dst_memory_state, VMAPermission::None,
357 VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::None, ignore_attribute);
358
359 if (dst_contiguous_check_result.Failed()) {
360 return dst_contiguous_check_result.Code();
361 }
362
363 const auto unmap_result = UnmapRange(dst_address, size);
364 if (unmap_result.IsError()) {
365 return unmap_result;
366 }
367
368 // With the mirrored portion unmapped, restore the original region's traits.
369 const auto src_vma_result = CarveVMARange(src_address, size);
370 if (src_vma_result.Failed()) {
371 return src_vma_result.Code();
372 }
373 auto src_vma_iter = *src_vma_result;
374 src_vma_iter->second.state = MemoryState::Heap;
375 src_vma_iter->second.attribute = MemoryAttribute::None;
376 Reprotect(src_vma_iter, VMAPermission::ReadWrite);
377
378 if (dst_memory_state == MemoryState::ModuleCode) {
379 Core::System::GetInstance().InvalidateCpuInstructionCaches();
380 }
381
382 return unmap_result;
383}
384
334MemoryInfo VMManager::QueryMemory(VAddr address) const { 385MemoryInfo VMManager::QueryMemory(VAddr address) const {
335 const auto vma = FindVMA(address); 386 const auto vma = FindVMA(address);
336 MemoryInfo memory_info{}; 387 MemoryInfo memory_info{};
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 27120d3b1..288eb9450 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -441,6 +441,29 @@ public:
441 /// 441 ///
442 ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size); 442 ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size);
443 443
444 /// Unmaps a region of memory designated as code module memory.
445 ///
446 /// @param dst_address The base address of the memory region aliasing the source memory region.
447 /// @param src_address The base address of the memory region being aliased.
448 /// @param size The size of the memory region to unmap in bytes.
449 ///
450 /// @pre Both memory ranges lie within the actual addressable address space.
451 ///
452 /// @pre The memory region being unmapped has been previously been mapped
453 /// by a call to MapCodeMemory.
454 ///
455 /// @post After execution of the function, if successful. the aliasing memory region
456 /// will be unmapped and the aliased region will have various traits about it
457 /// restored to what they were prior to the original mapping call preceding
458 /// this function call.
459 /// <p>
460 /// What this also entails is as follows:
461 /// 1. The state of the memory region will now indicate a general heap region.
462 /// 2. All memory attributes for the memory region are cleared.
463 /// 3. Memory permissions for the region are restored to user read/write.
464 ///
465 ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 size);
466
444 /// Queries the memory manager for information about the given address. 467 /// Queries the memory manager for information about the given address.
445 /// 468 ///
446 /// @param address The address to query the memory manager about for information. 469 /// @param address The address to query the memory manager about for information.