summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp138
1 files changed, 78 insertions, 60 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 725f16ea4..156c565b0 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1183,79 +1183,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
-static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr,
- u64 size, u32 permissions) {
- std::lock_guard lock{HLE::g_hle_lock};
+constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
+ switch (perm) {
+ case Svc::MemoryPermission::Read:
+ case Svc::MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
+ return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
+}
+
+static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
+ u64 size, Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
- shared_memory_handle, addr, size, permissions);
+ shmem_handle, address, size, map_perm);
- if (!Common::Is4KBAligned(addr)) {
- LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
- return ResultInvalidAddress;
- }
+ // 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);
- if (size == 0) {
- LOG_ERROR(Kernel_SVC, "Size is 0");
- return ResultInvalidSize;
- }
+ // Validate the permission.
+ R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
- if (!Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
- return ResultInvalidSize;
- }
+ // Get the current process.
+ auto& process = *system.Kernel().CurrentProcess();
+ auto& page_table = process.PageTable();
- if (!IsValidAddressRange(addr, size)) {
- LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
- addr, size);
- return ResultInvalidCurrentMemory;
- }
+ // Get the shared memory.
+ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
+ R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
- const auto permission_type = static_cast<MemoryPermission>(permissions);
- if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) {
- LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
- permissions);
- return ResultInvalidNewMemoryPermission;
- }
+ // Verify that the mapping is in range.
+ R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
- auto* const current_process{system.Kernel().CurrentProcess()};
- auto& page_table{current_process->PageTable()};
+ // Add the shared memory to the process.
+ R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
- if (page_table.IsInvalidRegion(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Addr does not fit within the valid region, addr=0x{:016X}, "
- "size=0x{:016X}",
- addr, size);
- return ResultInvalidMemoryRegion;
- }
+ // Ensure that we clean up the shared memory if we fail to map it.
+ auto guard =
+ SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
- if (page_table.IsInsideHeapRegion(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Addr does not fit within the heap region, addr=0x{:016X}, "
- "size=0x{:016X}",
- addr, size);
- return ResultInvalidMemoryRegion;
- }
+ // Map the shared memory.
+ R_TRY(shmem->Map(process, address, size, map_perm));
- if (page_table.IsInsideAliasRegion(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Address does not fit within the map region, addr=0x{:016X}, "
- "size=0x{:016X}",
- addr, size);
- return ResultInvalidMemoryRegion;
- }
+ // We succeeded.
+ guard.Cancel();
+ return RESULT_SUCCESS;
+}
+
+static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
+ u32 size, Svc::MemoryPermission map_perm) {
+ return MapSharedMemory(system, shmem_handle, address, size, map_perm);
+}
+
+static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
+ u64 size) {
+ // 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 current process.
+ auto& process = *system.Kernel().CurrentProcess();
+ auto& page_table = process.PageTable();
+
+ // Get the shared memory.
+ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
+ R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
- auto shared_memory{
- current_process->GetHandleTable().GetObject<KSharedMemory>(shared_memory_handle)};
- R_UNLESS(shared_memory.IsNotNull(), ResultInvalidHandle);
+ // Verify that the mapping is in range.
+ R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
- return shared_memory->Map(*current_process, addr, size,
- static_cast<KMemoryPermission>(permission_type));
+ // Unmap the shared memory.
+ R_TRY(shmem->Unmap(process, address, size));
+
+ // Remove the shared memory from the process.
+ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
+
+ return RESULT_SUCCESS;
}
-static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr,
- u32 size, u32 permissions) {
- return MapSharedMemory(system, shared_memory_handle, addr, size, permissions);
+static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
+ u32 size) {
+ return UnmapSharedMemory(system, shmem_handle, address, size);
}
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
@@ -2297,7 +2315,7 @@ static const FunctionDef SVC_Table_32[] = {
{0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
{0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
{0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
- {0x14, nullptr, "UnmapSharedMemory32"},
+ {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"},
{0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
{0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
{0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
@@ -2492,7 +2510,7 @@ static const FunctionDef SVC_Table_64[] = {
{0x11, SvcWrap64<SignalEvent>, "SignalEvent"},
{0x12, SvcWrap64<ClearEvent>, "ClearEvent"},
{0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"},
- {0x14, nullptr, "UnmapSharedMemory"},
+ {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"},
{0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"},
{0x16, SvcWrap64<CloseHandle>, "CloseHandle"},
{0x17, SvcWrap64<ResetSignal>, "ResetSignal"},