From 3013015a0c7b830c9985e4d3a6b2bd66f15546e2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 4 Jul 2014 23:46:16 -0400 Subject: [PATCH 1/5] mem_map: Updated interface to expose template functions to other modules. --- src/core/mem_map.h | 6 ++++++ src/core/mem_map_funcs.cpp | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/core/mem_map.h b/src/core/mem_map.h index d5899e4bbb..70a8dedcfb 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -128,6 +128,12 @@ extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here void Init(); void Shutdown(); +template +inline void Read(T &var, const u32 addr); + +template +inline void Write(u32 addr, const T data); + u8 Read8(const u32 addr); u16 Read16(const u32 addr); u32 Read32(const u32 addr); diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 37913119e2..d0ca85ccd7 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -41,7 +41,7 @@ u32 _VirtualAddress(const u32 addr) { } template -inline void _Read(T &var, const u32 addr) { +inline void Read(T &var, const u32 addr) { // TODO: Figure out the fastest order of tests for both read and write (they are probably different). // TODO: Make sure this represents the mirrors in a correct way. // Could just do a base-relative read, too.... TODO @@ -91,7 +91,7 @@ inline void _Read(T &var, const u32 addr) { } template -inline void _Write(u32 addr, const T data) { +inline void Write(u32 addr, const T data) { u32 vaddr = _VirtualAddress(addr); // Kernel memory command buffer @@ -247,25 +247,25 @@ u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) { u8 Read8(const u32 addr) { u8 _var = 0; - _Read(_var, addr); + Read(_var, addr); return (u8)_var; } u16 Read16(const u32 addr) { u16_le _var = 0; - _Read(_var, addr); + Read(_var, addr); return (u16)_var; } u32 Read32(const u32 addr) { u32_le _var = 0; - _Read(_var, addr); + Read(_var, addr); return _var; } u64 Read64(const u32 addr) { u64_le _var = 0; - _Read(_var, addr); + Read(_var, addr); return _var; } @@ -278,19 +278,19 @@ u32 Read16_ZX(const u32 addr) { } void Write8(const u32 addr, const u8 data) { - _Write(addr, data); + Write(addr, data); } void Write16(const u32 addr, const u16 data) { - _Write(addr, data); + Write(addr, data); } void Write32(const u32 addr, const u32 data) { - _Write(addr, data); + Write(addr, data); } void Write64(const u32 addr, const u64 data) { - _Write(addr, data); + Write(addr, data); } void WriteBlock(const u32 addr, const u8* data, const int size) { From e547128185c7bc1c2081d3ee25b6207f4d24509b Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 5 Jul 2014 00:55:39 -0400 Subject: [PATCH 2/5] Kernel: Added support for shared memory objects. SharedMemory: Added optional name field for tracking known objects. --- src/core/CMakeLists.txt | 2 + src/core/core.vcxproj | 2 + src/core/core.vcxproj.filters | 6 ++ src/core/hle/kernel/shared_memory.cpp | 94 +++++++++++++++++++++++++++ src/core/hle/kernel/shared_memory.h | 38 +++++++++++ 5 files changed, 142 insertions(+) create mode 100644 src/core/hle/kernel/shared_memory.cpp create mode 100644 src/core/hle/kernel/shared_memory.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9ee803fda3..0d3189d296 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -38,6 +38,7 @@ set(SRCS core.cpp hle/kernel/event.cpp hle/kernel/kernel.cpp hle/kernel/mutex.cpp + hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/service/apt.cpp hle/service/fs.cpp @@ -85,6 +86,7 @@ set(HEADERS core.h hle/kernel/archive.h hle/kernel/kernel.h hle/kernel/mutex.h + hle/kernel/shared_memory.h hle/kernel/thread.h hle/function_wrappers.h hle/service/apt.h diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 4e521903c4..a09a4a1f19 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -170,6 +170,7 @@ + @@ -222,6 +223,7 @@ + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 17829b8b13..7e6a7f91bf 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -179,6 +179,9 @@ file_sys + + hle\kernel + @@ -320,6 +323,9 @@ file_sys + + hle\kernel + diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp new file mode 100644 index 0000000000..3030d66fa9 --- /dev/null +++ b/src/core/hle/kernel/shared_memory.cpp @@ -0,0 +1,94 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common.h" + +#include "core/mem_map.h" +#include "core/hle/kernel/shared_memory.h" + +namespace Kernel { + +class SharedMemory : public Object { +public: + const char* GetTypeName() const { return "SharedMemory"; } + + static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } + Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } + + /** + * Wait for kernel object to synchronize + * @param wait Boolean wait set if current thread should wait as a result of sync operation + * @return Result of operation, 0 on success, otherwise error code + */ + Result WaitSynchronization(bool* wait) { + // TODO(bunnei): ImplementMe + ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); + return 0; + } + + u32 base_address; ///< Address of shared memory block in RAM + u32 permissions; ///< Permissions of shared memory block (specified by SVC field) + u32 other_permissions; ///< Other permissions of shared memory block (specified by SVC field) + std::string name; ///< Name of shared memory object (optional) +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Creates a shared memory object + * @param handle Handle of newly created shared memory object + * @param name Name of shared memory object + * @return Pointer to newly created shared memory object + */ +SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { + SharedMemory* shared_memory = new SharedMemory; + handle = Kernel::g_object_pool.Create(shared_memory); + shared_memory->name = name; + return shared_memory; +} + +/** + * Creates a shared memory object + * @param name Optional name of shared memory object + * @return Handle of newly created shared memory object + */ +Handle CreateSharedMemory(const std::string& name) { + Handle handle; + CreateSharedMemory(handle, name); + return handle; +} + +/** + * Maps a shared memory block to an address in system memory + * @param handle Shared memory block handle + * @param address Address in system memory to map shared memory block to + * @param permissions Memory block map permissions (specified by SVC field) + * @param other_permissions Memory block map other permissions (specified by SVC field) + * @return Result of operation, 0 on success, otherwise error code + */ +Result MapSharedMemory(u32 handle, u32 address, u32 permissions, u32 other_permissions) { + SharedMemory* shared_memory = Kernel::g_object_pool.GetFast(handle); + shared_memory->base_address = address; + shared_memory->permissions = permissions; + shared_memory->other_permissions = other_permissions; + return 0; +} + +/** + * Gets a pointer to the shared memory block + * @param handle Shared memory block handle + * @param offset Offset from the start of the shared memory block to get pointer + * @return Pointer to the shared memory block from the specified offset + */ +u8* GetSharedMemoryPointer(Handle handle, u32 offset) { + SharedMemory* shared_memory = Kernel::g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); + if (0 != shared_memory->base_address) + return Memory::GetPointer(shared_memory->base_address + offset); + + ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); + return nullptr; +} + +} // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h new file mode 100644 index 0000000000..4e235f6058 --- /dev/null +++ b/src/core/hle/kernel/shared_memory.h @@ -0,0 +1,38 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +/** + * Creates a shared memory object + * @param name Optional name of shared memory object + * @return Handle of newly created shared memory object + */ +Handle CreateSharedMemory(const std::string& name="Unknown"); + +/** + * Maps a shared memory block to an address in system memory + * @param handle Shared memory block handle + * @param address Address in system memory to map shared memory block to + * @param permissions Memory block map permissions (specified by SVC field) + * @param other_permissions Memory block map other permissions (specified by SVC field) + * @return Result of operation, 0 on success, otherwise error code + */ +Result MapSharedMemory(u32 handle, u32 address, u32 permissions, u32 other_permissions); + +/** + * Gets a pointer to the shared memory block + * @param handle Shared memory block handle + * @param offset Offset from the start of the shared memory block to get pointer + * @return Pointer to the shared memory block from the specified offset + */ +u8* GetSharedMemoryPointer(Handle handle, u32 offset); + +} // namespace From 7b7a435094654da2a707a2089ed5ca9584679c38 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 5 Jul 2014 00:59:58 -0400 Subject: [PATCH 3/5] GSP: Fixed to use real shared memory object, various cleanups. - Previously, used a hard-coded shared memory handle of 0x10002000 (as used by libctru homebrew) GSP: Added name for shared memory. GSP: Cleaned up assertion message. --- src/core/hle/service/gsp.cpp | 59 +++++++++++++++++++++--------------- src/core/hle/svc.cpp | 11 ++++--- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index f75ba75c28..1fdbdf3428 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -9,6 +9,7 @@ #include "core/mem_map.h" #include "core/hle/hle.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/gsp.h" #include "core/hw/gpu.h" @@ -36,14 +37,24 @@ union GX_CmdBufferHeader { BitField<8,8,u32> number_commands; }; -/// Gets the address of the start (header) of a command buffer in GSP shared memory -static inline u32 GX_GetCmdBufferAddress(u32 thread_id) { - return (0x10002000 + 0x800 + (thread_id * 0x200)); -} +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace GSP_GPU + +namespace GSP_GPU { + +Handle g_event = 0; +Handle g_shared_memory = 0; + +u32 g_thread_id = 0; + +enum { + REG_FRAMEBUFFER_1 = 0x00400468, + REG_FRAMEBUFFER_2 = 0x00400494, +}; /// Gets a pointer to the start (header) of a command buffer in GSP shared memory static inline u8* GX_GetCmdBufferPointer(u32 thread_id, u32 offset=0) { - return Memory::GetPointer(GX_GetCmdBufferAddress(thread_id) + offset); + return Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * 0x200) + offset); } /// Finishes execution of a GSP command @@ -56,19 +67,6 @@ void GX_FinishCommand(u32 thread_id) { // TODO: Increment header->index? } -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace GSP_GPU - -namespace GSP_GPU { - -Handle g_event_handle = 0; -u32 g_thread_id = 0; - -enum { - REG_FRAMEBUFFER_1 = 0x00400468, - REG_FRAMEBUFFER_2 = 0x00400494, -}; - /// Read a GSP GPU hardware register void ReadHWRegs(Service::Interface* self) { static const u32 framebuffer_1[] = {GPU::PADDR_VRAM_TOP_LEFT_FRAME1, GPU::PADDR_VRAM_TOP_RIGHT_FRAME1}; @@ -103,24 +101,34 @@ void ReadHWRegs(Service::Interface* self) { } +/** + * GSP_GPU::RegisterInterruptRelayQueue service function + * Inputs: + * 1 : "Flags" field, purpose is unknown + * 3 : Handle to GSP synchronization event + * Outputs: + * 0 : Result of function, 0 on success, otherwise error code + * 2 : Thread index into GSP command buffer + * 4 : Handle to GSP shared memory + */ void RegisterInterruptRelayQueue(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; - u32 event_handle = cmd_buff[3]; + g_event = cmd_buff[3]; - _assert_msg_(GSP, (event_handle != 0), "called, but event is nullptr!"); + _assert_msg_(GSP, (g_event != 0), "handle is not valid!"); - g_event_handle = event_handle; - - Kernel::SetEventLocked(event_handle, false); + Kernel::SetEventLocked(g_event, false); // Hack - This function will permanently set the state of the GSP event such that GPU command // synchronization barriers always passthrough. Correct solution would be to set this after the // GPU as processed all queued up commands, but due to the emulator being single-threaded they // will always be ready. - Kernel::SetPermanentLock(event_handle, true); + Kernel::SetPermanentLock(g_event, true); - cmd_buff[2] = g_thread_id; // ThreadID + cmd_buff[0] = 0; // Result - no error + cmd_buff[2] = g_thread_id; // ThreadID + cmd_buff[4] = g_shared_memory; // GSP shared memory } @@ -208,6 +216,7 @@ const Interface::FunctionInfo FunctionTable[] = { Interface::Interface() { Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + g_shared_memory = Kernel::CreateSharedMemory("GSPSharedMem"); } Interface::~Interface() { diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 441d8ce8d1..746d24a70d 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -12,6 +12,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/function_wrappers.h" @@ -58,17 +59,17 @@ Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 siz } /// Maps a memory block to specified address -Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { +Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", - memblock, addr, mypermissions, otherpermission); - switch (mypermissions) { + handle, addr, permissions, other_permissions); + switch (permissions) { case MEMORY_PERMISSION_NORMAL: case MEMORY_PERMISSION_NORMAL + 1: case MEMORY_PERMISSION_NORMAL + 2: - Memory::MapBlock_Shared(memblock, addr, mypermissions); + Kernel::MapSharedMemory(handle, addr, permissions, other_permissions); break; default: - ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions); + ERROR_LOG(OSHLE, "unknown permissions=0x%08X", permissions); } return 0; } From 882dc0792904ec47d57a356a3c9e8fc1a240cc73 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 5 Jul 2014 10:12:27 -0400 Subject: [PATCH 4/5] Memory: Removed deprecated MapBlock_Shared function. --- src/core/mem_map.h | 8 -------- src/core/mem_map_funcs.cpp | 22 ---------------------- 2 files changed, 30 deletions(-) diff --git a/src/core/mem_map.h b/src/core/mem_map.h index 70a8dedcfb..12941f558c 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -149,14 +149,6 @@ void WriteBlock(const u32 addr, const u8* data, const int size); u8* GetPointer(const u32 Address); -/** - * Maps a block of memory in shared memory - * @param handle Handle to map memory block for - * @param addr Address to map memory block to - * @param permissions Memory map permissions - */ -u32 MapBlock_Shared(u32 handle, u32 addr,u32 permissions) ; - /** * Maps a block of memory on the heap * @param size Size of block in bytes diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index d0ca85ccd7..0342122dfb 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -177,28 +177,6 @@ u8 *GetPointer(const u32 addr) { } } -/** - * Maps a block of memory in shared memory - * @param handle Handle to map memory block for - * @param addr Address to map memory block to - * @param permissions Memory map permissions - */ -u32 MapBlock_Shared(u32 handle, u32 addr,u32 permissions) { - MemoryBlock block; - - block.handle = handle; - block.base_address = addr; - block.permissions = permissions; - - if (g_shared_map.size() > 0) { - const MemoryBlock last_block = g_shared_map.rbegin()->second; - block.address = last_block.address + last_block.size; - } - g_shared_map[block.GetVirtualAddress()] = block; - - return block.GetVirtualAddress(); -} - /** * Maps a block of memory on the heap * @param size Size of block in bytes From 7ff92c36ed70e75a54d8a15a7806ab9be34b3168 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 5 Jul 2014 10:22:03 -0400 Subject: [PATCH 5/5] SharedMemory: Updated MapSharedMemory to use an enum for permissions. - Also added some safety checks to MapSharedMemory. --- src/core/hle/kernel/shared_memory.cpp | 21 ++++++++++++++++----- src/core/hle/kernel/shared_memory.h | 12 +++++++++++- src/core/hle/svc.cpp | 19 +++++++++---------- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 3030d66fa9..52823048f7 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -27,10 +27,10 @@ public: return 0; } - u32 base_address; ///< Address of shared memory block in RAM - u32 permissions; ///< Permissions of shared memory block (specified by SVC field) - u32 other_permissions; ///< Other permissions of shared memory block (specified by SVC field) - std::string name; ///< Name of shared memory object (optional) + u32 base_address; ///< Address of shared memory block in RAM + MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) + MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) + std::string name; ///< Name of shared memory object (optional) }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -67,11 +67,21 @@ Handle CreateSharedMemory(const std::string& name) { * @param other_permissions Memory block map other permissions (specified by SVC field) * @return Result of operation, 0 on success, otherwise error code */ -Result MapSharedMemory(u32 handle, u32 address, u32 permissions, u32 other_permissions) { +Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, + MemoryPermission other_permissions) { + + if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { + ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", + handle); + return -1; + } SharedMemory* shared_memory = Kernel::g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); + shared_memory->base_address = address; shared_memory->permissions = permissions; shared_memory->other_permissions = other_permissions; + return 0; } @@ -84,6 +94,7 @@ Result MapSharedMemory(u32 handle, u32 address, u32 permissions, u32 other_permi u8* GetSharedMemoryPointer(Handle handle, u32 offset) { SharedMemory* shared_memory = Kernel::g_object_pool.GetFast(handle); _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); + if (0 != shared_memory->base_address) return Memory::GetPointer(shared_memory->base_address + offset); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 4e235f6058..5312b88545 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -10,6 +10,15 @@ namespace Kernel { +/// Permissions for mapped shared memory blocks +enum class MemoryPermission : u32 { + None = 0, + Read = (1u << 0), + Write = (1u << 1), + ReadWrite = (Read | Write), + DontCare = (1u << 28) +}; + /** * Creates a shared memory object * @param name Optional name of shared memory object @@ -25,7 +34,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown"); * @param other_permissions Memory block map other permissions (specified by SVC field) * @return Result of operation, 0 on success, otherwise error code */ -Result MapSharedMemory(u32 handle, u32 address, u32 permissions, u32 other_permissions); +Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, + MemoryPermission other_permissions); /** * Gets a pointer to the shared memory block diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 746d24a70d..9130d77eca 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -29,11 +29,6 @@ enum ControlMemoryOperation { MEMORY_OPERATION_GSP_HEAP = 0x00010003, }; -enum MapMemoryPermission { - MEMORY_PERMISSION_UNMAP = 0x00000000, - MEMORY_PERMISSION_NORMAL = 0x00000001, -}; - /// Map application or GSP heap memory Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", @@ -62,11 +57,15 @@ Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 siz Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", handle, addr, permissions, other_permissions); - switch (permissions) { - case MEMORY_PERMISSION_NORMAL: - case MEMORY_PERMISSION_NORMAL + 1: - case MEMORY_PERMISSION_NORMAL + 2: - Kernel::MapSharedMemory(handle, addr, permissions, other_permissions); + + Kernel::MemoryPermission permissions_type = static_cast(permissions); + switch (permissions_type) { + case Kernel::MemoryPermission::Read: + case Kernel::MemoryPermission::Write: + case Kernel::MemoryPermission::ReadWrite: + case Kernel::MemoryPermission::DontCare: + Kernel::MapSharedMemory(handle, addr, permissions_type, + static_cast(other_permissions)); break; default: ERROR_LOG(OSHLE, "unknown permissions=0x%08X", permissions);