diff options
| author | 2022-01-09 02:17:17 -0800 | |
|---|---|---|
| committer | 2022-01-11 16:28:11 -0800 | |
| commit | 49a0e4330ee37bdfa503918f841ab9599ccc1c24 (patch) | |
| tree | e38e9dc90acbbf4fa8d64ea8c30736a86f32b37b | |
| parent | hle: service: ldr: UnmapCodeMemory BSS only when set. (diff) | |
| download | yuzu-49a0e4330ee37bdfa503918f841ab9599ccc1c24.tar.gz yuzu-49a0e4330ee37bdfa503918f841ab9599ccc1c24.tar.xz yuzu-49a0e4330ee37bdfa503918f841ab9599ccc1c24.zip | |
hle: kernel: k_page_table: Update SetProcessMemoryPermission.
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 73 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/physical_core.cpp | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 7 |
6 files changed, 68 insertions, 45 deletions
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 23734b501..27d86c9a4 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -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 | ||
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index a596bf381..274644181 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -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 856c200d3..cca405fed 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -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::UserReadWrite); | 553 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | bool KProcess::IsSignaled() const { | 556 | bool KProcess::IsSignaled() const { |
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 55ce0236f..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, |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 28d8114c5..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" |
| @@ -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::UserReadWrite); | 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) { |