Merge pull request #740 from yuriks/gsp-shmem

Fix crashes due to un-initialized GSP shared memory
master
archshift 2015-05-10 18:07:44 +07:00
commit e98fbadf4a
7 changed files with 67 additions and 34 deletions

@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstring>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/mem_map.h" #include "core/mem_map.h"
@ -12,11 +14,15 @@ namespace Kernel {
SharedMemory::SharedMemory() {} SharedMemory::SharedMemory() {}
SharedMemory::~SharedMemory() {} SharedMemory::~SharedMemory() {}
SharedPtr<SharedMemory> SharedMemory::Create(std::string name) { SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions,
MemoryPermission other_permissions, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory); SharedPtr<SharedMemory> shared_memory(new SharedMemory);
shared_memory->name = std::move(name); shared_memory->name = std::move(name);
shared_memory->base_address = 0x0; shared_memory->base_address = 0x0;
shared_memory->size = size;
shared_memory->permissions = permissions;
shared_memory->other_permissions = other_permissions;
return shared_memory; return shared_memory;
} }
@ -24,7 +30,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
MemoryPermission other_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!", LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!",
GetObjectId(), address); GetObjectId(), address);
// TODO: Verify error code with hardware // TODO: Verify error code with hardware
@ -32,21 +38,25 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent); ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
} }
// 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; this->base_address = address;
this->permissions = permissions;
this->other_permissions = other_permissions;
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { u8* SharedMemory::GetPointer(u32 offset) {
if (base_address != 0) if (base_address != 0)
return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); return Memory::GetPointer(base_address + offset);
LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
// TODO(yuriks): Verify error code. return nullptr;
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
ErrorSummary::InvalidState, ErrorLevel::Permanent);
} }
} // namespace } // namespace

@ -27,11 +27,16 @@ class SharedMemory final : public Object {
public: public:
/** /**
* Creates a shared memory object * 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<SharedMemory> Create(std::string name = "Unknown"); static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
MemoryPermission other_permissions, std::string name = "Unknown");
std::string GetTypeName() const override { return "SharedMemory"; } std::string GetTypeName() const override { return "SharedMemory"; }
std::string GetName() const override { return name; }
static const HandleType HANDLE_TYPE = HandleType::SharedMemory; static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
HandleType GetHandleType() const override { return HANDLE_TYPE; } 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 * @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 * @return Pointer to the shared memory block from the specified offset
*/ */
ResultVal<u8*> GetPointer(u32 offset = 0); u8* GetPointer(u32 offset = 0);
VAddr base_address; ///< Address of shared memory block in RAM /// Address of shared memory block in the process.
MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) VAddr base_address;
MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) /// Size of the memory block. Page-aligned.
std::string name; ///< Name of shared memory object (optional) 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: private:
SharedMemory(); SharedMemory();

@ -304,7 +304,9 @@ void Init() {
file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); file.ReadBytes(shared_font.data(), (size_t)file.GetSize());
// Create shared font memory object // 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 { } else {
LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
shared_font_mem = nullptr; shared_font_mem = nullptr;

@ -30,13 +30,12 @@ namespace GSP_GPU {
Kernel::SharedPtr<Kernel::Event> g_interrupt_event; Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
/// GSP shared memoryings /// GSP shared memoryings
Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory; Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
/// Thread index into interrupt relay queue, 1 is arbitrary /// Thread index into interrupt relay queue
u32 g_thread_id = 1; u32 g_thread_id = 0;
/// Gets a pointer to a thread command buffer in GSP shared memory /// Gets a pointer to a thread command buffer in GSP shared memory
static inline u8* GetCommandBuffer(u32 thread_id) { static inline u8* GetCommandBuffer(u32 thread_id) {
ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
return ptr.ValueOr(nullptr);
} }
static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 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 // For each thread there are two FrameBufferUpdate fields
u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset); u8* ptr = g_shared_memory->GetPointer(offset);
return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); return reinterpret_cast<FrameBufferUpdate*>(ptr);
} }
/// Gets a pointer to the interrupt relay queue for a given thread index /// Gets a pointer to the interrupt relay queue for a given thread index
static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); u8* ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); return reinterpret_cast<InterruptRelayQueue*>(ptr);
} }
/** /**
@ -278,7 +277,7 @@ static void FlushDataCache(Service::Interface* self) {
* 1 : "Flags" field, purpose is unknown * 1 : "Flags" field, purpose is unknown
* 3 : Handle to GSP synchronization event * 3 : Handle to GSP synchronization event
* Outputs: * 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 * 2 : Thread index into GSP command buffer
* 4 : Handle to GSP shared memory * 4 : Handle to GSP shared memory
*/ */
@ -288,11 +287,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem");
Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); 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[2] = g_thread_id++; // Thread ID
cmd_buff[4] = shmem_handle; // GSP shared memory cmd_buff[4] = shmem_handle; // GSP shared memory
@ -527,8 +527,12 @@ Interface::Interface() {
Register(FunctionTable); Register(FunctionTable);
g_interrupt_event = 0; 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 } // namespace

@ -48,7 +48,7 @@ static u32 next_touch_index;
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
void Update() { void Update() {
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr)); SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
const PadState state = VideoCore::g_emu_window->GetPadState(); const PadState state = VideoCore::g_emu_window->GetPadState();
if (mem == nullptr) { if (mem == nullptr) {
@ -163,7 +163,9 @@ void Init() {
AddService(new HID_U_Interface); AddService(new HID_U_Interface);
AddService(new HID_SPVR_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_pad_index = 0;
next_touch_index = 0; next_touch_index = 0;

@ -34,7 +34,9 @@ void Init() {
AddService(new IR_U_Interface); AddService(new IR_U_Interface);
AddService(new IR_User_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) // Create event handle(s)
handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent"); handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent");

@ -601,7 +601,9 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
using Kernel::SharedMemory; using Kernel::SharedMemory;
// TODO(Subv): Implement this function // TODO(Subv): Implement this function
SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(); using Kernel::MemoryPermission;
SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
(MemoryPermission)my_permission, (MemoryPermission)other_permission);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);