diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-01-18 16:54:34 -0300 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2018-01-18 14:54:34 -0500 | 
| commit | 59575d5cae573b57eb9e1e611e2c25ceb935ec0a (patch) | |
| tree | ec98ab8ec825b0001face3a4e7c9b821bd67e0b2 /src/core/hle | |
| parent | 463356f0a74d103ff1d4e6ef5cbd73b8a8b53135 (diff) | |
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
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/ipc.h | 4 | ||||
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 34 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/am/applet_oe.cpp | 86 | 
5 files changed, 127 insertions, 7 deletions
| diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 1840fac12..0dcaede67 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -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"); diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 25530a3c8..4c9b0de28 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -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 { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ac62a0d5a..73bb6a8be 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -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.  } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 6dceb766d..80fa48d7f 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -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{};  }; diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index b360e7e5f..0d7f9c03d 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -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. | 
