diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 3501e45db..882a51df1 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -188,6 +188,10 @@ template void Wrap() { FuncReturn(retval); } +template void Wrap() { + FuncReturn(func(PARAM(0), PARAM(1)).raw); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type u32 diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 1f477664b..d90f0f00f 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -39,6 +39,12 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } + // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't + // match what was specified when the memory block was created. + + // TODO(Subv): Return E0E01BEE when address should be 0. + // Note: Find out when that's the case. + if (fixed_address != 0) { if (address != 0 && address != fixed_address) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X!", @@ -74,6 +80,21 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, return RESULT_SUCCESS; } +ResultCode SharedMemory::Unmap(VAddr address) { + if (base_address == 0) { + // TODO(Subv): Verify what actually happens when you want to unmap a memory block that + // was originally mapped with address = 0 + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); + } + + if (base_address != address) + return ResultCode(ErrorDescription::WrongAddress, ErrorModule::OS, ErrorSummary::InvalidState, ErrorLevel::Usage); + + base_address = 0; + + return RESULT_SUCCESS; +} + u8* SharedMemory::GetPointer(u32 offset) { if (base_address != 0) return Memory::GetPointer(base_address + offset); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 35b550d12..b51049ad0 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -52,6 +52,13 @@ public: */ ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); + /** + * Unmaps a shared memory block from the specified address in system memory + * @param address Address in system memory where the shared memory block is mapped + * @return Result code of the unmap operation + */ + ResultCode Unmap(VAddr address); + /** * Gets a pointer to the shared memory block * @param offset Offset from the start of the shared memory block to get pointer diff --git a/src/core/hle/result.h b/src/core/hle/result.h index cb2d681e0..ea3abb5f6 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -18,6 +18,7 @@ /// Detailed description of the error. This listing is likely incomplete. enum class ErrorDescription : u32 { Success = 0, + WrongAddress = 53, FS_NotFound = 100, FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive InvalidSection = 1000, diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index e39edcc16..ba21e06d5 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -161,6 +161,8 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", handle, addr, permissions, other_permissions); + // TODO(Subv): The same process that created a SharedMemory object can not map it in its own address space + SharedPtr shared_memory = Kernel::g_handle_table.Get(handle); if (shared_memory == nullptr) return ERR_INVALID_HANDLE; @@ -175,13 +177,27 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o case MemoryPermission::WriteExecute: case MemoryPermission::ReadWriteExecute: case MemoryPermission::DontCare: - shared_memory->Map(addr, permissions_type, + return shared_memory->Map(addr, permissions_type, static_cast(other_permissions)); - break; default: LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); } - return RESULT_SUCCESS; + + return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); +} + +static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { + using Kernel::SharedMemory; + + LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr); + + // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap + + SharedPtr shared_memory = Kernel::g_handle_table.Get(handle); + if (shared_memory == nullptr) + return ERR_INVALID_HANDLE; + + return shared_memory->Unmap(addr); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -765,7 +781,13 @@ static s64 GetSystemTick() { static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, u32 other_permission) { using Kernel::SharedMemory; - // TODO(Subv): Implement this function + + if (size % Memory::PAGE_SIZE != 0) + return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); + + // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap + + // TODO(Subv): Implement this function properly using Kernel::MemoryPermission; SharedPtr shared_memory = SharedMemory::Create(size, @@ -912,7 +934,7 @@ static const FunctionDef SVC_Table[] = { {0x1D, HLE::Wrap, "ClearTimer"}, {0x1E, HLE::Wrap, "CreateMemoryBlock"}, {0x1F, HLE::Wrap, "MapMemoryBlock"}, - {0x20, nullptr, "UnmapMemoryBlock"}, + {0x20, HLE::Wrap, "UnmapMemoryBlock"}, {0x21, HLE::Wrap, "CreateAddressArbiter"}, {0x22, HLE::Wrap, "ArbitrateAddress"}, {0x23, HLE::Wrap, "CloseHandle"},