Stub PopLaunchParameter and implement Buffer C Descriptors reading on hle_ipc (#96)
* Stub PopLaunchParameter and implement Buffer C Descriptors reading * Address PR feedback * Ensure we push a u64 not a size_t * Fix formatting
This commit is contained in:
		| @@ -133,6 +133,10 @@ struct BufferDescriptorC { | ||||
|         address |= static_cast<VAddr>(address_bits_32_47) << 32; | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     u64 Size() const { | ||||
|         return static_cast<u64>(size); | ||||
|     } | ||||
| }; | ||||
| static_assert(sizeof(BufferDescriptorC) == 8, "BufferDescriptorC size is incorrect"); | ||||
|  | ||||
|   | ||||
| @@ -54,6 +54,10 @@ public: | ||||
|     unsigned GetCurrentOffset() const { | ||||
|         return static_cast<unsigned>(index); | ||||
|     } | ||||
|  | ||||
|     void SetCurrentOffset(unsigned offset) { | ||||
|         index = static_cast<ptrdiff_t>(offset); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class RequestBuilder : public RequestHelperBase { | ||||
|   | ||||
| @@ -81,13 +81,8 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | ||||
|     for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) { | ||||
|         buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | ||||
|     } | ||||
|     if (command_header->buf_c_descriptor_flags != | ||||
|         IPC::CommandHeader::BufferDescriptorCFlag::Disabled) { | ||||
|         if (command_header->buf_c_descriptor_flags != | ||||
|             IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; | ||||
|  | ||||
|     // Padding to align to 16 bytes | ||||
|     rp.AlignWithPadding(); | ||||
| @@ -117,6 +112,31 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | ||||
|         ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); | ||||
|     } | ||||
|  | ||||
|     rp.SetCurrentOffset(buffer_c_offset); | ||||
|  | ||||
|     // For Inline buffers, the response data is written directly to buffer_c_offset | ||||
|     // and in this case we don't have any BufferDescriptorC on the request. | ||||
|     if (command_header->buf_c_descriptor_flags > | ||||
|         IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { | ||||
|         if (command_header->buf_c_descriptor_flags == | ||||
|             IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { | ||||
|             buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); | ||||
|         } else { | ||||
|             unsigned num_buf_c_descriptors = | ||||
|                 static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2; | ||||
|  | ||||
|             // This is used to detect possible underflows, in case something is broken | ||||
|             // with the two ifs above and the flags value is == 0 || == 1. | ||||
|             ASSERT(num_buf_c_descriptors < 14); | ||||
|  | ||||
|             for (unsigned i = 0; i < num_buf_c_descriptors; ++i) { | ||||
|                 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     rp.SetCurrentOffset(data_payload_offset); | ||||
|  | ||||
|     command = rp.Pop<u32_le>(); | ||||
|     rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. | ||||
| } | ||||
|   | ||||
| @@ -143,6 +143,10 @@ public: | ||||
|         return buffer_b_desciptors; | ||||
|     } | ||||
|  | ||||
|     const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { | ||||
|         return buffer_c_desciptors; | ||||
|     } | ||||
|  | ||||
|     const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { | ||||
|         return domain_message_header; | ||||
|     } | ||||
| @@ -200,8 +204,10 @@ private: | ||||
|     std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; | ||||
|     std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; | ||||
|     std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; | ||||
|     std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; | ||||
|  | ||||
|     unsigned data_payload_offset{}; | ||||
|     unsigned buffer_c_offset{}; | ||||
|     u32_le command{}; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -201,10 +201,76 @@ private: | ||||
|     Kernel::SharedPtr<Kernel::Event> event; | ||||
| }; | ||||
|  | ||||
| class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | ||||
| public: | ||||
|     explicit IStorageAccessor(std::vector<u8> buffer) | ||||
|         : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IStorageAccessor::GetSize, "GetSize"}, | ||||
|             {11, &IStorageAccessor::Read, "Read"}, | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     std::vector<u8> buffer; | ||||
|  | ||||
|     void GetSize(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestBuilder rb{ctx, 4}; | ||||
|  | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push(static_cast<u64>(buffer.size())); | ||||
|  | ||||
|         LOG_DEBUG(Service, "called"); | ||||
|     } | ||||
|  | ||||
|     void Read(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|  | ||||
|         u64 offset = rp.Pop<u64>(); | ||||
|  | ||||
|         const auto& output_buffer = ctx.BufferDescriptorC()[0]; | ||||
|  | ||||
|         ASSERT(offset + output_buffer.Size() <= buffer.size()); | ||||
|  | ||||
|         Memory::WriteBlock(output_buffer.Address(), buffer.data() + offset, output_buffer.Size()); | ||||
|  | ||||
|         IPC::RequestBuilder rb{ctx, 2}; | ||||
|  | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|  | ||||
|         LOG_DEBUG(Service, "called"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class IStorage final : public ServiceFramework<IStorage> { | ||||
| public: | ||||
|     explicit IStorage(std::vector<u8> buffer) | ||||
|         : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IStorage::Open, "Open"}, | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     std::vector<u8> buffer; | ||||
|  | ||||
|     void Open(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; | ||||
|  | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushIpcInterface<AM::IStorageAccessor>(buffer); | ||||
|  | ||||
|         LOG_DEBUG(Service, "called"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | ||||
| public: | ||||
|     IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, | ||||
|             {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, | ||||
|             {66, &IApplicationFunctions::InitializeGamePlayRecording, | ||||
|              "InitializeGamePlayRecording"}, | ||||
| @@ -215,6 +281,26 @@ public: | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void PopLaunchParameter(Kernel::HLERequestContext& ctx) { | ||||
|         constexpr u8 data[0x88] = { | ||||
|             0xca, 0x97, 0x94, 0xc7, // Magic | ||||
|             1,    0,    0,    0,    // IsAccountSelected (bool) | ||||
|             1,    0,    0,    0,    // User Id (word 0) | ||||
|             0,    0,    0,    0,    // User Id (word 1) | ||||
|             0,    0,    0,    0,    // User Id (word 2) | ||||
|             0,    0,    0,    0     // User Id (word 3) | ||||
|         }; | ||||
|  | ||||
|         std::vector<u8> buffer(data, data + sizeof(data)); | ||||
|  | ||||
|         IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; | ||||
|  | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushIpcInterface<AM::IStorage>(buffer); | ||||
|  | ||||
|         LOG_DEBUG(Service, "called"); | ||||
|     } | ||||
|  | ||||
|     void SetTerminateResult(Kernel::HLERequestContext& ctx) { | ||||
|         // Takes an input u32 Result, no output. | ||||
|         // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user