kernel: svc: Implement Map/UnmapProcessMemory and Create/ControlCodeMemory
Used by Skyline modding framework
This commit is contained in:
parent
f1f91ad468
commit
8aef8f39d8
|
@ -9,6 +9,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hardware_properties.h"
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/init/init_slab_setup.h"
|
#include "core/hle/kernel/init/init_slab_setup.h"
|
||||||
|
#include "core/hle/kernel/k_code_memory.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.h"
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||||
#include "core/hle/kernel/k_memory_manager.h"
|
#include "core/hle/kernel/k_memory_manager.h"
|
||||||
|
@ -32,6 +33,7 @@ namespace Kernel::Init {
|
||||||
HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
|
HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
|
||||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
|
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
|
||||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
||||||
|
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
|
||||||
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
|
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
|
||||||
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
|
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/hle/kernel/k_class_token.h"
|
#include "core/hle/kernel/k_class_token.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
#include "core/hle/kernel/k_client_session.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_event.h"
|
||||||
#include "core/hle/kernel/k_port.h"
|
#include "core/hle/kernel/k_port.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
@ -48,7 +49,7 @@ static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000);
|
||||||
static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
|
static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
|
||||||
// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
|
// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
|
||||||
// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
|
// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
|
||||||
// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
|
static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
|
||||||
|
|
||||||
// Ensure that the token hierarchy is correct.
|
// Ensure that the token hierarchy is correct.
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAut
|
||||||
static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
|
static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
|
||||||
// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
|
// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
|
||||||
// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
|
// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
|
||||||
// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
|
static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
|
||||||
|
|
||||||
// Ensure that the token hierarchy reflects the class hierarchy.
|
// Ensure that the token hierarchy reflects the class hierarchy.
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -131,6 +131,26 @@ enum class KMemoryPermission : u8 {
|
||||||
|
|
||||||
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
|
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
|
||||||
Svc::MemoryPermission::Execute),
|
Svc::MemoryPermission::Execute),
|
||||||
|
|
||||||
|
KernelShift = 3,
|
||||||
|
|
||||||
|
KernelRead = Read << KernelShift,
|
||||||
|
KernelWrite = Write << KernelShift,
|
||||||
|
KernelExecute = Execute << KernelShift,
|
||||||
|
|
||||||
|
NotMapped = (1 << (2 * KernelShift)),
|
||||||
|
|
||||||
|
KernelReadWrite = KernelRead | KernelWrite,
|
||||||
|
KernelReadExecute = KernelRead | KernelExecute,
|
||||||
|
|
||||||
|
UserRead = Read | KernelRead,
|
||||||
|
UserWrite = Write | KernelWrite,
|
||||||
|
UserExecute = Execute,
|
||||||
|
|
||||||
|
UserReadWrite = UserRead | UserWrite,
|
||||||
|
UserReadExecute = UserRead | UserExecute,
|
||||||
|
|
||||||
|
IpcLockChangeMask = NotMapped | UserReadWrite
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,10 @@ public:
|
||||||
return num_pages;
|
return num_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t GetSize() const {
|
||||||
|
return GetNumPages() * PageSize;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u64 addr{};
|
u64 addr{};
|
||||||
std::size_t num_pages{};
|
std::size_t num_pages{};
|
||||||
|
|
|
@ -368,6 +368,33 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||||
|
KPageTable& src_page_table, VAddr src_addr) {
|
||||||
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
|
const std::size_t num_pages{size / PageSize};
|
||||||
|
|
||||||
|
// Check that the memory is mapped in the destination process.
|
||||||
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All,
|
||||||
|
KMemoryState::SharedCode, KMemoryPermission::UserReadWrite,
|
||||||
|
KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
|
||||||
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
|
// Check that the memory is mapped in the source process.
|
||||||
|
R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess,
|
||||||
|
KMemoryState::FlagCanMapProcess, KMemoryPermission::None,
|
||||||
|
KMemoryPermission::None, KMemoryAttribute::All,
|
||||||
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
|
CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
|
||||||
|
|
||||||
|
// Apply the memory block update.
|
||||||
|
block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
|
||||||
|
KMemoryAttribute::None);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) {
|
void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) {
|
||||||
auto node{page_linked_list.Nodes().begin()};
|
auto node{page_linked_list.Nodes().begin()};
|
||||||
PAddr map_addr{node->GetAddress()};
|
PAddr map_addr{node->GetAddress()};
|
||||||
|
@ -942,6 +969,62 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
|
||||||
|
|
||||||
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
|
KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite;
|
||||||
|
|
||||||
|
KMemoryPermission old_perm{};
|
||||||
|
|
||||||
|
if (const ResultCode result{CheckMemoryState(
|
||||||
|
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||||
|
KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask,
|
||||||
|
KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
|
||||||
|
result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
|
||||||
|
|
||||||
|
block_manager->UpdateLock(
|
||||||
|
addr, size / PageSize,
|
||||||
|
[](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
|
||||||
|
block->ShareToDevice(permission);
|
||||||
|
},
|
||||||
|
new_perm);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
|
||||||
|
|
||||||
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
|
KMemoryPermission new_perm = KMemoryPermission::UserReadWrite;
|
||||||
|
|
||||||
|
KMemoryPermission old_perm{};
|
||||||
|
|
||||||
|
if (const ResultCode result{CheckMemoryState(
|
||||||
|
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||||
|
KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
|
KMemoryAttribute::All, KMemoryAttribute::Locked)};
|
||||||
|
result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
|
||||||
|
|
||||||
|
block_manager->UpdateLock(
|
||||||
|
addr, size / PageSize,
|
||||||
|
[](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
|
||||||
|
block->UnshareToDevice(permission);
|
||||||
|
},
|
||||||
|
new_perm);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
|
ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
|
||||||
block_manager = std::make_unique<KMemoryBlockManager>(start, end);
|
block_manager = std::make_unique<KMemoryBlockManager>(start, end);
|
||||||
|
|
||||||
|
@ -1231,4 +1314,43 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
|
||||||
|
KMemoryState state_mask, KMemoryState state,
|
||||||
|
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||||
|
KMemoryAttribute attr_mask, KMemoryAttribute attr) const {
|
||||||
|
|
||||||
|
// Get information about the first block.
|
||||||
|
const VAddr last_addr = addr + size - 1;
|
||||||
|
KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
|
||||||
|
KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
// If the start address isn't aligned, we need a block.
|
||||||
|
const size_t blocks_for_start_align =
|
||||||
|
(Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Validate against the provided masks.
|
||||||
|
R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||||
|
|
||||||
|
// Break once we're done.
|
||||||
|
if (last_addr <= info.GetLastAddress()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance our iterator.
|
||||||
|
it++;
|
||||||
|
info = it->GetMemoryInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the end address isn't aligned, we need a block.
|
||||||
|
const size_t blocks_for_end_align =
|
||||||
|
(Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||||
|
|
||||||
|
if (out_blocks_needed != nullptr) {
|
||||||
|
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -33,6 +33,8 @@ public:
|
||||||
KMemoryPermission perm);
|
KMemoryPermission perm);
|
||||||
ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||||
ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||||
|
ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
|
||||||
|
VAddr src_addr);
|
||||||
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
|
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
|
||||||
ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
|
ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
|
||||||
ResultCode UnmapMemory(VAddr addr, std::size_t size);
|
ResultCode UnmapMemory(VAddr addr, std::size_t size);
|
||||||
|
@ -55,6 +57,8 @@ public:
|
||||||
KMemoryPermission perm, PAddr map_addr = 0);
|
KMemoryPermission perm, PAddr map_addr = 0);
|
||||||
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||||
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||||
|
ResultCode LockForCodeMemory(VAddr addr, std::size_t size);
|
||||||
|
ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size);
|
||||||
|
|
||||||
Common::PageTable& PageTableImpl() {
|
Common::PageTable& PageTableImpl() {
|
||||||
return page_table_impl;
|
return page_table_impl;
|
||||||
|
@ -115,6 +119,10 @@ private:
|
||||||
return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
|
return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
|
||||||
perm, attr_mask, attr, ignore_attr);
|
perm, attr_mask, attr, ignore_attr);
|
||||||
}
|
}
|
||||||
|
ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
|
||||||
|
KMemoryState state_mask, KMemoryState state,
|
||||||
|
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||||
|
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
|
||||||
|
|
||||||
std::recursive_mutex page_table_lock;
|
std::recursive_mutex page_table_lock;
|
||||||
std::unique_ptr<KMemoryBlockManager> block_manager;
|
std::unique_ptr<KMemoryBlockManager> block_manager;
|
||||||
|
|
|
@ -53,6 +53,7 @@ class KSharedMemoryInfo;
|
||||||
class KThread;
|
class KThread;
|
||||||
class KTransferMemory;
|
class KTransferMemory;
|
||||||
class KWritableEvent;
|
class KWritableEvent;
|
||||||
|
class KCodeMemory;
|
||||||
class PhysicalCore;
|
class PhysicalCore;
|
||||||
class ServiceThread;
|
class ServiceThread;
|
||||||
class Synchronization;
|
class Synchronization;
|
||||||
|
@ -326,6 +327,8 @@ public:
|
||||||
return slab_heap_container->transfer_memory;
|
return slab_heap_container->transfer_memory;
|
||||||
} else if constexpr (std::is_same_v<T, KWritableEvent>) {
|
} else if constexpr (std::is_same_v<T, KWritableEvent>) {
|
||||||
return slab_heap_container->writeable_event;
|
return slab_heap_container->writeable_event;
|
||||||
|
} else if constexpr (std::is_same_v<T, KCodeMemory>) {
|
||||||
|
return slab_heap_container->code_memory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +380,7 @@ private:
|
||||||
KSlabHeap<KThread> thread;
|
KSlabHeap<KThread> thread;
|
||||||
KSlabHeap<KTransferMemory> transfer_memory;
|
KSlabHeap<KTransferMemory> transfer_memory;
|
||||||
KSlabHeap<KWritableEvent> writeable_event;
|
KSlabHeap<KWritableEvent> writeable_event;
|
||||||
|
KSlabHeap<KCodeMemory> code_memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_client_port.h"
|
#include "core/hle/kernel/k_client_port.h"
|
||||||
#include "core/hle/kernel/k_client_session.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_event.h"
|
||||||
#include "core/hle/kernel/k_handle_table.h"
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
#include "core/hle/kernel/k_memory_block.h"
|
#include "core/hle/kernel/k_memory_block.h"
|
||||||
|
@ -1197,6 +1198,22 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
|
return perm == Svc::MemoryPermission::ReadWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
|
return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
|
return perm == Svc::MemoryPermission::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
|
return perm == Svc::MemoryPermission::None;
|
||||||
|
}
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
|
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
|
||||||
|
@ -1306,6 +1323,195 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces
|
||||||
return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
|
return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
|
||||||
|
VAddr src_address, u64 size) {
|
||||||
|
LOG_TRACE(Kernel_SVC,
|
||||||
|
"called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
|
||||||
|
dst_address, process_handle, src_address, size);
|
||||||
|
|
||||||
|
// Validate the address/size.
|
||||||
|
R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
|
||||||
|
R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
|
||||||
|
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||||
|
R_UNLESS(size > 0, ResultInvalidSize);
|
||||||
|
R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Get the processes.
|
||||||
|
KProcess* dst_process = system.CurrentProcess();
|
||||||
|
KScopedAutoObject src_process =
|
||||||
|
dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
|
||||||
|
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
|
||||||
|
|
||||||
|
// Get the page tables.
|
||||||
|
auto& dst_pt = dst_process->PageTable();
|
||||||
|
auto& src_pt = src_process->PageTable();
|
||||||
|
|
||||||
|
// Validate that the mapping is in range.
|
||||||
|
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
|
||||||
|
ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// Create a new page group.
|
||||||
|
KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address);
|
||||||
|
KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
|
||||||
|
|
||||||
|
// Map the group.
|
||||||
|
R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
|
||||||
|
KMemoryPermission::UserReadWrite));
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
|
||||||
|
VAddr src_address, u64 size) {
|
||||||
|
LOG_TRACE(Kernel_SVC,
|
||||||
|
"called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
|
||||||
|
dst_address, process_handle, src_address, size);
|
||||||
|
|
||||||
|
// Validate the address/size.
|
||||||
|
R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
|
||||||
|
R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
|
||||||
|
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||||
|
R_UNLESS(size > 0, ResultInvalidSize);
|
||||||
|
R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Get the processes.
|
||||||
|
KProcess* dst_process = system.CurrentProcess();
|
||||||
|
KScopedAutoObject src_process =
|
||||||
|
dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
|
||||||
|
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
|
||||||
|
|
||||||
|
// Get the page tables.
|
||||||
|
auto& dst_pt = dst_process->PageTable();
|
||||||
|
auto& src_pt = src_process->PageTable();
|
||||||
|
|
||||||
|
// Validate that the mapping is in range.
|
||||||
|
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
|
||||||
|
ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// Unmap the memory.
|
||||||
|
R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
|
||||||
|
LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}",
|
||||||
|
static_cast<void*>(out), address, size);
|
||||||
|
// Get kernel instance.
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
|
||||||
|
// Validate address / size.
|
||||||
|
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||||
|
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||||
|
R_UNLESS(size > 0, ResultInvalidSize);
|
||||||
|
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Create the code memory.
|
||||||
|
|
||||||
|
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
|
||||||
|
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
|
||||||
|
|
||||||
|
// Verify that the region is in range.
|
||||||
|
R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size),
|
||||||
|
ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Initialize the code memory.
|
||||||
|
R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
|
||||||
|
|
||||||
|
// Register the code memory.
|
||||||
|
KCodeMemory::Register(kernel, code_mem);
|
||||||
|
|
||||||
|
// Add the code memory to the handle table.
|
||||||
|
R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem));
|
||||||
|
|
||||||
|
code_mem->Close();
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation,
|
||||||
|
VAddr address, size_t size, Svc::MemoryPermission perm) {
|
||||||
|
|
||||||
|
LOG_TRACE(Kernel_SVC,
|
||||||
|
"called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
|
||||||
|
"permission=0x{:X}",
|
||||||
|
code_memory_handle, operation, address, size, perm);
|
||||||
|
|
||||||
|
// Validate the address / size.
|
||||||
|
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||||
|
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||||
|
R_UNLESS(size > 0, ResultInvalidSize);
|
||||||
|
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Get the code memory from its handle.
|
||||||
|
KScopedAutoObject code_mem =
|
||||||
|
system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle);
|
||||||
|
R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
|
||||||
|
|
||||||
|
// NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
|
||||||
|
// This enables homebrew usage of these SVCs for JIT.
|
||||||
|
|
||||||
|
// Perform the operation.
|
||||||
|
switch (static_cast<CodeMemoryOperation>(operation)) {
|
||||||
|
case CodeMemoryOperation::Map: {
|
||||||
|
// Check that the region is in range.
|
||||||
|
R_UNLESS(
|
||||||
|
system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
|
||||||
|
ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// Check the memory permission.
|
||||||
|
R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||||
|
|
||||||
|
// Map the memory.
|
||||||
|
R_TRY(code_mem->Map(address, size));
|
||||||
|
} break;
|
||||||
|
case CodeMemoryOperation::Unmap: {
|
||||||
|
// Check that the region is in range.
|
||||||
|
R_UNLESS(
|
||||||
|
system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
|
||||||
|
ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// Check the memory permission.
|
||||||
|
R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||||
|
|
||||||
|
// Unmap the memory.
|
||||||
|
R_TRY(code_mem->Unmap(address, size));
|
||||||
|
} break;
|
||||||
|
case CodeMemoryOperation::MapToOwner: {
|
||||||
|
// Check that the region is in range.
|
||||||
|
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
|
||||||
|
KMemoryState::GeneratedCode),
|
||||||
|
ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// Check the memory permission.
|
||||||
|
R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||||
|
|
||||||
|
// Map the memory to its owner.
|
||||||
|
R_TRY(code_mem->MapToOwner(address, size, perm));
|
||||||
|
} break;
|
||||||
|
case CodeMemoryOperation::UnmapFromOwner: {
|
||||||
|
// Check that the region is in range.
|
||||||
|
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
|
||||||
|
KMemoryState::GeneratedCode),
|
||||||
|
ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// Check the memory permission.
|
||||||
|
R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||||
|
|
||||||
|
// Unmap the memory from its owner.
|
||||||
|
R_TRY(code_mem->UnmapFromOwner(address, size));
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
return ResultInvalidEnumValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
|
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
|
||||||
VAddr page_info_address, Handle process_handle,
|
VAddr page_info_address, Handle process_handle,
|
||||||
VAddr address) {
|
VAddr address) {
|
||||||
|
@ -2600,8 +2806,8 @@ static const FunctionDef SVC_Table_64[] = {
|
||||||
{0x48, nullptr, "MapPhysicalMemoryUnsafe"},
|
{0x48, nullptr, "MapPhysicalMemoryUnsafe"},
|
||||||
{0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
|
{0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
|
||||||
{0x4A, nullptr, "SetUnsafeLimit"},
|
{0x4A, nullptr, "SetUnsafeLimit"},
|
||||||
{0x4B, nullptr, "CreateCodeMemory"},
|
{0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"},
|
||||||
{0x4C, nullptr, "ControlCodeMemory"},
|
{0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"},
|
||||||
{0x4D, nullptr, "SleepSystem"},
|
{0x4D, nullptr, "SleepSystem"},
|
||||||
{0x4E, nullptr, "ReadWriteRegister"},
|
{0x4E, nullptr, "ReadWriteRegister"},
|
||||||
{0x4F, nullptr, "SetProcessActivity"},
|
{0x4F, nullptr, "SetProcessActivity"},
|
||||||
|
@ -2641,8 +2847,8 @@ static const FunctionDef SVC_Table_64[] = {
|
||||||
{0x71, nullptr, "ManageNamedPort"},
|
{0x71, nullptr, "ManageNamedPort"},
|
||||||
{0x72, nullptr, "ConnectToPort"},
|
{0x72, nullptr, "ConnectToPort"},
|
||||||
{0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
|
{0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
|
||||||
{0x74, nullptr, "MapProcessMemory"},
|
{0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"},
|
||||||
{0x75, nullptr, "UnmapProcessMemory"},
|
{0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"},
|
||||||
{0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
|
{0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
|
||||||
{0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
|
{0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
|
||||||
{0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
|
{0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
|
||||||
|
|
|
@ -73,6 +73,23 @@ void SvcWrap64(Core::System& system) {
|
||||||
.raw);
|
.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by MapProcessMemory and UnmapProcessMemory
|
||||||
|
template <ResultCode func(Core::System&, u64, u32, u64, u64)>
|
||||||
|
void SvcWrap64(Core::System& system) {
|
||||||
|
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
|
||||||
|
Param(system, 2), Param(system, 3))
|
||||||
|
.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by ControlCodeMemory
|
||||||
|
template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
|
||||||
|
void SvcWrap64(Core::System& system) {
|
||||||
|
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
|
||||||
|
static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
|
||||||
|
static_cast<Svc::MemoryPermission>(Param(system, 4)))
|
||||||
|
.raw);
|
||||||
|
}
|
||||||
|
|
||||||
template <ResultCode func(Core::System&, u32*)>
|
template <ResultCode func(Core::System&, u32*)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
u32 param = 0;
|
u32 param = 0;
|
||||||
|
@ -301,6 +318,16 @@ void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, retval);
|
FuncReturn(system, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by CreateCodeMemory
|
||||||
|
template <ResultCode func(Core::System&, Handle*, u64, u64)>
|
||||||
|
void SvcWrap64(Core::System& system) {
|
||||||
|
u32 param_1 = 0;
|
||||||
|
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw;
|
||||||
|
|
||||||
|
system.CurrentArmInterface().SetReg(1, param_1);
|
||||||
|
FuncReturn(system, retval);
|
||||||
|
}
|
||||||
|
|
||||||
template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
|
template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
u32 param_1 = 0;
|
u32 param_1 = 0;
|
||||||
|
|
Reference in New Issue