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; |         address |= static_cast<VAddr>(address_bits_32_47) << 32; | ||||||
|         return address; |         return address; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     u64 Size() const { | ||||||
|  |         return static_cast<u64>(size); | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| static_assert(sizeof(BufferDescriptorC) == 8, "BufferDescriptorC size is incorrect"); | static_assert(sizeof(BufferDescriptorC) == 8, "BufferDescriptorC size is incorrect"); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -54,6 +54,10 @@ public: | |||||||
|     unsigned GetCurrentOffset() const { |     unsigned GetCurrentOffset() const { | ||||||
|         return static_cast<unsigned>(index); |         return static_cast<unsigned>(index); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void SetCurrentOffset(unsigned offset) { | ||||||
|  |         index = static_cast<ptrdiff_t>(offset); | ||||||
|  |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class RequestBuilder : public RequestHelperBase { | 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) { |     for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) { | ||||||
|         buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); |         buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | ||||||
|     } |     } | ||||||
|     if (command_header->buf_c_descriptor_flags != |  | ||||||
|         IPC::CommandHeader::BufferDescriptorCFlag::Disabled) { |     buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; | ||||||
|         if (command_header->buf_c_descriptor_flags != |  | ||||||
|             IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { |  | ||||||
|             UNIMPLEMENTED(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Padding to align to 16 bytes |     // Padding to align to 16 bytes | ||||||
|     rp.AlignWithPadding(); |     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')); |         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>(); |     command = rp.Pop<u32_le>(); | ||||||
|     rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. |     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; |         return buffer_b_desciptors; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { | ||||||
|  |         return buffer_c_desciptors; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { |     const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { | ||||||
|         return domain_message_header; |         return domain_message_header; | ||||||
|     } |     } | ||||||
| @@ -200,8 +204,10 @@ private: | |||||||
|     std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; |     std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; | ||||||
|     std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; |     std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; | ||||||
|     std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; |     std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; | ||||||
|  |     std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; | ||||||
|  |  | ||||||
|     unsigned data_payload_offset{}; |     unsigned data_payload_offset{}; | ||||||
|  |     unsigned buffer_c_offset{}; | ||||||
|     u32_le command{}; |     u32_le command{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -201,10 +201,76 @@ private: | |||||||
|     Kernel::SharedPtr<Kernel::Event> event; |     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> { | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | ||||||
| public: | public: | ||||||
|     IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { |     IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|  |             {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, | ||||||
|             {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, |             {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, | ||||||
|             {66, &IApplicationFunctions::InitializeGamePlayRecording, |             {66, &IApplicationFunctions::InitializeGamePlayRecording, | ||||||
|              "InitializeGamePlayRecording"}, |              "InitializeGamePlayRecording"}, | ||||||
| @@ -215,6 +281,26 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | 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) { |     void SetTerminateResult(Kernel::HLERequestContext& ctx) { | ||||||
|         // Takes an input u32 Result, no output. |         // Takes an input u32 Result, no output. | ||||||
|         // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak. |         // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user