Merge pull request #1899 from lioncash/state

vm_manager/svc: Modify MemoryState enum, and correct error handling for svcQueryMemory
This commit is contained in:
bunnei 2018-12-14 15:30:02 -05:00 committed by GitHub
commit 1a23970d17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 187 additions and 83 deletions

View file

@ -150,7 +150,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
vm_manager vm_manager
.MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size, .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
MemoryState::Mapped) MemoryState::Stack)
.Unwrap(); .Unwrap();
vm_manager.LogLayout(); vm_manager.LogLayout();

View file

@ -262,8 +262,7 @@ public:
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
ResultCode HeapFree(VAddr target, u32 size); ResultCode HeapFree(VAddr target, u32 size);
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
MemoryState state = MemoryState::Mapped);
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);

View file

@ -35,6 +35,7 @@
#include "core/hle/lock.h" #include "core/hle/lock.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/memory.h"
namespace Kernel { namespace Kernel {
namespace { namespace {
@ -273,7 +274,7 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
return result; return result;
} }
return current_process->MirrorMemory(dst_addr, src_addr, size); return current_process->MirrorMemory(dst_addr, src_addr, size, MemoryState::Stack);
} }
/// Unmaps a region that was previously mapped with svcMapMemory /// Unmaps a region that was previously mapped with svcMapMemory
@ -1066,10 +1067,9 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
return shared_memory->Unmap(*current_process, addr); return shared_memory->Unmap(*current_process, addr);
} }
/// Query process memory static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_address,
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, Handle process_handle, VAddr address) {
Handle process_handle, u64 addr) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
SharedPtr<Process> process = handle_table.Get<Process>(process_handle); SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
if (!process) { if (!process) {
@ -1079,28 +1079,32 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
} }
const auto& vm_manager = process->VMManager(); const auto& vm_manager = process->VMManager();
const auto vma = vm_manager.FindVMA(addr); const MemoryInfo memory_info = vm_manager.QueryMemory(address);
memory_info->attributes = 0; Memory::Write64(memory_info_address, memory_info.base_address);
if (vm_manager.IsValidHandle(vma)) { Memory::Write64(memory_info_address + 8, memory_info.size);
memory_info->base_address = vma->second.base; Memory::Write32(memory_info_address + 16, memory_info.state);
memory_info->permission = static_cast<u32>(vma->second.permissions); Memory::Write32(memory_info_address + 20, memory_info.attributes);
memory_info->size = vma->second.size; Memory::Write32(memory_info_address + 24, memory_info.permission);
memory_info->type = static_cast<u32>(vma->second.meminfo_state); Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count);
} else { Memory::Write32(memory_info_address + 28, memory_info.device_ref_count);
memory_info->base_address = 0; Memory::Write32(memory_info_address + 36, 0);
memory_info->permission = static_cast<u32>(VMAPermission::None);
memory_info->size = 0; // Page info appears to be currently unused by the kernel and is always set to zero.
memory_info->type = static_cast<u32>(MemoryState::Unmapped); Memory::Write32(page_info_address, 0);
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
/// Query memory static ResultCode QueryMemory(VAddr memory_info_address, VAddr page_info_address,
static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { VAddr query_address) {
LOG_TRACE(Kernel_SVC, "called, addr={:X}", addr); LOG_TRACE(Kernel_SVC,
return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr); "called, memory_info_address=0x{:016X}, page_info_address=0x{:016X}, "
"query_address=0x{:016X}",
memory_info_address, page_info_address, query_address);
return QueryProcessMemory(memory_info_address, page_info_address, CurrentProcess,
query_address);
} }
/// Exits the current process /// Exits the current process
@ -1907,7 +1911,7 @@ static const FunctionDef SVC_Table[] = {
{0x73, nullptr, "SetProcessMemoryPermission"}, {0x73, nullptr, "SetProcessMemoryPermission"},
{0x74, nullptr, "MapProcessMemory"}, {0x74, nullptr, "MapProcessMemory"},
{0x75, nullptr, "UnmapProcessMemory"}, {0x75, nullptr, "UnmapProcessMemory"},
{0x76, nullptr, "QueryProcessMemory"}, {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"},
{0x77, nullptr, "MapProcessCodeMemory"}, {0x77, nullptr, "MapProcessCodeMemory"},
{0x78, nullptr, "UnmapProcessCodeMemory"}, {0x78, nullptr, "UnmapProcessCodeMemory"},
{0x79, nullptr, "CreateProcess"}, {0x79, nullptr, "CreateProcess"},

View file

@ -8,22 +8,6 @@
namespace Kernel { namespace Kernel {
struct MemoryInfo {
u64 base_address;
u64 size;
u32 type;
u32 attributes;
u32 permission;
u32 device_refcount;
u32 ipc_refcount;
INSERT_PADDING_WORDS(1);
};
static_assert(sizeof(MemoryInfo) == 0x28, "MemoryInfo has incorrect size.");
struct PageInfo {
u64 flags;
};
void CallSVC(u32 immediate); void CallSVC(u32 immediate);
} // namespace Kernel } // namespace Kernel

View file

@ -7,9 +7,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/memory.h"
namespace Kernel { namespace Kernel {
@ -132,6 +130,11 @@ void SvcWrap() {
func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw); func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw);
} }
template <ResultCode func(u64, u64, u32, u64)>
void SvcWrap() {
FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2)), Param(3)).raw);
}
template <ResultCode func(u32, u64, u32)> template <ResultCode func(u32, u64, u32)>
void SvcWrap() { void SvcWrap() {
FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw); FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw);
@ -191,21 +194,6 @@ void SvcWrap() {
FuncReturn(retval); FuncReturn(retval);
} }
template <ResultCode func(MemoryInfo*, PageInfo*, u64)>
void SvcWrap() {
MemoryInfo memory_info = {};
PageInfo page_info = {};
u32 retval = func(&memory_info, &page_info, Param(2)).raw;
Memory::Write64(Param(0), memory_info.base_address);
Memory::Write64(Param(0) + 8, memory_info.size);
Memory::Write32(Param(0) + 16, memory_info.type);
Memory::Write32(Param(0) + 20, memory_info.attributes);
Memory::Write32(Param(0) + 24, memory_info.permission);
FuncReturn(retval);
}
template <ResultCode func(u32*, u64, u64, u32)> template <ResultCode func(u32*, u64, u64, u32)>
void SvcWrap() { void SvcWrap() {
u32 param_1 = 0; u32 param_1 = 0;

View file

@ -25,14 +25,14 @@ static const char* GetMemoryStateName(MemoryState state) {
"CodeMutable", "Heap", "CodeMutable", "Heap",
"Shared", "Unknown1", "Shared", "Unknown1",
"ModuleCodeStatic", "ModuleCodeMutable", "ModuleCodeStatic", "ModuleCodeMutable",
"IpcBuffer0", "Mapped", "IpcBuffer0", "Stack",
"ThreadLocal", "TransferMemoryIsolated", "ThreadLocal", "TransferMemoryIsolated",
"TransferMemory", "ProcessMemory", "TransferMemory", "ProcessMemory",
"Unknown2", "IpcBuffer1", "Inaccessible", "IpcBuffer1",
"IpcBuffer3", "KernelStack", "IpcBuffer3", "KernelStack",
}; };
return names[static_cast<int>(state)]; return names[ToSvcMemoryState(state)];
} }
bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
@ -302,6 +302,25 @@ ResultCode VMManager::HeapFree(VAddr target, u64 size) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
MemoryInfo VMManager::QueryMemory(VAddr address) const {
const auto vma = FindVMA(address);
MemoryInfo memory_info{};
if (IsValidHandle(vma)) {
memory_info.base_address = vma->second.base;
memory_info.permission = static_cast<u32>(vma->second.permissions);
memory_info.size = vma->second.size;
memory_info.state = ToSvcMemoryState(vma->second.meminfo_state);
} else {
memory_info.base_address = address_space_end;
memory_info.permission = static_cast<u32>(VMAPermission::None);
memory_info.size = 0 - address_space_end;
memory_info.state = static_cast<u32>(MemoryState::Inaccessible);
}
return memory_info;
}
ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) { ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
const auto vma = FindVMA(src_addr); const auto vma = FindVMA(src_addr);

View file

@ -43,26 +43,129 @@ enum class VMAPermission : u8 {
ReadWriteExecute = Read | Write | Execute, ReadWriteExecute = Read | Write | Execute,
}; };
/// Set of values returned in MemoryInfo.state by svcQueryMemory. // clang-format off
/// Represents memory states and any relevant flags, as used by the kernel.
/// svcQueryMemory interprets these by masking away all but the first eight
/// bits when storing memory state into a MemoryInfo instance.
enum class MemoryState : u32 { enum class MemoryState : u32 {
Unmapped = 0x0, Mask = 0xFF,
Io = 0x1, FlagProtect = 1U << 8,
Normal = 0x2, FlagDebug = 1U << 9,
CodeStatic = 0x3, FlagIPC0 = 1U << 10,
CodeMutable = 0x4, FlagIPC3 = 1U << 11,
Heap = 0x5, FlagIPC1 = 1U << 12,
Shared = 0x6, FlagMapped = 1U << 13,
ModuleCodeStatic = 0x8, FlagCode = 1U << 14,
ModuleCodeMutable = 0x9, FlagAlias = 1U << 15,
IpcBuffer0 = 0xA, FlagModule = 1U << 16,
Mapped = 0xB, FlagTransfer = 1U << 17,
ThreadLocal = 0xC, FlagQueryPhysicalAddressAllowed = 1U << 18,
TransferMemoryIsolated = 0xD, FlagSharedDevice = 1U << 19,
TransferMemory = 0xE, FlagSharedDeviceAligned = 1U << 20,
ProcessMemory = 0xF, FlagIPCBuffer = 1U << 21,
IpcBuffer1 = 0x11, FlagMemoryPoolAllocated = 1U << 22,
IpcBuffer3 = 0x12, FlagMapProcess = 1U << 23,
KernelStack = 0x13, FlagUncached = 1U << 24,
FlagCodeMemory = 1U << 25,
// Convenience flag sets to reduce repetition
IPCFlags = FlagIPC0 | FlagIPC3 | FlagIPC1,
CodeFlags = FlagDebug | IPCFlags | FlagMapped | FlagCode | FlagQueryPhysicalAddressAllowed |
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
DataFlags = FlagProtect | IPCFlags | FlagMapped | FlagAlias | FlagTransfer |
FlagQueryPhysicalAddressAllowed | FlagSharedDevice | FlagSharedDeviceAligned |
FlagMemoryPoolAllocated | FlagIPCBuffer | FlagUncached,
Unmapped = 0x00,
Io = 0x01 | FlagMapped,
Normal = 0x02 | FlagMapped | FlagQueryPhysicalAddressAllowed,
CodeStatic = 0x03 | CodeFlags | FlagMapProcess,
CodeMutable = 0x04 | CodeFlags | FlagMapProcess | FlagCodeMemory,
Heap = 0x05 | DataFlags | FlagCodeMemory,
Shared = 0x06 | FlagMapped | FlagMemoryPoolAllocated,
ModuleCodeStatic = 0x08 | CodeFlags | FlagModule | FlagMapProcess,
ModuleCodeMutable = 0x09 | DataFlags | FlagModule | FlagMapProcess | FlagCodeMemory,
IpcBuffer0 = 0x0A | FlagMapped | FlagQueryPhysicalAddressAllowed | FlagMemoryPoolAllocated |
IPCFlags | FlagSharedDevice | FlagSharedDeviceAligned,
Stack = 0x0B | FlagMapped | IPCFlags | FlagQueryPhysicalAddressAllowed |
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
ThreadLocal = 0x0C | FlagMapped | FlagMemoryPoolAllocated,
TransferMemoryIsolated = 0x0D | IPCFlags | FlagMapped | FlagQueryPhysicalAddressAllowed |
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated |
FlagUncached,
TransferMemory = 0x0E | FlagIPC3 | FlagIPC1 | FlagMapped | FlagQueryPhysicalAddressAllowed |
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
ProcessMemory = 0x0F | FlagIPC3 | FlagIPC1 | FlagMapped | FlagMemoryPoolAllocated,
// Used to signify an inaccessible or invalid memory region with memory queries
Inaccessible = 0x10,
IpcBuffer1 = 0x11 | FlagIPC3 | FlagIPC1 | FlagMapped | FlagQueryPhysicalAddressAllowed |
FlagSharedDevice | FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
IpcBuffer3 = 0x12 | FlagIPC3 | FlagMapped | FlagQueryPhysicalAddressAllowed |
FlagSharedDeviceAligned | FlagMemoryPoolAllocated,
KernelStack = 0x13 | FlagMapped,
};
// clang-format on
constexpr MemoryState operator|(MemoryState lhs, MemoryState rhs) {
return static_cast<MemoryState>(u32(lhs) | u32(rhs));
}
constexpr MemoryState operator&(MemoryState lhs, MemoryState rhs) {
return static_cast<MemoryState>(u32(lhs) & u32(rhs));
}
constexpr MemoryState operator^(MemoryState lhs, MemoryState rhs) {
return static_cast<MemoryState>(u32(lhs) ^ u32(rhs));
}
constexpr MemoryState operator~(MemoryState lhs) {
return static_cast<MemoryState>(~u32(lhs));
}
constexpr MemoryState& operator|=(MemoryState& lhs, MemoryState rhs) {
lhs = lhs | rhs;
return lhs;
}
constexpr MemoryState& operator&=(MemoryState& lhs, MemoryState rhs) {
lhs = lhs & rhs;
return lhs;
}
constexpr MemoryState& operator^=(MemoryState& lhs, MemoryState rhs) {
lhs = lhs ^ rhs;
return lhs;
}
constexpr u32 ToSvcMemoryState(MemoryState state) {
return static_cast<u32>(state & MemoryState::Mask);
}
struct MemoryInfo {
u64 base_address;
u64 size;
u32 state;
u32 attributes;
u32 permission;
u32 ipc_ref_count;
u32 device_ref_count;
};
static_assert(sizeof(MemoryInfo) == 0x28, "MemoryInfo has incorrect size.");
struct PageInfo {
u32 flags;
}; };
/** /**
@ -186,8 +289,15 @@ public:
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
ResultCode HeapFree(VAddr target, u64 size); ResultCode HeapFree(VAddr target, u64 size);
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
MemoryState state = MemoryState::Mapped);
/// Queries the memory manager for information about the given address.
///
/// @param address The address to query the memory manager about for information.
///
/// @return A MemoryInfo instance containing information about the given address.
///
MemoryInfo QueryMemory(VAddr address) const;
/** /**
* Scans all VMAs and updates the page table range of any that use the given vector as backing * Scans all VMAs and updates the page table range of any that use the given vector as backing