Merge pull request #1315 from lioncash/size
kernel/svc: Handle a few error cases within memory-related functions
This commit is contained in:
commit
e6367ab955
|
@ -17,6 +17,7 @@ enum {
|
||||||
|
|
||||||
// Confirmed Switch OS error codes
|
// Confirmed Switch OS error codes
|
||||||
MaxConnectionsReached = 7,
|
MaxConnectionsReached = 7,
|
||||||
|
InvalidSize = 101,
|
||||||
InvalidAddress = 102,
|
InvalidAddress = 102,
|
||||||
HandleTableFull = 105,
|
HandleTableFull = 105,
|
||||||
InvalidMemoryState = 106,
|
InvalidMemoryState = 106,
|
||||||
|
@ -55,6 +56,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
|
||||||
ErrCodes::InvalidMemoryPermissions);
|
ErrCodes::InvalidMemoryPermissions);
|
||||||
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
||||||
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
||||||
|
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
|
||||||
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
|
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
|
||||||
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
|
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
|
||||||
ErrCodes::InvalidThreadPriority);
|
ErrCodes::InvalidThreadPriority);
|
||||||
|
|
|
@ -35,10 +35,21 @@
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
namespace {
|
||||||
|
constexpr bool Is4KBAligned(VAddr address) {
|
||||||
|
return (address & 0xFFF) == 0;
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
||||||
static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
|
static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
|
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
|
||||||
|
|
||||||
|
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB.
|
||||||
|
if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
auto& process = *Core::CurrentProcess();
|
auto& process = *Core::CurrentProcess();
|
||||||
CASCADE_RESULT(*heap_addr,
|
CASCADE_RESULT(*heap_addr,
|
||||||
process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
|
process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
|
||||||
|
@ -56,6 +67,15 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state
|
||||||
static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||||
src_addr, size);
|
src_addr, size);
|
||||||
|
|
||||||
|
if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
||||||
|
return ERR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0 || !Is4KBAligned(size)) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
|
return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +83,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||||
static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||||
src_addr, size);
|
src_addr, size);
|
||||||
|
|
||||||
|
if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
||||||
|
return ERR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0 || !Is4KBAligned(size)) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
|
return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,35 +444,43 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
|
||||||
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
|
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
|
||||||
shared_memory_handle, addr, size, permissions);
|
shared_memory_handle, addr, size, permissions);
|
||||||
|
|
||||||
|
if (!Is4KBAligned(addr)) {
|
||||||
|
return ERR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0 || !Is4KBAligned(size)) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto permissions_type = static_cast<MemoryPermission>(permissions);
|
||||||
|
if (permissions_type != MemoryPermission::Read &&
|
||||||
|
permissions_type != MemoryPermission::ReadWrite) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions);
|
||||||
|
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
auto& kernel = Core::System::GetInstance().Kernel();
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
|
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
|
||||||
if (!shared_memory) {
|
if (!shared_memory) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions);
|
|
||||||
switch (permissions_type) {
|
|
||||||
case MemoryPermission::Read:
|
|
||||||
case MemoryPermission::Write:
|
|
||||||
case MemoryPermission::ReadWrite:
|
|
||||||
case MemoryPermission::Execute:
|
|
||||||
case MemoryPermission::ReadExecute:
|
|
||||||
case MemoryPermission::WriteExecute:
|
|
||||||
case MemoryPermission::ReadWriteExecute:
|
|
||||||
case MemoryPermission::DontCare:
|
|
||||||
return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
|
return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
|
||||||
MemoryPermission::DontCare);
|
MemoryPermission::DontCare);
|
||||||
default:
|
|
||||||
LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
|
static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
|
||||||
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
|
LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}",
|
||||||
shared_memory_handle, addr, size);
|
shared_memory_handle, addr, size);
|
||||||
|
|
||||||
|
if (!Is4KBAligned(addr)) {
|
||||||
|
return ERR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0 || !Is4KBAligned(size)) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
auto& kernel = Core::System::GetInstance().Kernel();
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
|
auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
|
||||||
|
|
||||||
|
@ -899,12 +936,28 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
|
||||||
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
|
LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
|
||||||
local_permissions, remote_permissions);
|
local_permissions, remote_permissions);
|
||||||
|
|
||||||
|
// Size must be a multiple of 4KB and be less than or equal to
|
||||||
|
// approx. 8 GB (actually (1GB - 512B) * 8)
|
||||||
|
if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto local_perms = static_cast<MemoryPermission>(local_permissions);
|
||||||
|
if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) {
|
||||||
|
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto remote_perms = static_cast<MemoryPermission>(remote_permissions);
|
||||||
|
if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite &&
|
||||||
|
remote_perms != MemoryPermission::DontCare) {
|
||||||
|
return ERR_INVALID_MEMORY_PERMISSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
auto& kernel = Core::System::GetInstance().Kernel();
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
auto& handle_table = kernel.HandleTable();
|
auto& handle_table = kernel.HandleTable();
|
||||||
auto shared_mem_handle =
|
auto shared_mem_handle =
|
||||||
SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
|
SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
|
||||||
static_cast<MemoryPermission>(local_permissions),
|
local_perms, remote_perms);
|
||||||
static_cast<MemoryPermission>(remote_permissions));
|
|
||||||
|
|
||||||
CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
|
CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
|
Reference in New Issue