diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 70 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 51 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 23 |
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 | ||
| 1260 | ResultCode 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 |
| 1261 | static void ExitProcess(Core::System& system) { | 1329 | static 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 | ||
| 334 | ResultCode 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 | |||
| 334 | MemoryInfo VMManager::QueryMemory(VAddr address) const { | 385 | MemoryInfo 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. |