Browse Source
kernel: svc: Implement Map/UnmapProcessMemory and Create/ControlCodeMemory
kernel: svc: Implement Map/UnmapProcessMemory and Create/ControlCodeMemory
Used by Skyline modding frameworknce_cpp
11 changed files with 636 additions and 7 deletions
-
2src/core/hle/kernel/init/init_slab_setup.cpp
-
5src/core/hle/kernel/k_class_token.cpp
-
159src/core/hle/kernel/k_code_memory.cpp
-
76src/core/hle/kernel/k_code_memory.h
-
20src/core/hle/kernel/k_memory_block.h
-
4src/core/hle/kernel/k_page_linked_list.h
-
124src/core/hle/kernel/k_page_table.cpp
-
8src/core/hle/kernel/k_page_table.h
-
4src/core/hle/kernel/kernel.h
-
214src/core/hle/kernel/svc.cpp
-
27src/core/hle/kernel/svc_wrap.h
@ -0,0 +1,159 @@ |
|||||
|
#include "core/core.h"
|
||||
|
#include "core/core_timing.h"
|
||||
|
#include "core/hle/kernel/k_client_port.h"
|
||||
|
#include "core/hle/kernel/k_client_session.h"
|
||||
|
#include "core/hle/kernel/k_code_memory.h"
|
||||
|
#include "core/hle/kernel/k_event.h"
|
||||
|
#include "core/hle/kernel/k_handle_table.h"
|
||||
|
#include "core/hle/kernel/k_memory_block.h"
|
||||
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||
|
#include "core/hle/kernel/k_page_table.h"
|
||||
|
#include "core/hle/kernel/k_process.h"
|
||||
|
#include "core/hle/kernel/k_readable_event.h"
|
||||
|
#include "core/hle/kernel/k_resource_limit.h"
|
||||
|
#include "core/hle/kernel/k_scheduler.h"
|
||||
|
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||
|
#include "core/hle/kernel/k_shared_memory.h"
|
||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
|
#include "core/hle/kernel/k_thread.h"
|
||||
|
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
|
#include "core/hle/kernel/k_writable_event.h"
|
||||
|
#include "core/hle/kernel/kernel.h"
|
||||
|
#include "core/hle/kernel/physical_core.h"
|
||||
|
#include "core/hle/kernel/svc.h"
|
||||
|
#include "core/hle/kernel/svc_results.h"
|
||||
|
#include "core/hle/kernel/svc_types.h"
|
||||
|
#include "core/hle/kernel/svc_wrap.h"
|
||||
|
#include "core/hle/lock.h"
|
||||
|
#include "core/hle/result.h"
|
||||
|
#include "core/memory.h"
|
||||
|
#include "core/reporter.h"
|
||||
|
namespace Kernel { |
||||
|
|
||||
|
KCodeMemory::KCodeMemory(KernelCore& kernel_) |
||||
|
: KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {} |
||||
|
|
||||
|
ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) { |
||||
|
// Set members.
|
||||
|
m_owner = kernel.CurrentProcess(); |
||||
|
|
||||
|
// Get the owner page table.
|
||||
|
auto& page_table = m_owner->PageTable(); |
||||
|
|
||||
|
// Construct the page group.
|
||||
|
KMemoryInfo kBlockInfo = page_table.QueryInfo(addr); |
||||
|
m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); |
||||
|
|
||||
|
// Lock the memory.
|
||||
|
R_TRY(page_table.LockForCodeMemory(addr, size)) |
||||
|
|
||||
|
// Clear the memory.
|
||||
|
for (const auto& block : m_page_group.Nodes()) { |
||||
|
std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); |
||||
|
} |
||||
|
|
||||
|
// Set remaining tracking members.
|
||||
|
m_address = addr; |
||||
|
m_is_initialized = true; |
||||
|
m_is_owner_mapped = false; |
||||
|
m_is_mapped = false; |
||||
|
|
||||
|
// We succeeded.
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
void KCodeMemory::Finalize() { |
||||
|
// Unlock.
|
||||
|
if (!m_is_mapped && !m_is_owner_mapped) { |
||||
|
const size_t size = m_page_group.GetNumPages() * PageSize; |
||||
|
m_owner->PageTable().UnlockForCodeMemory(m_address, size); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ResultCode KCodeMemory::Map(VAddr address, size_t size) { |
||||
|
// Validate the size.
|
||||
|
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); |
||||
|
|
||||
|
// Lock ourselves.
|
||||
|
KScopedLightLock lk(m_lock); |
||||
|
|
||||
|
// Ensure we're not already mapped.
|
||||
|
R_UNLESS(!m_is_mapped, ResultInvalidState); |
||||
|
|
||||
|
// Map the memory.
|
||||
|
R_TRY(kernel.CurrentProcess()->PageTable().MapPages( |
||||
|
address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); |
||||
|
|
||||
|
// Mark ourselves as mapped.
|
||||
|
m_is_mapped = true; |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
ResultCode KCodeMemory::Unmap(VAddr address, size_t size) { |
||||
|
// Validate the size.
|
||||
|
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); |
||||
|
|
||||
|
// Lock ourselves.
|
||||
|
KScopedLightLock lk(m_lock); |
||||
|
|
||||
|
// Unmap the memory.
|
||||
|
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group, |
||||
|
KMemoryState::CodeOut)); |
||||
|
|
||||
|
// Mark ourselves as unmapped.
|
||||
|
m_is_mapped = false; |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) { |
||||
|
// Validate the size.
|
||||
|
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); |
||||
|
|
||||
|
// Lock ourselves.
|
||||
|
KScopedLightLock lk(m_lock); |
||||
|
|
||||
|
// Ensure we're not already mapped.
|
||||
|
R_UNLESS(!m_is_owner_mapped, ResultInvalidState); |
||||
|
|
||||
|
// Convert the memory permission.
|
||||
|
KMemoryPermission k_perm{}; |
||||
|
switch (perm) { |
||||
|
case Svc::MemoryPermission::Read: |
||||
|
k_perm = KMemoryPermission::UserRead; |
||||
|
break; |
||||
|
case Svc::MemoryPermission::ReadExecute: |
||||
|
k_perm = KMemoryPermission::UserReadExecute; |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// Map the memory.
|
||||
|
R_TRY( |
||||
|
m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm)); |
||||
|
|
||||
|
// Mark ourselves as mapped.
|
||||
|
m_is_owner_mapped = true; |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) { |
||||
|
// Validate the size.
|
||||
|
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); |
||||
|
|
||||
|
// Lock ourselves.
|
||||
|
KScopedLightLock lk(m_lock); |
||||
|
|
||||
|
// Unmap the memory.
|
||||
|
R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode)); |
||||
|
|
||||
|
// Mark ourselves as unmapped.
|
||||
|
m_is_owner_mapped = false; |
||||
|
|
||||
|
return ResultSuccess; |
||||
|
} |
||||
|
|
||||
|
} // namespace Kernel
|
||||
@ -0,0 +1,76 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include "core/core.h" |
||||
|
#include "core/core_timing.h" |
||||
|
#include "core/hle/kernel/k_client_port.h" |
||||
|
#include "core/hle/kernel/k_client_session.h" |
||||
|
#include "core/hle/kernel/k_event.h" |
||||
|
#include "core/hle/kernel/k_handle_table.h" |
||||
|
#include "core/hle/kernel/k_memory_block.h" |
||||
|
#include "core/hle/kernel/k_memory_layout.h" |
||||
|
#include "core/hle/kernel/k_page_table.h" |
||||
|
#include "core/hle/kernel/k_process.h" |
||||
|
#include "core/hle/kernel/k_readable_event.h" |
||||
|
#include "core/hle/kernel/k_resource_limit.h" |
||||
|
#include "core/hle/kernel/k_scheduler.h" |
||||
|
#include "core/hle/kernel/k_scoped_resource_reservation.h" |
||||
|
#include "core/hle/kernel/k_shared_memory.h" |
||||
|
#include "core/hle/kernel/k_synchronization_object.h" |
||||
|
#include "core/hle/kernel/k_thread.h" |
||||
|
#include "core/hle/kernel/k_transfer_memory.h" |
||||
|
#include "core/hle/kernel/k_writable_event.h" |
||||
|
#include "core/hle/kernel/kernel.h" |
||||
|
#include "core/hle/kernel/physical_core.h" |
||||
|
#include "core/hle/kernel/svc.h" |
||||
|
#include "core/hle/kernel/svc_results.h" |
||||
|
#include "core/hle/kernel/svc_types.h" |
||||
|
#include "core/hle/kernel/svc_wrap.h" |
||||
|
#include "core/hle/lock.h" |
||||
|
#include "core/hle/result.h" |
||||
|
#include "core/memory.h" |
||||
|
#include "core/reporter.h" |
||||
|
|
||||
|
namespace Kernel { |
||||
|
|
||||
|
enum class CodeMemoryOperation : u32 { Map = 0, MapToOwner = 1, Unmap = 2, UnmapFromOwner = 3 }; |
||||
|
|
||||
|
class KCodeMemory final |
||||
|
: public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> { |
||||
|
KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject); |
||||
|
|
||||
|
private: |
||||
|
KPageLinkedList m_page_group; |
||||
|
KProcess* m_owner; |
||||
|
VAddr m_address; |
||||
|
KLightLock m_lock; |
||||
|
bool m_is_initialized; |
||||
|
bool m_is_owner_mapped; |
||||
|
bool m_is_mapped; |
||||
|
|
||||
|
public: |
||||
|
explicit KCodeMemory(KernelCore& kernel_); |
||||
|
|
||||
|
ResultCode Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size); |
||||
|
void Finalize(); |
||||
|
|
||||
|
ResultCode Map(VAddr address, size_t size); |
||||
|
ResultCode Unmap(VAddr address, size_t size); |
||||
|
ResultCode MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm); |
||||
|
ResultCode UnmapFromOwner(VAddr address, size_t size); |
||||
|
|
||||
|
bool IsInitialized() const { |
||||
|
return m_is_initialized; |
||||
|
} |
||||
|
static void PostDestroy([[maybe_unused]] uintptr_t arg) {} |
||||
|
|
||||
|
KProcess* GetOwner() const { |
||||
|
return m_owner; |
||||
|
} |
||||
|
VAddr GetSourceAddress() { |
||||
|
return m_address; |
||||
|
} |
||||
|
size_t GetSize() const { |
||||
|
return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0; |
||||
|
} |
||||
|
}; |
||||
|
} // namespace Kernel |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue