summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2022-03-07 20:28:39 -0800
committerGravatar GitHub2022-03-07 20:28:39 -0800
commit1f378960660a72ad0cf166c1efd08d4e956e07eb (patch)
treed277eaeb0c384df0b6bad4868e23a7da859f1f0b /src
parentMerge pull request #7930 from asLody/dma-semaphore (diff)
parenthle: kernel: KPageTable: Improve implementations of MapCodeMemory and UnmapCo... (diff)
downloadyuzu-1f378960660a72ad0cf166c1efd08d4e956e07eb.tar.gz
yuzu-1f378960660a72ad0cf166c1efd08d4e956e07eb.tar.xz
yuzu-1f378960660a72ad0cf166c1efd08d4e956e07eb.zip
Merge pull request #7974 from bunnei/improve-code-mem
Kernel Memory Updates (Part 5): Revamp MapCodeMemory and UnmapCodeMemory.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/k_page_table.cpp159
-rw-r--r--src/core/hle/kernel/k_page_table.h4
2 files changed, 116 insertions, 47 deletions
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index dfea0b6e2..0602de1f7 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -285,72 +285,141 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
285 return ResultSuccess; 285 return ResultSuccess;
286} 286}
287 287
288ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { 288ResultCode KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) {
289 // Validate the mapping request.
290 R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
291 ResultInvalidMemoryRegion);
292
293 // Lock the table.
289 KScopedLightLock lk(general_lock); 294 KScopedLightLock lk(general_lock);
290 295
291 const std::size_t num_pages{size / PageSize}; 296 // Verify that the source memory is normal heap.
297 KMemoryState src_state{};
298 KMemoryPermission src_perm{};
299 std::size_t num_src_allocator_blocks{};
300 R_TRY(this->CheckMemoryState(&src_state, &src_perm, nullptr, &num_src_allocator_blocks,
301 src_address, size, KMemoryState::All, KMemoryState::Normal,
302 KMemoryPermission::All, KMemoryPermission::UserReadWrite,
303 KMemoryAttribute::All, KMemoryAttribute::None));
292 304
293 KMemoryState state{}; 305 // Verify that the destination memory is unmapped.
294 KMemoryPermission perm{}; 306 std::size_t num_dst_allocator_blocks{};
295 CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size, 307 R_TRY(this->CheckMemoryState(&num_dst_allocator_blocks, dst_address, size, KMemoryState::All,
296 KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All, 308 KMemoryState::Free, KMemoryPermission::None,
297 KMemoryPermission::UserReadWrite, KMemoryAttribute::Mask, 309 KMemoryPermission::None, KMemoryAttribute::None,
298 KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); 310 KMemoryAttribute::None));
299 311
300 if (IsRegionMapped(dst_addr, size)) { 312 // Map the code memory.
301 return ResultInvalidCurrentMemory; 313 {
302 } 314 // Determine the number of pages being operated on.
315 const std::size_t num_pages = size / PageSize;
303 316
304 KPageLinkedList page_linked_list; 317 // Create page groups for the memory being mapped.
305 AddRegionToPages(src_addr, num_pages, page_linked_list); 318 KPageLinkedList pg;
319 AddRegionToPages(src_address, num_pages, pg);
306 320
307 { 321 // Reprotect the source as kernel-read/not mapped.
308 auto block_guard = detail::ScopeExit( 322 const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
309 [&] { Operate(src_addr, num_pages, perm, OperationType::ChangePermissions); }); 323 KMemoryPermission::NotMapped);
324 R_TRY(Operate(src_address, num_pages, new_perm, OperationType::ChangePermissions));
310 325
311 CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, 326 // Ensure that we unprotect the source pages on failure.
312 OperationType::ChangePermissions)); 327 auto unprot_guard = SCOPE_GUARD({
313 CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::None)); 328 ASSERT(this->Operate(src_address, num_pages, src_perm, OperationType::ChangePermissions)
329 .IsSuccess());
330 });
314 331
315 block_guard.Cancel(); 332 // Map the alias pages.
316 } 333 R_TRY(MapPages(dst_address, pg, new_perm));
317 334
318 block_manager->Update(src_addr, num_pages, state, KMemoryPermission::None, 335 // We successfully mapped the alias pages, so we don't need to unprotect the src pages on
319 KMemoryAttribute::Locked); 336 // failure.
320 block_manager->Update(dst_addr, num_pages, KMemoryState::AliasCode); 337 unprot_guard.Cancel();
338
339 // Apply the memory block updates.
340 block_manager->Update(src_address, num_pages, src_state, new_perm,
341 KMemoryAttribute::Locked);
342 block_manager->Update(dst_address, num_pages, KMemoryState::AliasCode, new_perm,
343 KMemoryAttribute::None);
344 }
321 345
322 return ResultSuccess; 346 return ResultSuccess;
323} 347}
324 348
325ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { 349ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) {
350 // Validate the mapping request.
351 R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
352 ResultInvalidMemoryRegion);
353
354 // Lock the table.
326 KScopedLightLock lk(general_lock); 355 KScopedLightLock lk(general_lock);
327 356
328 if (!size) { 357 // Verify that the source memory is locked normal heap.
329 return ResultSuccess; 358 std::size_t num_src_allocator_blocks{};
359 R_TRY(this->CheckMemoryState(std::addressof(num_src_allocator_blocks), src_address, size,
360 KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None,
361 KMemoryPermission::None, KMemoryAttribute::All,
362 KMemoryAttribute::Locked));
363
364 // Verify that the destination memory is aliasable code.
365 std::size_t num_dst_allocator_blocks{};
366 R_TRY(this->CheckMemoryStateContiguous(
367 std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias,
368 KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
369 KMemoryAttribute::All, KMemoryAttribute::None));
370
371 // Determine whether any pages being unmapped are code.
372 bool any_code_pages = false;
373 {
374 KMemoryBlockManager::const_iterator it = block_manager->FindIterator(dst_address);
375 while (true) {
376 // Get the memory info.
377 const KMemoryInfo info = it->GetMemoryInfo();
378
379 // Check if the memory has code flag.
380 if ((info.GetState() & KMemoryState::FlagCode) != KMemoryState::None) {
381 any_code_pages = true;
382 break;
383 }
384
385 // Check if we're done.
386 if (dst_address + size - 1 <= info.GetLastAddress()) {
387 break;
388 }
389
390 // Advance.
391 ++it;
392 }
330 } 393 }
331 394
332 const std::size_t num_pages{size / PageSize}; 395 // Ensure that we maintain the instruction cache.
396 bool reprotected_pages = false;
397 SCOPE_EXIT({
398 if (reprotected_pages && any_code_pages) {
399 system.InvalidateCpuInstructionCacheRange(dst_address, size);
400 }
401 });
333 402
334 CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, nullptr, src_addr, size, 403 // Unmap.
335 KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None, 404 {
336 KMemoryPermission::None, KMemoryAttribute::Mask, 405 // Determine the number of pages being operated on.
337 KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); 406 const std::size_t num_pages = size / PageSize;
338 407
339 KMemoryState state{}; 408 // Unmap the aliased copy of the pages.
340 CASCADE_CODE(CheckMemoryState( 409 R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap));
341 &state, nullptr, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias,
342 KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
343 KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
344 CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None,
345 KMemoryPermission::None, KMemoryAttribute::Mask,
346 KMemoryAttribute::None));
347 CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
348 410
349 block_manager->Update(dst_addr, num_pages, KMemoryState::Free); 411 // Try to set the permissions for the source pages back to what they should be.
350 block_manager->Update(src_addr, num_pages, KMemoryState::Normal, 412 R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
351 KMemoryPermission::UserReadWrite); 413 OperationType::ChangePermissions));
352 414
353 system.InvalidateCpuInstructionCacheRange(dst_addr, size); 415 // Apply the memory block updates.
416 block_manager->Update(dst_address, num_pages, KMemoryState::None);
417 block_manager->Update(src_address, num_pages, KMemoryState::Normal,
418 KMemoryPermission::UserReadWrite);
419
420 // Note that we reprotected pages.
421 reprotected_pages = true;
422 }
354 423
355 return ResultSuccess; 424 return ResultSuccess;
356} 425}
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 194177332..aea1b8f63 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -36,8 +36,8 @@ public:
36 KMemoryManager::Pool pool); 36 KMemoryManager::Pool pool);
37 ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, 37 ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
38 KMemoryPermission perm); 38 KMemoryPermission perm);
39 ResultCode MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); 39 ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
40 ResultCode UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); 40 ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
41 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, 41 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
42 VAddr src_addr); 42 VAddr src_addr);
43 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); 43 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);