hle: kernel: k_page_table: Update SetProcessMemoryPermission.
This commit is contained in:
		| @@ -713,50 +713,61 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, | |||||||
| } | } | ||||||
|  |  | ||||||
| ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, | ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, | ||||||
|                                                   KMemoryPermission perm) { |                                                   Svc::MemoryPermission svc_perm) { | ||||||
|  |     const size_t num_pages = size / PageSize; | ||||||
|  |  | ||||||
|  |     // Lock the table. | ||||||
|     std::lock_guard lock{page_table_lock}; |     std::lock_guard lock{page_table_lock}; | ||||||
|  |  | ||||||
|     KMemoryState prev_state{}; |     // Verify we can change the memory permission. | ||||||
|     KMemoryPermission prev_perm{}; |     KMemoryState old_state; | ||||||
|  |     KMemoryPermission old_perm; | ||||||
|  |     size_t num_allocator_blocks; | ||||||
|  |     R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, | ||||||
|  |                                  std::addressof(num_allocator_blocks), addr, size, | ||||||
|  |                                  KMemoryState::FlagCode, KMemoryState::FlagCode, | ||||||
|  |                                  KMemoryPermission::None, KMemoryPermission::None, | ||||||
|  |                                  KMemoryAttribute::All, KMemoryAttribute::None)); | ||||||
|  |  | ||||||
|     CASCADE_CODE(CheckMemoryState( |     // Determine new perm/state. | ||||||
|         &prev_state, &prev_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCode, |     const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); | ||||||
|         KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, |     KMemoryState new_state = old_state; | ||||||
|         KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |     const bool is_w = (new_perm & KMemoryPermission::UserWrite) == KMemoryPermission::UserWrite; | ||||||
|  |     const bool is_x = (new_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute; | ||||||
|  |     const bool was_x = | ||||||
|  |         (old_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute; | ||||||
|  |     ASSERT(!(is_w && is_x)); | ||||||
|  |  | ||||||
|     KMemoryState state{prev_state}; |     if (is_w) { | ||||||
|  |         switch (old_state) { | ||||||
|     // Ensure state is mutable if permission allows write |         case KMemoryState::Code: | ||||||
|     if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { |             new_state = KMemoryState::CodeData; | ||||||
|         if (prev_state == KMemoryState::Code) { |             break; | ||||||
|             state = KMemoryState::CodeData; |         case KMemoryState::AliasCode: | ||||||
|         } else if (prev_state == KMemoryState::AliasCode) { |             new_state = KMemoryState::AliasCodeData; | ||||||
|             state = KMemoryState::AliasCodeData; |             break; | ||||||
|         } else { |         default: | ||||||
|             UNREACHABLE(); |             UNREACHABLE(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Return early if there is nothing to change |     // Succeed if there's nothing to do. | ||||||
|     if (state == prev_state && perm == prev_perm) { |     R_SUCCEED_IF(old_perm == new_perm && old_state == new_state); | ||||||
|         return ResultSuccess; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) { |     // Perform mapping operation. | ||||||
|  |     const auto operation = | ||||||
|  |         was_x ? OperationType::ChangePermissionsAndRefresh : OperationType::ChangePermissions; | ||||||
|  |     R_TRY(Operate(addr, num_pages, new_perm, operation)); | ||||||
|  |  | ||||||
|  |     // Update the blocks. | ||||||
|  |     block_manager->Update(addr, num_pages, new_state, new_perm, KMemoryAttribute::None); | ||||||
|  |  | ||||||
|  |     // Ensure cache coherency, if we're setting pages as executable. | ||||||
|  |     if (is_x) { | ||||||
|         // Memory execution state is changing, invalidate CPU cache range |         // Memory execution state is changing, invalidate CPU cache range | ||||||
|         system.InvalidateCpuInstructionCacheRange(addr, size); |         system.InvalidateCpuInstructionCacheRange(addr, size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const std::size_t num_pages{size / PageSize}; |  | ||||||
|     const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None |  | ||||||
|                                       ? OperationType::ChangePermissionsAndRefresh |  | ||||||
|                                       : OperationType::ChangePermissions}; |  | ||||||
|  |  | ||||||
|     CASCADE_CODE(Operate(addr, num_pages, perm, operation)); |  | ||||||
|  |  | ||||||
|     block_manager->Update(addr, num_pages, state, perm); |  | ||||||
|  |  | ||||||
|     return ResultSuccess; |     return ResultSuccess; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,7 +43,8 @@ public: | |||||||
|     ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, |     ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, | ||||||
|                         KMemoryPermission perm); |                         KMemoryPermission perm); | ||||||
|     ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); |     ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); | ||||||
|     ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); |     ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, | ||||||
|  |                                           Svc::MemoryPermission svc_perm); | ||||||
|     KMemoryInfo QueryInfo(VAddr addr); |     KMemoryInfo QueryInfo(VAddr addr); | ||||||
|     ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |     ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | ||||||
|     ResultCode ResetTransferMemory(VAddr addr, std::size_t size); |     ResultCode ResetTransferMemory(VAddr addr, std::size_t size); | ||||||
|   | |||||||
| @@ -541,16 +541,16 @@ void KProcess::FreeTLSRegion(VAddr tls_address) { | |||||||
|  |  | ||||||
| void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { | ||||||
|     const auto ReprotectSegment = [&](const CodeSet::Segment& segment, |     const auto ReprotectSegment = [&](const CodeSet::Segment& segment, | ||||||
|                                       KMemoryPermission permission) { |                                       Svc::MemoryPermission permission) { | ||||||
|         page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); |         page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), |     kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), | ||||||
|                                         code_set.memory.size()); |                                         code_set.memory.size()); | ||||||
|  |  | ||||||
|     ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); |     ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute); | ||||||
|     ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); |     ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read); | ||||||
|     ReprotectSegment(code_set.DataSegment(), KMemoryPermission::UserReadWrite); |     ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool KProcess::IsSignaled() const { | bool KProcess::IsSignaled() const { | ||||||
|   | |||||||
| @@ -16,17 +16,25 @@ namespace Kernel { | |||||||
| PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, | PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, | ||||||
|                            Core::CPUInterrupts& interrupts_) |                            Core::CPUInterrupts& interrupts_) | ||||||
|     : core_index{core_index_}, system{system_}, scheduler{scheduler_}, |     : core_index{core_index_}, system{system_}, scheduler{scheduler_}, | ||||||
|       interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {} |       interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} { | ||||||
|  | #ifdef ARCHITECTURE_x86_64 | ||||||
|  |     // TODO(bunnei): Initialization relies on a core being available. We may later replace this with | ||||||
|  |     // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. | ||||||
|  |     auto& kernel = system.Kernel(); | ||||||
|  |     arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( | ||||||
|  |         system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | ||||||
|  | #else | ||||||
|  | #error Platform not supported yet. | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
| PhysicalCore::~PhysicalCore() = default; | PhysicalCore::~PhysicalCore() = default; | ||||||
|  |  | ||||||
| void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { | void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { | ||||||
| #ifdef ARCHITECTURE_x86_64 | #ifdef ARCHITECTURE_x86_64 | ||||||
|     auto& kernel = system.Kernel(); |     auto& kernel = system.Kernel(); | ||||||
|     if (is_64_bit) { |     if (!is_64_bit) { | ||||||
|         arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( |         // We already initialized a 64-bit core, replace with a 32-bit one. | ||||||
|             system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); |  | ||||||
|     } else { |  | ||||||
|         arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( |         arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( | ||||||
|             system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); |             system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1309,6 +1309,8 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces | |||||||
|     R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |     R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||||||
|     R_UNLESS(size > 0, ResultInvalidSize); |     R_UNLESS(size > 0, ResultInvalidSize); | ||||||
|     R_UNLESS((address < address + size), ResultInvalidCurrentMemory); |     R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||||||
|  |     R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); | ||||||
|  |     R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); | ||||||
|  |  | ||||||
|     // Validate the memory permission. |     // Validate the memory permission. | ||||||
|     R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); |     R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||||||
| @@ -1323,7 +1325,7 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces | |||||||
|     R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); |     R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | ||||||
|  |  | ||||||
|     // Set the memory permission. |     // Set the memory permission. | ||||||
|     return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); |     return page_table.SetProcessMemoryPermission(address, size, perm); | ||||||
| } | } | ||||||
|  |  | ||||||
| static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, | static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
| #include "core/hle/kernel/k_page_table.h" | #include "core/hle/kernel/k_page_table.h" | ||||||
| #include "core/hle/kernel/k_system_control.h" | #include "core/hle/kernel/k_system_control.h" | ||||||
| #include "core/hle/kernel/svc_results.h" | #include "core/hle/kernel/svc_results.h" | ||||||
|  | #include "core/hle/kernel/svc_types.h" | ||||||
| #include "core/hle/service/ldr/ldr.h" | #include "core/hle/service/ldr/ldr.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| #include "core/loader/nro.h" | #include "core/loader/nro.h" | ||||||
| @@ -397,12 +398,12 @@ public: | |||||||
|                  nro_header.segment_headers[DATA_INDEX].memory_size); |                  nro_header.segment_headers[DATA_INDEX].memory_size); | ||||||
|  |  | ||||||
|         CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( |         CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( | ||||||
|             text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); |             text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute)); | ||||||
|         CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( |         CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( | ||||||
|             ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read)); |             ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read)); | ||||||
|  |  | ||||||
|         return process->PageTable().SetProcessMemoryPermission( |         return process->PageTable().SetProcessMemoryPermission( | ||||||
|             data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::UserReadWrite); |             data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void LoadModule(Kernel::HLERequestContext& ctx) { |     void LoadModule(Kernel::HLERequestContext& ctx) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei