diff options
| author | bunnei <bunneidev@gmail.com> | 2022-01-09 02:17:17 -0800 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2022-01-11 16:28:11 -0800 | 
| commit | 49a0e4330ee37bdfa503918f841ab9599ccc1c24 (patch) | |
| tree | e38e9dc90acbbf4fa8d64ea8c30736a86f32b37b | |
| parent | 6ac44f3bdca29c3b0530aa600b914c5952e525f3 (diff) | |
hle: kernel: k_page_table: Update SetProcessMemoryPermission.
| -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,  }  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}; -    KMemoryState prev_state{}; -    KMemoryPermission prev_perm{}; - -    CASCADE_CODE(CheckMemoryState( -        &prev_state, &prev_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCode, -        KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, -        KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - -    KMemoryState state{prev_state}; +    // Verify we can change the memory permission. +    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)); -    // Ensure state is mutable if permission allows write -    if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { -        if (prev_state == KMemoryState::Code) { -            state = KMemoryState::CodeData; -        } else if (prev_state == KMemoryState::AliasCode) { -            state = KMemoryState::AliasCodeData; -        } else { +    // Determine new perm/state. +    const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); +    KMemoryState new_state = old_state; +    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)); + +    if (is_w) { +        switch (old_state) { +        case KMemoryState::Code: +            new_state = KMemoryState::CodeData; +            break; +        case KMemoryState::AliasCode: +            new_state = KMemoryState::AliasCodeData; +            break; +        default:              UNREACHABLE();          }      } -    // Return early if there is nothing to change -    if (state == prev_state && perm == prev_perm) { -        return ResultSuccess; -    } +    // Succeed if there's nothing to do. +    R_SUCCEED_IF(old_perm == new_perm && old_state == new_state); -    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          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;  } 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:      ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,                          KMemoryPermission perm);      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);      ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);      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) {  void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {      const auto ReprotectSegment = [&](const CodeSet::Segment& segment, -                                      KMemoryPermission permission) { +                                      Svc::MemoryPermission permission) {          page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);      };      kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),                                          code_set.memory.size()); -    ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); -    ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); -    ReprotectSegment(code_set.DataSegment(), KMemoryPermission::UserReadWrite); +    ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute); +    ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read); +    ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);  }  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 {  PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,                             Core::CPUInterrupts& interrupts_)      : 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;  void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {  #ifdef ARCHITECTURE_x86_64      auto& kernel = system.Kernel(); -    if (is_64_bit) { -        arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( -            system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); -    } else { +    if (!is_64_bit) { +        // We already initialized a 64-bit core, replace with a 32-bit one.          arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(              system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);      } 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      R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);      R_UNLESS(size > 0, ResultInvalidSize);      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.      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);      // 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, 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 @@  #include "core/hle/kernel/k_page_table.h"  #include "core/hle/kernel/k_system_control.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/service.h"  #include "core/loader/nro.h" @@ -397,12 +398,12 @@ public:                   nro_header.segment_headers[DATA_INDEX].memory_size);          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( -            ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read)); +            ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));          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) { | 
