diff options
| author | 2022-01-14 00:41:17 -0500 | |
|---|---|---|
| committer | 2022-01-14 00:41:17 -0500 | |
| commit | 07e477f891c015b76cadb4421feabd78852a715b (patch) | |
| tree | 35dbd81c5bcce0c85132531e9e21fd874b07e297 /src | |
| parent | Merge pull request #7690 from Morph1984/increase-file-limit-win (diff) | |
| parent | hle: kernel: k_page_table: Update SetProcessMemoryPermission. (diff) | |
| download | yuzu-07e477f891c015b76cadb4421feabd78852a715b.tar.gz yuzu-07e477f891c015b76cadb4421feabd78852a715b.tar.xz yuzu-07e477f891c015b76cadb4421feabd78852a715b.zip | |
Merge pull request #7698 from bunnei/mem-code-memory-updates
Kernel Memory Updates (Part 2): SetProcessMemoryPermission, update permissions, and other minor changes.
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 105 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.h | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/physical_core.cpp | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 38 |
6 files changed, 107 insertions, 81 deletions
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 6077985b5..27d86c9a4 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -298,7 +298,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory | |||
| 298 | return ResultSuccess; | 298 | return ResultSuccess; |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { | 301 | ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { |
| 302 | std::lock_guard lock{page_table_lock}; | 302 | std::lock_guard lock{page_table_lock}; |
| 303 | 303 | ||
| 304 | const std::size_t num_pages{size / PageSize}; | 304 | const std::size_t num_pages{size / PageSize}; |
| @@ -307,7 +307,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std: | |||
| 307 | KMemoryPermission perm{}; | 307 | KMemoryPermission perm{}; |
| 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size, | 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size, |
| 309 | KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All, | 309 | KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All, |
| 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, | 310 | KMemoryPermission::UserReadWrite, KMemoryAttribute::Mask, |
| 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 312 | 312 | ||
| 313 | if (IsRegionMapped(dst_addr, size)) { | 313 | if (IsRegionMapped(dst_addr, size)) { |
| @@ -335,7 +335,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std: | |||
| 335 | return ResultSuccess; | 335 | return ResultSuccess; |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { | 338 | ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { |
| 339 | std::lock_guard lock{page_table_lock}; | 339 | std::lock_guard lock{page_table_lock}; |
| 340 | 340 | ||
| 341 | if (!size) { | 341 | if (!size) { |
| @@ -361,7 +361,7 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st | |||
| 361 | 361 | ||
| 362 | block_manager->Update(dst_addr, num_pages, KMemoryState::Free); | 362 | block_manager->Update(dst_addr, num_pages, KMemoryState::Free); |
| 363 | block_manager->Update(src_addr, num_pages, KMemoryState::Normal, | 363 | block_manager->Update(src_addr, num_pages, KMemoryState::Normal, |
| 364 | KMemoryPermission::ReadAndWrite); | 364 | KMemoryPermission::UserReadWrite); |
| 365 | 365 | ||
| 366 | system.InvalidateCpuInstructionCacheRange(dst_addr, size); | 366 | system.InvalidateCpuInstructionCacheRange(dst_addr, size); |
| 367 | 367 | ||
| @@ -416,7 +416,7 @@ void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr star | |||
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; | 418 | const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; |
| 419 | Operate(dst_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::Map, | 419 | Operate(dst_addr, num_pages, KMemoryPermission::UserReadWrite, OperationType::Map, |
| 420 | map_addr); | 420 | map_addr); |
| 421 | 421 | ||
| 422 | dst_addr += num_pages * PageSize; | 422 | dst_addr += num_pages * PageSize; |
| @@ -470,7 +470,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 470 | const std::size_t num_pages{size / PageSize}; | 470 | const std::size_t num_pages{size / PageSize}; |
| 471 | block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, | 471 | block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, |
| 472 | KMemoryAttribute::None, KMemoryState::Normal, | 472 | KMemoryAttribute::None, KMemoryState::Normal, |
| 473 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); | 473 | KMemoryPermission::UserReadWrite, KMemoryAttribute::None); |
| 474 | 474 | ||
| 475 | return ResultSuccess; | 475 | return ResultSuccess; |
| 476 | } | 476 | } |
| @@ -554,7 +554,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 554 | KMemoryState src_state{}; | 554 | KMemoryState src_state{}; |
| 555 | CASCADE_CODE(CheckMemoryState( | 555 | CASCADE_CODE(CheckMemoryState( |
| 556 | &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 556 | &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 557 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite, | 557 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::UserReadWrite, |
| 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 559 | 559 | ||
| 560 | if (IsRegionMapped(dst_addr, size)) { | 560 | if (IsRegionMapped(dst_addr, size)) { |
| @@ -568,13 +568,13 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 568 | 568 | ||
| 569 | { | 569 | { |
| 570 | auto block_guard = detail::ScopeExit([&] { | 570 | auto block_guard = detail::ScopeExit([&] { |
| 571 | Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, | 571 | Operate(src_addr, num_pages, KMemoryPermission::UserReadWrite, |
| 572 | OperationType::ChangePermissions); | 572 | OperationType::ChangePermissions); |
| 573 | }); | 573 | }); |
| 574 | 574 | ||
| 575 | CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, | 575 | CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, |
| 576 | OperationType::ChangePermissions)); | 576 | OperationType::ChangePermissions)); |
| 577 | CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::ReadAndWrite)); | 577 | CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::UserReadWrite)); |
| 578 | 578 | ||
| 579 | block_guard.Cancel(); | 579 | block_guard.Cancel(); |
| 580 | } | 580 | } |
| @@ -582,7 +582,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 582 | block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None, | 582 | block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None, |
| 583 | KMemoryAttribute::Locked); | 583 | KMemoryAttribute::Locked); |
| 584 | block_manager->Update(dst_addr, num_pages, KMemoryState::Stack, | 584 | block_manager->Update(dst_addr, num_pages, KMemoryState::Stack, |
| 585 | KMemoryPermission::ReadAndWrite); | 585 | KMemoryPermission::UserReadWrite); |
| 586 | 586 | ||
| 587 | return ResultSuccess; | 587 | return ResultSuccess; |
| 588 | } | 588 | } |
| @@ -617,13 +617,13 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 617 | auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); | 617 | auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); |
| 618 | 618 | ||
| 619 | CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); | 619 | CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); |
| 620 | CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, | 620 | CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::UserReadWrite, |
| 621 | OperationType::ChangePermissions)); | 621 | OperationType::ChangePermissions)); |
| 622 | 622 | ||
| 623 | block_guard.Cancel(); | 623 | block_guard.Cancel(); |
| 624 | } | 624 | } |
| 625 | 625 | ||
| 626 | block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::ReadAndWrite); | 626 | block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::UserReadWrite); |
| 627 | block_manager->Update(dst_addr, num_pages, KMemoryState::Free); | 627 | block_manager->Update(dst_addr, num_pages, KMemoryState::Free); |
| 628 | 628 | ||
| 629 | return ResultSuccess; | 629 | return ResultSuccess; |
| @@ -713,50 +713,61 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, | |||
| 713 | } | 713 | } |
| 714 | 714 | ||
| 715 | ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, | 715 | ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, |
| 716 | KMemoryPermission perm) { | 716 | Svc::MemoryPermission svc_perm) { |
| 717 | const size_t num_pages = size / PageSize; | ||
| 717 | 718 | ||
| 719 | // Lock the table. | ||
| 718 | std::lock_guard lock{page_table_lock}; | 720 | std::lock_guard lock{page_table_lock}; |
| 719 | 721 | ||
| 720 | KMemoryState prev_state{}; | 722 | // Verify we can change the memory permission. |
| 721 | KMemoryPermission prev_perm{}; | 723 | KMemoryState old_state; |
| 722 | 724 | KMemoryPermission old_perm; | |
| 723 | CASCADE_CODE(CheckMemoryState( | 725 | size_t num_allocator_blocks; |
| 724 | &prev_state, &prev_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCode, | 726 | R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, |
| 725 | KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, | 727 | std::addressof(num_allocator_blocks), addr, size, |
| 726 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 728 | KMemoryState::FlagCode, KMemoryState::FlagCode, |
| 727 | 729 | KMemoryPermission::None, KMemoryPermission::None, | |
| 728 | KMemoryState state{prev_state}; | 730 | KMemoryAttribute::All, KMemoryAttribute::None)); |
| 729 | 731 | ||
| 730 | // Ensure state is mutable if permission allows write | 732 | // Determine new perm/state. |
| 731 | if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { | 733 | const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); |
| 732 | if (prev_state == KMemoryState::Code) { | 734 | KMemoryState new_state = old_state; |
| 733 | state = KMemoryState::CodeData; | 735 | const bool is_w = (new_perm & KMemoryPermission::UserWrite) == KMemoryPermission::UserWrite; |
| 734 | } else if (prev_state == KMemoryState::AliasCode) { | 736 | const bool is_x = (new_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute; |
| 735 | state = KMemoryState::AliasCodeData; | 737 | const bool was_x = |
| 736 | } else { | 738 | (old_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute; |
| 739 | ASSERT(!(is_w && is_x)); | ||
| 740 | |||
| 741 | if (is_w) { | ||
| 742 | switch (old_state) { | ||
| 743 | case KMemoryState::Code: | ||
| 744 | new_state = KMemoryState::CodeData; | ||
| 745 | break; | ||
| 746 | case KMemoryState::AliasCode: | ||
| 747 | new_state = KMemoryState::AliasCodeData; | ||
| 748 | break; | ||
| 749 | default: | ||
| 737 | UNREACHABLE(); | 750 | UNREACHABLE(); |
| 738 | } | 751 | } |
| 739 | } | 752 | } |
| 740 | 753 | ||
| 741 | // Return early if there is nothing to change | 754 | // Succeed if there's nothing to do. |
| 742 | if (state == prev_state && perm == prev_perm) { | 755 | R_SUCCEED_IF(old_perm == new_perm && old_state == new_state); |
| 743 | return ResultSuccess; | ||
| 744 | } | ||
| 745 | 756 | ||
| 746 | if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) { | 757 | // Perform mapping operation. |
| 758 | const auto operation = | ||
| 759 | was_x ? OperationType::ChangePermissionsAndRefresh : OperationType::ChangePermissions; | ||
| 760 | R_TRY(Operate(addr, num_pages, new_perm, operation)); | ||
| 761 | |||
| 762 | // Update the blocks. | ||
| 763 | block_manager->Update(addr, num_pages, new_state, new_perm, KMemoryAttribute::None); | ||
| 764 | |||
| 765 | // Ensure cache coherency, if we're setting pages as executable. | ||
| 766 | if (is_x) { | ||
| 747 | // Memory execution state is changing, invalidate CPU cache range | 767 | // Memory execution state is changing, invalidate CPU cache range |
| 748 | system.InvalidateCpuInstructionCacheRange(addr, size); | 768 | system.InvalidateCpuInstructionCacheRange(addr, size); |
| 749 | } | 769 | } |
| 750 | 770 | ||
| 751 | const std::size_t num_pages{size / PageSize}; | ||
| 752 | const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None | ||
| 753 | ? OperationType::ChangePermissionsAndRefresh | ||
| 754 | : OperationType::ChangePermissions}; | ||
| 755 | |||
| 756 | CASCADE_CODE(Operate(addr, num_pages, perm, operation)); | ||
| 757 | |||
| 758 | block_manager->Update(addr, num_pages, state, perm); | ||
| 759 | |||
| 760 | return ResultSuccess; | 771 | return ResultSuccess; |
| 761 | } | 772 | } |
| 762 | 773 | ||
| @@ -785,7 +796,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo | |||
| 785 | &state, nullptr, &attribute, nullptr, addr, size, | 796 | &state, nullptr, &attribute, nullptr, addr, size, |
| 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, | 797 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, |
| 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, | 798 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, |
| 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, | 799 | KMemoryPermission::UserReadWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, |
| 789 | KMemoryAttribute::IpcAndDeviceMapped)); | 800 | KMemoryAttribute::IpcAndDeviceMapped)); |
| 790 | 801 | ||
| 791 | block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked); | 802 | block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked); |
| @@ -805,7 +816,7 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) { | |||
| 805 | KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, | 816 | KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, |
| 806 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 817 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 807 | 818 | ||
| 808 | block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); | 819 | block_manager->Update(addr, size / PageSize, state, KMemoryPermission::UserReadWrite); |
| 809 | return ResultSuccess; | 820 | return ResultSuccess; |
| 810 | } | 821 | } |
| 811 | 822 | ||
| @@ -906,7 +917,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) { | |||
| 906 | R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), | 917 | R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), |
| 907 | heap_region_start + size, GetHeapSize() - size, | 918 | heap_region_start + size, GetHeapSize() - size, |
| 908 | KMemoryState::All, KMemoryState::Normal, | 919 | KMemoryState::All, KMemoryState::Normal, |
| 909 | KMemoryPermission::All, KMemoryPermission::ReadAndWrite, | 920 | KMemoryPermission::All, KMemoryPermission::UserReadWrite, |
| 910 | KMemoryAttribute::All, KMemoryAttribute::None)); | 921 | KMemoryAttribute::All, KMemoryAttribute::None)); |
| 911 | 922 | ||
| 912 | // Unmap the end of the heap. | 923 | // Unmap the end of the heap. |
| @@ -981,7 +992,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) { | |||
| 981 | 992 | ||
| 982 | // Apply the memory block update. | 993 | // Apply the memory block update. |
| 983 | block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal, | 994 | block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal, |
| 984 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); | 995 | KMemoryPermission::UserReadWrite, KMemoryAttribute::None); |
| 985 | 996 | ||
| 986 | // Update the current heap end. | 997 | // Update the current heap end. |
| 987 | current_heap_end = heap_region_start + size; | 998 | current_heap_end = heap_region_start + size; |
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 9235b822a..274644181 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -31,8 +31,8 @@ public: | |||
| 31 | KMemoryManager::Pool pool); | 31 | KMemoryManager::Pool pool); |
| 32 | ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, | 32 | ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, |
| 33 | KMemoryPermission perm); | 33 | KMemoryPermission perm); |
| 34 | ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); | 34 | ResultCode MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); |
| 35 | ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); | 35 | ResultCode UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); |
| 36 | ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, | 36 | ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, |
| 37 | VAddr src_addr); | 37 | VAddr src_addr); |
| 38 | ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); | 38 | ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); |
| @@ -43,7 +43,8 @@ public: | |||
| 43 | ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, | 43 | ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, |
| 44 | KMemoryPermission perm); | 44 | KMemoryPermission perm); |
| 45 | ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); | 45 | ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); |
| 46 | ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); | 46 | ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, |
| 47 | Svc::MemoryPermission svc_perm); | ||
| 47 | KMemoryInfo QueryInfo(VAddr addr); | 48 | KMemoryInfo QueryInfo(VAddr addr); |
| 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | 49 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); | 50 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index bf98a51e2..cca405fed 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -509,7 +509,7 @@ VAddr KProcess::CreateTLSRegion() { | |||
| 509 | const VAddr tls_page_addr{page_table | 509 | const VAddr tls_page_addr{page_table |
| 510 | ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, | 510 | ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, |
| 511 | KMemoryState::ThreadLocal, | 511 | KMemoryState::ThreadLocal, |
| 512 | KMemoryPermission::ReadAndWrite, | 512 | KMemoryPermission::UserReadWrite, |
| 513 | tls_map_addr) | 513 | tls_map_addr) |
| 514 | .ValueOr(0)}; | 514 | .ValueOr(0)}; |
| 515 | 515 | ||
| @@ -541,16 +541,16 @@ void KProcess::FreeTLSRegion(VAddr tls_address) { | |||
| 541 | 541 | ||
| 542 | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { | 542 | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { |
| 543 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, | 543 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, |
| 544 | KMemoryPermission permission) { | 544 | Svc::MemoryPermission permission) { |
| 545 | page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); | 545 | page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); |
| 546 | }; | 546 | }; |
| 547 | 547 | ||
| 548 | kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), | 548 | kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), |
| 549 | code_set.memory.size()); | 549 | code_set.memory.size()); |
| 550 | 550 | ||
| 551 | ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); | 551 | ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute); |
| 552 | ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); | 552 | ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read); |
| 553 | ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); | 553 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | bool KProcess::IsSignaled() const { | 556 | bool KProcess::IsSignaled() const { |
| @@ -587,7 +587,7 @@ ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) { | |||
| 587 | CASCADE_RESULT(main_thread_stack_top, | 587 | CASCADE_RESULT(main_thread_stack_top, |
| 588 | page_table->AllocateAndMapMemory( | 588 | page_table->AllocateAndMapMemory( |
| 589 | main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, | 589 | main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, |
| 590 | KMemoryState::Stack, KMemoryPermission::ReadAndWrite)); | 590 | KMemoryState::Stack, KMemoryPermission::UserReadWrite)); |
| 591 | 591 | ||
| 592 | main_thread_stack_top += main_thread_stack_size; | 592 | main_thread_stack_top += main_thread_stack_size; |
| 593 | 593 | ||
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 7f02d9471..7477668e4 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp | |||
| @@ -16,17 +16,25 @@ namespace Kernel { | |||
| 16 | PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, | 16 | PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, |
| 17 | Core::CPUInterrupts& interrupts_) | 17 | Core::CPUInterrupts& interrupts_) |
| 18 | : core_index{core_index_}, system{system_}, scheduler{scheduler_}, | 18 | : core_index{core_index_}, system{system_}, scheduler{scheduler_}, |
| 19 | interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {} | 19 | interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} { |
| 20 | #ifdef ARCHITECTURE_x86_64 | ||
| 21 | // TODO(bunnei): Initialization relies on a core being available. We may later replace this with | ||
| 22 | // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. | ||
| 23 | auto& kernel = system.Kernel(); | ||
| 24 | arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( | ||
| 25 | system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | ||
| 26 | #else | ||
| 27 | #error Platform not supported yet. | ||
| 28 | #endif | ||
| 29 | } | ||
| 20 | 30 | ||
| 21 | PhysicalCore::~PhysicalCore() = default; | 31 | PhysicalCore::~PhysicalCore() = default; |
| 22 | 32 | ||
| 23 | void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { | 33 | void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { |
| 24 | #ifdef ARCHITECTURE_x86_64 | 34 | #ifdef ARCHITECTURE_x86_64 |
| 25 | auto& kernel = system.Kernel(); | 35 | auto& kernel = system.Kernel(); |
| 26 | if (is_64_bit) { | 36 | if (!is_64_bit) { |
| 27 | arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( | 37 | // We already initialized a 64-bit core, replace with a 32-bit one. |
| 28 | system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | ||
| 29 | } else { | ||
| 30 | arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( | 38 | arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( |
| 31 | system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | 39 | system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); |
| 32 | } | 40 | } |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4362508a3..c7f5140f4 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -1309,6 +1309,8 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces | |||
| 1309 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | 1309 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |
| 1310 | R_UNLESS(size > 0, ResultInvalidSize); | 1310 | R_UNLESS(size > 0, ResultInvalidSize); |
| 1311 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | 1311 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); |
| 1312 | R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); | ||
| 1313 | R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); | ||
| 1312 | 1314 | ||
| 1313 | // Validate the memory permission. | 1315 | // Validate the memory permission. |
| 1314 | R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); | 1316 | R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); |
| @@ -1323,7 +1325,7 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces | |||
| 1323 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | 1325 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); |
| 1324 | 1326 | ||
| 1325 | // Set the memory permission. | 1327 | // Set the memory permission. |
| 1326 | return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); | 1328 | return page_table.SetProcessMemoryPermission(address, size, perm); |
| 1327 | } | 1329 | } |
| 1328 | 1330 | ||
| 1329 | static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, | 1331 | static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, |
| @@ -1626,7 +1628,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand | |||
| 1626 | return ResultInvalidMemoryRegion; | 1628 | return ResultInvalidMemoryRegion; |
| 1627 | } | 1629 | } |
| 1628 | 1630 | ||
| 1629 | return page_table.MapProcessCodeMemory(dst_address, src_address, size); | 1631 | return page_table.MapCodeMemory(dst_address, src_address, size); |
| 1630 | } | 1632 | } |
| 1631 | 1633 | ||
| 1632 | static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, | 1634 | static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, |
| @@ -1694,7 +1696,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha | |||
| 1694 | return ResultInvalidMemoryRegion; | 1696 | return ResultInvalidMemoryRegion; |
| 1695 | } | 1697 | } |
| 1696 | 1698 | ||
| 1697 | return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); | 1699 | return page_table.UnmapCodeMemory(dst_address, src_address, size); |
| 1698 | } | 1700 | } |
| 1699 | 1701 | ||
| 1700 | /// Exits the current process | 1702 | /// Exits the current process |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 3782703d2..9fc7bb1b1 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "core/hle/kernel/k_page_table.h" | 14 | #include "core/hle/kernel/k_page_table.h" |
| 15 | #include "core/hle/kernel/k_system_control.h" | 15 | #include "core/hle/kernel/k_system_control.h" |
| 16 | #include "core/hle/kernel/svc_results.h" | 16 | #include "core/hle/kernel/svc_results.h" |
| 17 | #include "core/hle/kernel/svc_types.h" | ||
| 17 | #include "core/hle/service/ldr/ldr.h" | 18 | #include "core/hle/service/ldr/ldr.h" |
| 18 | #include "core/hle/service/service.h" | 19 | #include "core/hle/service/service.h" |
| 19 | #include "core/loader/nro.h" | 20 | #include "core/loader/nro.h" |
| @@ -325,7 +326,7 @@ public: | |||
| 325 | for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { | 326 | for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { |
| 326 | auto& page_table{process->PageTable()}; | 327 | auto& page_table{process->PageTable()}; |
| 327 | const VAddr addr{GetRandomMapRegion(page_table, size)}; | 328 | const VAddr addr{GetRandomMapRegion(page_table, size)}; |
| 328 | const ResultCode result{page_table.MapProcessCodeMemory(addr, baseAddress, size)}; | 329 | const ResultCode result{page_table.MapCodeMemory(addr, baseAddress, size)}; |
| 329 | 330 | ||
| 330 | if (result == Kernel::ResultInvalidCurrentMemory) { | 331 | if (result == Kernel::ResultInvalidCurrentMemory) { |
| 331 | continue; | 332 | continue; |
| @@ -351,12 +352,12 @@ public: | |||
| 351 | 352 | ||
| 352 | if (bss_size) { | 353 | if (bss_size) { |
| 353 | auto block_guard = detail::ScopeExit([&] { | 354 | auto block_guard = detail::ScopeExit([&] { |
| 354 | page_table.UnmapProcessCodeMemory(addr + nro_size, bss_addr, bss_size); | 355 | page_table.UnmapCodeMemory(addr + nro_size, bss_addr, bss_size); |
| 355 | page_table.UnmapProcessCodeMemory(addr, nro_addr, nro_size); | 356 | page_table.UnmapCodeMemory(addr, nro_addr, nro_size); |
| 356 | }); | 357 | }); |
| 357 | 358 | ||
| 358 | const ResultCode result{ | 359 | const ResultCode result{ |
| 359 | page_table.MapProcessCodeMemory(addr + nro_size, bss_addr, bss_size)}; | 360 | page_table.MapCodeMemory(addr + nro_size, bss_addr, bss_size)}; |
| 360 | 361 | ||
| 361 | if (result == Kernel::ResultInvalidCurrentMemory) { | 362 | if (result == Kernel::ResultInvalidCurrentMemory) { |
| 362 | continue; | 363 | continue; |
| @@ -397,12 +398,12 @@ public: | |||
| 397 | nro_header.segment_headers[DATA_INDEX].memory_size); | 398 | nro_header.segment_headers[DATA_INDEX].memory_size); |
| 398 | 399 | ||
| 399 | CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( | 400 | CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( |
| 400 | text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); | 401 | text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute)); |
| 401 | CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( | 402 | CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( |
| 402 | ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read)); | 403 | ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read)); |
| 403 | 404 | ||
| 404 | return process->PageTable().SetProcessMemoryPermission( | 405 | return process->PageTable().SetProcessMemoryPermission( |
| 405 | data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); | 406 | data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite); |
| 406 | } | 407 | } |
| 407 | 408 | ||
| 408 | void LoadModule(Kernel::HLERequestContext& ctx) { | 409 | void LoadModule(Kernel::HLERequestContext& ctx) { |
| @@ -530,16 +531,19 @@ public: | |||
| 530 | ResultCode UnmapNro(const NROInfo& info) { | 531 | ResultCode UnmapNro(const NROInfo& info) { |
| 531 | // Each region must be unmapped separately to validate memory state | 532 | // Each region must be unmapped separately to validate memory state |
| 532 | auto& page_table{system.CurrentProcess()->PageTable()}; | 533 | auto& page_table{system.CurrentProcess()->PageTable()}; |
| 533 | CASCADE_CODE(page_table.UnmapProcessCodeMemory(info.nro_address + info.text_size + | 534 | |
| 534 | info.ro_size + info.data_size, | 535 | if (info.bss_size != 0) { |
| 535 | info.bss_address, info.bss_size)); | 536 | CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size + |
| 536 | CASCADE_CODE(page_table.UnmapProcessCodeMemory( | 537 | info.ro_size + info.data_size, |
| 537 | info.nro_address + info.text_size + info.ro_size, | 538 | info.bss_address, info.bss_size)); |
| 538 | info.src_addr + info.text_size + info.ro_size, info.data_size)); | 539 | } |
| 539 | CASCADE_CODE(page_table.UnmapProcessCodeMemory( | 540 | |
| 540 | info.nro_address + info.text_size, info.src_addr + info.text_size, info.ro_size)); | 541 | CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size, |
| 541 | CASCADE_CODE( | 542 | info.src_addr + info.text_size + info.ro_size, |
| 542 | page_table.UnmapProcessCodeMemory(info.nro_address, info.src_addr, info.text_size)); | 543 | info.data_size)); |
| 544 | CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size, | ||
| 545 | info.src_addr + info.text_size, info.ro_size)); | ||
| 546 | CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address, info.src_addr, info.text_size)); | ||
| 543 | return ResultSuccess; | 547 | return ResultSuccess; |
| 544 | } | 548 | } |
| 545 | 549 | ||