From c96f22490a4a459d477f446fd4e5f894f580b69c Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 10 May 2015 19:47:07 -0300 Subject: [PATCH 1/4] Kernel: Capture SharedMemory attributes at creation, not when mapping --- src/core/hle/kernel/shared_memory.cpp | 20 +++++++++++--------- src/core/hle/kernel/shared_memory.h | 25 ++++++++++++++++++------- src/core/hle/service/apt/apt.cpp | 4 +++- src/core/hle/service/gsp_gpu.cpp | 16 +++++++++------- src/core/hle/service/hid/hid.cpp | 6 ++++-- src/core/hle/service/ir/ir.cpp | 4 +++- src/core/hle/svc.cpp | 4 +++- 7 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index cb5c16696..178589cbb 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -12,11 +12,15 @@ namespace Kernel { SharedMemory::SharedMemory() {} SharedMemory::~SharedMemory() {} -SharedPtr SharedMemory::Create(std::string name) { +SharedPtr SharedMemory::Create(u32 size, MemoryPermission permissions, + MemoryPermission other_permissions, std::string name) { SharedPtr shared_memory(new SharedMemory); shared_memory->name = std::move(name); shared_memory->base_address = 0x0; + shared_memory->size = size; + shared_memory->permissions = permissions; + shared_memory->other_permissions = other_permissions; return shared_memory; } @@ -24,7 +28,7 @@ SharedPtr SharedMemory::Create(std::string name) { ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { - if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { + if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!", GetObjectId(), address); // TODO: Verify error code with hardware @@ -32,21 +36,19 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } + // TODO: Test permissions + this->base_address = address; - this->permissions = permissions; - this->other_permissions = other_permissions; return RESULT_SUCCESS; } -ResultVal SharedMemory::GetPointer(u32 offset) { +u8* SharedMemory::GetPointer(u32 offset) { if (base_address != 0) - return MakeResult(Memory::GetPointer(base_address + offset)); + return Memory::GetPointer(base_address + offset); LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); - // TODO(yuriks): Verify error code. - return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, - ErrorSummary::InvalidState, ErrorLevel::Permanent); + return nullptr; } } // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 5833b411c..204266896 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -27,11 +27,16 @@ class SharedMemory final : public Object { public: /** * Creates a shared memory object - * @param name Optional object name, used only for debugging purposes. + * @param size Size of the memory block. Must be page-aligned. + * @param permissions Permission restrictions applied to the process which created the block. + * @param other_permissions Permission restrictions applied to other processes mapping the block. + * @param name Optional object name, used for debugging purposes. */ - static SharedPtr Create(std::string name = "Unknown"); + static SharedPtr Create(u32 size, MemoryPermission permissions, + MemoryPermission other_permissions, std::string name = "Unknown"); std::string GetTypeName() const override { return "SharedMemory"; } + std::string GetName() const override { return name; } static const HandleType HANDLE_TYPE = HandleType::SharedMemory; HandleType GetHandleType() const override { return HANDLE_TYPE; } @@ -49,12 +54,18 @@ public: * @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 */ - ResultVal GetPointer(u32 offset = 0); + u8* GetPointer(u32 offset = 0); - VAddr 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) + /// Address of shared memory block in the process. + VAddr base_address; + /// Size of the memory block. Page-aligned. + u32 size; + /// Permission restrictions applied to the process which created the block. + MemoryPermission permissions; + /// Permission restrictions applied to other processes mapping the block. + MemoryPermission other_permissions; + /// Name of shared memory object. + std::string name; private: SharedMemory(); diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 560c9dcf6..09d463dd5 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -304,7 +304,9 @@ void Init() { file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); // Create shared font memory object - shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem"); + using Kernel::MemoryPermission; + shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB + MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem"); } else { LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); shared_font_mem = nullptr; diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 8da063bd2..e2b6b0b02 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -35,8 +35,7 @@ u32 g_thread_id = 1; /// Gets a pointer to a thread command buffer in GSP shared memory static inline u8* GetCommandBuffer(u32 thread_id) { - ResultVal ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); - return ptr.ValueOr(nullptr); + return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); } static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { @@ -44,14 +43,14 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in // For each thread there are two FrameBufferUpdate fields u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); - ResultVal ptr = g_shared_memory->GetPointer(offset); - return reinterpret_cast(ptr.ValueOr(nullptr)); + u8* ptr = g_shared_memory->GetPointer(offset); + return reinterpret_cast(ptr); } /// Gets a pointer to the interrupt relay queue for a given thread index static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { - ResultVal ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); - return reinterpret_cast(ptr.ValueOr(nullptr)); + u8* ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); + return reinterpret_cast(ptr); } /** @@ -288,7 +287,10 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { g_interrupt_event = Kernel::g_handle_table.Get(cmd_buff[3]); ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); - g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem"); + + using Kernel::MemoryPermission; + g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, + MemoryPermission::ReadWrite, "GSPSharedMem"); Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index dd85848d0..9695f7e56 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -48,7 +48,7 @@ static u32 next_touch_index; // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 void Update() { - SharedMem* mem = reinterpret_cast(shared_mem->GetPointer().ValueOr(nullptr)); + SharedMem* mem = reinterpret_cast(shared_mem->GetPointer()); const PadState state = VideoCore::g_emu_window->GetPadState(); if (mem == nullptr) { @@ -163,7 +163,9 @@ void Init() { AddService(new HID_U_Interface); AddService(new HID_SPVR_Interface); - shared_mem = SharedMemory::Create("HID:SharedMem"); + using Kernel::MemoryPermission; + shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, + MemoryPermission::Read, "HID:SharedMem"); next_pad_index = 0; next_touch_index = 0; diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp index 15ac477ef..adfbb258d 100644 --- a/src/core/hle/service/ir/ir.cpp +++ b/src/core/hle/service/ir/ir.cpp @@ -34,7 +34,9 @@ void Init() { AddService(new IR_U_Interface); AddService(new IR_User_Interface); - shared_memory = SharedMemory::Create("IR:SharedMemory"); + using Kernel::MemoryPermission; + shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite, + Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory"); // Create event handle(s) handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent"); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 393cfbe79..1ec6599c7 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -601,7 +601,9 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 using Kernel::SharedMemory; // TODO(Subv): Implement this function - SharedPtr shared_memory = SharedMemory::Create(); + using Kernel::MemoryPermission; + SharedPtr shared_memory = SharedMemory::Create(size, + (MemoryPermission)my_permission, (MemoryPermission)other_permission); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); From 774eea83741286338e249e1bf188f53b53243411 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 10 May 2015 19:49:46 -0300 Subject: [PATCH 2/4] Kernel: Zero-fill shared memory blocks when mapping This works around crashes related to GSP/HID/etc. shared memory blocks having garbage values. The proper fix requires proper management of mapped memory blocks in the process. --- src/core/hle/kernel/shared_memory.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 178589cbb..0c59f4876 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include "common/logging/log.h" #include "core/mem_map.h" @@ -38,6 +40,12 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, // TODO: Test permissions + // HACK: Since there's no way to write to the memory block without mapping it onto the game + // process yet, at least initialize memory the first time it's mapped. + if (address != this->base_address) { + std::memset(Memory::GetPointer(address), 0, size); + } + this->base_address = address; return RESULT_SUCCESS; From 1538a34eda324782bf88fa382201e1e5cf8a237c Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 10 May 2015 19:51:37 -0300 Subject: [PATCH 3/4] GSP: Small tweaks to shared memory initialization --- src/core/hle/service/gsp_gpu.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index e2b6b0b02..917f4685f 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -31,7 +31,7 @@ Kernel::SharedPtr g_interrupt_event; /// GSP shared memoryings Kernel::SharedPtr g_shared_memory; /// Thread index into interrupt relay queue, 1 is arbitrary -u32 g_thread_id = 1; +u32 g_thread_id = 0; /// Gets a pointer to a thread command buffer in GSP shared memory static inline u8* GetCommandBuffer(u32 thread_id) { @@ -277,7 +277,7 @@ static void FlushDataCache(Service::Interface* self) { * 1 : "Flags" field, purpose is unknown * 3 : Handle to GSP synchronization event * Outputs: - * 0 : Result of function, 0 on success, otherwise error code + * 1 : Result of function, 0x2A07 on success, otherwise error code * 2 : Thread index into GSP command buffer * 4 : Handle to GSP shared memory */ @@ -288,13 +288,11 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { g_interrupt_event = Kernel::g_handle_table.Get(cmd_buff[3]); ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); - using Kernel::MemoryPermission; - g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, "GSPSharedMem"); - Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); - cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init + // This specific code is required for a successful initialization, rather than 0 + cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX, + ErrorSummary::Success, ErrorLevel::Success).raw; cmd_buff[2] = g_thread_id++; // Thread ID cmd_buff[4] = shmem_handle; // GSP shared memory @@ -529,8 +527,12 @@ Interface::Interface() { Register(FunctionTable); g_interrupt_event = 0; - g_shared_memory = 0; - g_thread_id = 1; + + using Kernel::MemoryPermission; + g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, + MemoryPermission::ReadWrite, "GSPSharedMem"); + + g_thread_id = 0; } } // namespace From fd85367621a1428552ed4d8f43605dd0d7b5f100 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 10 May 2015 20:09:41 -0300 Subject: [PATCH 4/4] fixup! GSP: Small tweaks to shared memory initialization --- src/core/hle/service/gsp_gpu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 917f4685f..c6252a03b 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -30,7 +30,7 @@ namespace GSP_GPU { Kernel::SharedPtr g_interrupt_event; /// GSP shared memoryings Kernel::SharedPtr g_shared_memory; -/// Thread index into interrupt relay queue, 1 is arbitrary +/// Thread index into interrupt relay queue u32 g_thread_id = 0; /// Gets a pointer to a thread command buffer in GSP shared memory