mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	
						commit
						a1393dc70c
					
				@ -219,6 +219,7 @@ set(HEADERS
 | 
			
		||||
            hle/config_mem.h
 | 
			
		||||
            hle/function_wrappers.h
 | 
			
		||||
            hle/ipc.h
 | 
			
		||||
            hle/ipc_helpers.h
 | 
			
		||||
            hle/applets/applet.h
 | 
			
		||||
            hle/applets/erreula.h
 | 
			
		||||
            hle/applets/mii_selector.h
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,26 @@ static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of
 | 
			
		||||
 * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
 | 
			
		||||
 * the service handler process' memory.
 | 
			
		||||
 * @param offset Optional offset into command buffer
 | 
			
		||||
 * @param offset Optional offset into command buffer (in bytes)
 | 
			
		||||
 * @return Pointer to command buffer
 | 
			
		||||
 */
 | 
			
		||||
inline u32* GetCommandBuffer(const int offset = 0) {
 | 
			
		||||
    return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
 | 
			
		||||
                                    offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const int kStaticBuffersOffset =
 | 
			
		||||
    0x100; ///< Offset into static buffers, relative to command buffer header
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns a pointer to the static buffers area in the current thread's TLS
 | 
			
		||||
 * TODO(Subv): cf. GetCommandBuffer
 | 
			
		||||
 * @param offset Optional offset into static buffers area (in bytes)
 | 
			
		||||
 * @return Pointer to static buffers area
 | 
			
		||||
 */
 | 
			
		||||
inline u32* GetStaticBuffers(const int offset = 0) {
 | 
			
		||||
    return GetCommandBuffer(kStaticBuffersOffset + offset);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace IPC {
 | 
			
		||||
@ -40,10 +54,17 @@ enum DescriptorType : u32 {
 | 
			
		||||
    CallingPid = 0x20,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union Header {
 | 
			
		||||
    u32 raw;
 | 
			
		||||
    BitField<0, 6, u32> translate_params_size;
 | 
			
		||||
    BitField<6, 6, u32> normal_params_size;
 | 
			
		||||
    BitField<16, 16, u32> command_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Creates a command header to be used for IPC
 | 
			
		||||
 * @param command_id            ID of the command to create a header for.
 | 
			
		||||
 * @param normal_params         Size of the normal parameters in words. Up to 63.
 | 
			
		||||
 * @param normal_params_size         Size of the normal parameters in words. Up to 63.
 | 
			
		||||
 * @param translate_params_size Size of the translate parameters in words. Up to 63.
 | 
			
		||||
 * @return The created IPC header.
 | 
			
		||||
 *
 | 
			
		||||
@ -51,24 +72,16 @@ enum DescriptorType : u32 {
 | 
			
		||||
 * through modifications and checks by the kernel.
 | 
			
		||||
 * The translate parameters are described by headers generated with the IPC::*Desc functions.
 | 
			
		||||
 *
 | 
			
		||||
 * @note While #normal_params is equivalent to the number of normal parameters,
 | 
			
		||||
 * @note While #normal_params_size is equivalent to the number of normal parameters,
 | 
			
		||||
 * #translate_params_size includes the size occupied by the translate parameters headers.
 | 
			
		||||
 */
 | 
			
		||||
constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params,
 | 
			
		||||
                         unsigned int translate_params_size) {
 | 
			
		||||
    return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) |
 | 
			
		||||
           (u32(translate_params_size) & 0x3F);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
union Header {
 | 
			
		||||
    u32 raw;
 | 
			
		||||
    BitField<0, 6, u32> translate_params_size;
 | 
			
		||||
    BitField<6, 6, u32> normal_params;
 | 
			
		||||
    BitField<16, 16, u32> command_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline Header ParseHeader(u32 header) {
 | 
			
		||||
    return {header};
 | 
			
		||||
inline u32 MakeHeader(u16 command_id, unsigned int normal_params_size,
 | 
			
		||||
                      unsigned int translate_params_size) {
 | 
			
		||||
    Header header;
 | 
			
		||||
    header.command_id.Assign(command_id);
 | 
			
		||||
    header.normal_params_size.Assign(normal_params_size);
 | 
			
		||||
    header.translate_params_size.Assign(translate_params_size);
 | 
			
		||||
    return header.raw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr u32 MoveHandleDesc(u32 num_handles = 1) {
 | 
			
		||||
@ -83,7 +96,7 @@ constexpr u32 CallingPidDesc() {
 | 
			
		||||
    return CallingPid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr bool isHandleDescriptor(u32 descriptor) {
 | 
			
		||||
constexpr bool IsHandleDescriptor(u32 descriptor) {
 | 
			
		||||
    return (descriptor & 0xF) == 0x0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -91,18 +104,19 @@ constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) {
 | 
			
		||||
    return (handle_descriptor >> 26) + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) {
 | 
			
		||||
    return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
union StaticBufferDescInfo {
 | 
			
		||||
    u32 raw;
 | 
			
		||||
    BitField<0, 4, u32> descriptor_type;
 | 
			
		||||
    BitField<10, 4, u32> buffer_id;
 | 
			
		||||
    BitField<14, 18, u32> size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) {
 | 
			
		||||
    return {desc};
 | 
			
		||||
inline u32 StaticBufferDesc(u32 size, u8 buffer_id) {
 | 
			
		||||
    StaticBufferDescInfo info;
 | 
			
		||||
    info.descriptor_type.Assign(StaticBuffer);
 | 
			
		||||
    info.buffer_id.Assign(buffer_id);
 | 
			
		||||
    info.size.Assign(size);
 | 
			
		||||
    return info.raw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -122,29 +136,30 @@ inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) {
 | 
			
		||||
    return type | (size << 8) | ((buffer_id & 0xF) << 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum MappedBufferPermissions {
 | 
			
		||||
enum MappedBufferPermissions : u32 {
 | 
			
		||||
    R = 1,
 | 
			
		||||
    W = 2,
 | 
			
		||||
    RW = R | W,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
 | 
			
		||||
    return MappedBuffer | (size << 4) | (u32(perms) << 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
union MappedBufferDescInfo {
 | 
			
		||||
    u32 raw;
 | 
			
		||||
    BitField<4, 28, u32> size;
 | 
			
		||||
    BitField<0, 4, u32> flags;
 | 
			
		||||
    BitField<1, 2, MappedBufferPermissions> perms;
 | 
			
		||||
    BitField<4, 28, u32> size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) {
 | 
			
		||||
    return {desc};
 | 
			
		||||
inline u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
 | 
			
		||||
    MappedBufferDescInfo info;
 | 
			
		||||
    info.flags.Assign(MappedBuffer);
 | 
			
		||||
    info.perms.Assign(perms);
 | 
			
		||||
    info.size.Assign(size);
 | 
			
		||||
    return info.raw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline DescriptorType GetDescriptorType(u32 descriptor) {
 | 
			
		||||
    // Note: Those checks must be done in this order
 | 
			
		||||
    if (isHandleDescriptor(descriptor))
 | 
			
		||||
    if (IsHandleDescriptor(descriptor))
 | 
			
		||||
        return (DescriptorType)(descriptor & 0x30);
 | 
			
		||||
 | 
			
		||||
    // handle the fact that the following descriptors can have rights
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										275
									
								
								src/core/hle/ipc_helpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								src/core/hle/ipc_helpers.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,275 @@
 | 
			
		||||
// Copyright 2016 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "core/hle/ipc.h"
 | 
			
		||||
#include "core/hle/kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
namespace IPC {
 | 
			
		||||
 | 
			
		||||
class RequestHelperBase {
 | 
			
		||||
protected:
 | 
			
		||||
    u32* cmdbuf;
 | 
			
		||||
    ptrdiff_t index = 1;
 | 
			
		||||
    Header header;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    RequestHelperBase(u32* command_buffer, Header command_header)
 | 
			
		||||
        : cmdbuf(command_buffer), header(command_header) {}
 | 
			
		||||
 | 
			
		||||
    /// Returns the total size of the request in words
 | 
			
		||||
    size_t TotalSize() const {
 | 
			
		||||
        return 1 /* command header */ + header.normal_params_size + header.translate_params_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ValidateHeader() {
 | 
			
		||||
        DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)",
 | 
			
		||||
                         header.raw);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class RequestBuilder : public RequestHelperBase {
 | 
			
		||||
public:
 | 
			
		||||
    RequestBuilder(u32* command_buffer, Header command_header)
 | 
			
		||||
        : RequestHelperBase(command_buffer, command_header) {
 | 
			
		||||
        cmdbuf[0] = header.raw;
 | 
			
		||||
    }
 | 
			
		||||
    explicit RequestBuilder(u32* command_buffer, u32 command_header)
 | 
			
		||||
        : RequestBuilder(command_buffer, Header{command_header}) {}
 | 
			
		||||
    RequestBuilder(u32* command_buffer, u16 command_id, unsigned normal_params_size,
 | 
			
		||||
                   unsigned translate_params_size)
 | 
			
		||||
        : RequestBuilder(command_buffer,
 | 
			
		||||
                         MakeHeader(command_id, normal_params_size, translate_params_size)) {}
 | 
			
		||||
 | 
			
		||||
    // Validate on destruction, as there shouldn't be any case where we don't want it
 | 
			
		||||
    ~RequestBuilder() {
 | 
			
		||||
        ValidateHeader();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void Push(T value);
 | 
			
		||||
 | 
			
		||||
    void Push(u32 value) {
 | 
			
		||||
        cmdbuf[index++] = value;
 | 
			
		||||
    }
 | 
			
		||||
    template <typename First, typename... Other>
 | 
			
		||||
    void Push(const First& first_value, const Other&... other_values) {
 | 
			
		||||
        Push(first_value);
 | 
			
		||||
        Push(other_values...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Copies the content of the given trivially copyable class to the buffer as a normal
 | 
			
		||||
     * param
 | 
			
		||||
     * @note: The input class must be correctly packed/padded to fit hardware layout.
 | 
			
		||||
     */
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void PushRaw(const T& value) {
 | 
			
		||||
        static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable");
 | 
			
		||||
        std::memcpy(cmdbuf + index, &value, sizeof(T));
 | 
			
		||||
        index += (sizeof(T) + 3) / 4; // round up to word length
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO : ensure that translate params are added after all regular params
 | 
			
		||||
    template <typename... H>
 | 
			
		||||
    void PushCopyHandles(H... handles) {
 | 
			
		||||
        Push(CopyHandleDesc(sizeof...(H)));
 | 
			
		||||
        Push(static_cast<Kernel::Handle>(handles)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... H>
 | 
			
		||||
    void PushMoveHandles(H... handles) {
 | 
			
		||||
        Push(MoveHandleDesc(sizeof...(H)));
 | 
			
		||||
        Push(static_cast<Kernel::Handle>(handles)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PushCurrentPIDHandle() {
 | 
			
		||||
        Push(CallingPidDesc());
 | 
			
		||||
        Push(u32(0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) {
 | 
			
		||||
        Push(StaticBufferDesc(size, buffer_id));
 | 
			
		||||
        Push(buffer_vaddr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms) {
 | 
			
		||||
        Push(MappedBufferDesc(size, perms));
 | 
			
		||||
        Push(buffer_vaddr);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Push ///
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline void RequestBuilder::Push<u32>(u32 value) {
 | 
			
		||||
    Push(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline void RequestBuilder::Push<u64>(u64 value) {
 | 
			
		||||
    Push(static_cast<u32>(value));
 | 
			
		||||
    Push(static_cast<u32>(value >> 32));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline void RequestBuilder::Push<ResultCode>(ResultCode value) {
 | 
			
		||||
    Push(value.raw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class RequestParser : public RequestHelperBase {
 | 
			
		||||
public:
 | 
			
		||||
    RequestParser(u32* command_buffer, Header command_header)
 | 
			
		||||
        : RequestHelperBase(command_buffer, command_header) {}
 | 
			
		||||
    explicit RequestParser(u32* command_buffer, u32 command_header)
 | 
			
		||||
        : RequestParser(command_buffer, Header{command_header}) {}
 | 
			
		||||
    RequestParser(u32* command_buffer, u16 command_id, unsigned normal_params_size,
 | 
			
		||||
                  unsigned translate_params_size)
 | 
			
		||||
        : RequestParser(command_buffer,
 | 
			
		||||
                        MakeHeader(command_id, normal_params_size, translate_params_size)) {}
 | 
			
		||||
 | 
			
		||||
    RequestBuilder MakeBuilder(u32 normal_params_size, u32 translate_params_size,
 | 
			
		||||
                               bool validateHeader = true) {
 | 
			
		||||
        if (validateHeader)
 | 
			
		||||
            ValidateHeader();
 | 
			
		||||
        Header builderHeader{
 | 
			
		||||
            MakeHeader(header.command_id, normal_params_size, translate_params_size)};
 | 
			
		||||
        return {cmdbuf, builderHeader};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    T Pop();
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void Pop(T& value);
 | 
			
		||||
 | 
			
		||||
    template <typename First, typename... Other>
 | 
			
		||||
    void Pop(First& first_value, Other&... other_values);
 | 
			
		||||
 | 
			
		||||
    Kernel::Handle PopHandle();
 | 
			
		||||
 | 
			
		||||
    template <typename... H>
 | 
			
		||||
    void PopHandles(H&... handles);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Pops the static buffer vaddr
 | 
			
		||||
     * @return                  The virtual address of the buffer
 | 
			
		||||
     * @param[out] data_size    If non-null, the pointed value will be set to the size of the data
 | 
			
		||||
     * @param[out] useStaticBuffersToGetVaddr Indicates if we should read the vaddr from the static
 | 
			
		||||
     * buffers (which is the correct thing to do, but no service presently implement it) instead of
 | 
			
		||||
     * using the same value as the process who sent the request
 | 
			
		||||
     * given by the source process
 | 
			
		||||
     *
 | 
			
		||||
     * Static buffers must be set up before any IPC request using those is sent.
 | 
			
		||||
     * It is the duty of the process (usually services) to allocate and set up the receiving static
 | 
			
		||||
     * buffer information
 | 
			
		||||
     * Please note that the setup uses virtual addresses.
 | 
			
		||||
     */
 | 
			
		||||
    VAddr PopStaticBuffer(size_t* data_size = nullptr, bool useStaticBuffersToGetVaddr = false);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Pops the mapped buffer vaddr
 | 
			
		||||
     * @return                  The virtual address of the buffer
 | 
			
		||||
     * @param[out] data_size    If non-null, the pointed value will be set to the size of the data
 | 
			
		||||
     * given by the source process
 | 
			
		||||
     * @param[out] buffer_perms If non-null, the pointed value will be set to the permissions of the
 | 
			
		||||
     * buffer
 | 
			
		||||
     */
 | 
			
		||||
    VAddr PopMappedBuffer(size_t* data_size = nullptr,
 | 
			
		||||
                          MappedBufferPermissions* buffer_perms = nullptr);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Reads the next normal parameters as a struct, by copying it
 | 
			
		||||
     * @note: The output class must be correctly packed/padded to fit hardware layout.
 | 
			
		||||
     */
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void PopRaw(T& value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Pop ///
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline u32 RequestParser::Pop<u32>() {
 | 
			
		||||
    return cmdbuf[index++];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline u64 RequestParser::Pop<u64>() {
 | 
			
		||||
    const u64 lsw = Pop<u32>();
 | 
			
		||||
    const u64 msw = Pop<u32>();
 | 
			
		||||
    return msw << 32 | lsw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
inline ResultCode RequestParser::Pop<ResultCode>() {
 | 
			
		||||
    return ResultCode{Pop<u32>()};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void RequestParser::Pop(T& value) {
 | 
			
		||||
    value = Pop<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename First, typename... Other>
 | 
			
		||||
void RequestParser::Pop(First& first_value, Other&... other_values) {
 | 
			
		||||
    first_value = Pop<First>();
 | 
			
		||||
    Pop(other_values...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Kernel::Handle RequestParser::PopHandle() {
 | 
			
		||||
    const u32 handle_descriptor = Pop<u32>();
 | 
			
		||||
    DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor),
 | 
			
		||||
                     "Tried to pop handle(s) but the descriptor is not a handle descriptor");
 | 
			
		||||
    DEBUG_ASSERT_MSG(HandleNumberFromDesc(handle_descriptor) == 1,
 | 
			
		||||
                     "Descriptor indicates that there isn't exactly one handle");
 | 
			
		||||
    return Pop<Kernel::Handle>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename... H>
 | 
			
		||||
void RequestParser::PopHandles(H&... handles) {
 | 
			
		||||
    const u32 handle_descriptor = Pop<u32>();
 | 
			
		||||
    const int handles_number = sizeof...(H);
 | 
			
		||||
    DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor),
 | 
			
		||||
                     "Tried to pop handle(s) but the descriptor is not a handle descriptor");
 | 
			
		||||
    DEBUG_ASSERT_MSG(handles_number == HandleNumberFromDesc(handle_descriptor),
 | 
			
		||||
                     "Number of handles doesn't match the descriptor");
 | 
			
		||||
    Pop(static_cast<Kernel::Handle&>(handles)...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline VAddr RequestParser::PopStaticBuffer(size_t* data_size, bool useStaticBuffersToGetVaddr) {
 | 
			
		||||
    const u32 sbuffer_descriptor = Pop<u32>();
 | 
			
		||||
    StaticBufferDescInfo bufferInfo{sbuffer_descriptor};
 | 
			
		||||
    if (data_size != nullptr)
 | 
			
		||||
        *data_size = bufferInfo.size;
 | 
			
		||||
    if (!useStaticBuffersToGetVaddr)
 | 
			
		||||
        return Pop<VAddr>();
 | 
			
		||||
    else {
 | 
			
		||||
        ASSERT_MSG(0, "remove the assert if multiprocess/IPC translation are implemented.");
 | 
			
		||||
        // The buffer has already been copied to the static buffer by the kernel during
 | 
			
		||||
        // translation
 | 
			
		||||
        Pop<VAddr>(); // Pop the calling process buffer address
 | 
			
		||||
                      // and get the vaddr from the static buffers
 | 
			
		||||
        return cmdbuf[(0x100 >> 2) + bufferInfo.buffer_id * 2 + 1];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline VAddr RequestParser::PopMappedBuffer(size_t* data_size,
 | 
			
		||||
                                            MappedBufferPermissions* buffer_perms) {
 | 
			
		||||
    const u32 sbuffer_descriptor = Pop<u32>();
 | 
			
		||||
    MappedBufferDescInfo bufferInfo{sbuffer_descriptor};
 | 
			
		||||
    if (data_size != nullptr)
 | 
			
		||||
        *data_size = bufferInfo.size;
 | 
			
		||||
    if (buffer_perms != nullptr)
 | 
			
		||||
        *buffer_perms = bufferInfo.perms;
 | 
			
		||||
    return Pop<VAddr>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void RequestParser::PopRaw(T& value) {
 | 
			
		||||
    static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable");
 | 
			
		||||
    std::memcpy(&value, cmdbuf + index, sizeof(T));
 | 
			
		||||
    index += (sizeof(T) + 3) / 4; // round up to word length
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace IPC
 | 
			
		||||
@ -54,15 +54,17 @@ static void Initialize(Service::Interface* self) {
 | 
			
		||||
 *      3 : File handle
 | 
			
		||||
 */
 | 
			
		||||
static void OpenFile(Service::Interface* self) {
 | 
			
		||||
    u32* cmd_buff = Kernel::GetCommandBuffer();
 | 
			
		||||
    // The helper should be passed by argument to the function
 | 
			
		||||
    IPC::RequestParser rp(Kernel::GetCommandBuffer(), {0x080201C2});
 | 
			
		||||
    rp.Pop<u32>(); // Always 0 ?
 | 
			
		||||
 | 
			
		||||
    ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
 | 
			
		||||
    auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
 | 
			
		||||
    u32 filename_size = cmd_buff[5];
 | 
			
		||||
    ArchiveHandle archive_handle = rp.Pop<u64>();
 | 
			
		||||
    auto filename_type = static_cast<FileSys::LowPathType>(rp.Pop<u32>());
 | 
			
		||||
    u32 filename_size = rp.Pop<u32>();
 | 
			
		||||
    FileSys::Mode mode;
 | 
			
		||||
    mode.hex = cmd_buff[6];
 | 
			
		||||
    u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
 | 
			
		||||
    u32 filename_ptr = cmd_buff[9];
 | 
			
		||||
    mode.hex = rp.Pop<u32>();
 | 
			
		||||
    u32 attributes = rp.Pop<u32>(); // TODO(Link Mauve): do something with those attributes.
 | 
			
		||||
    VAddr filename_ptr = rp.PopStaticBuffer();
 | 
			
		||||
    FileSys::Path file_path(filename_type, filename_size, filename_ptr);
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex,
 | 
			
		||||
@ -70,16 +72,17 @@ static void OpenFile(Service::Interface* self) {
 | 
			
		||||
 | 
			
		||||
    ResultVal<std::shared_ptr<File>> file_res =
 | 
			
		||||
        OpenFileFromArchive(archive_handle, file_path, mode);
 | 
			
		||||
    cmd_buff[1] = file_res.Code().raw;
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
 | 
			
		||||
    rb.Push(file_res.Code());
 | 
			
		||||
    if (file_res.Succeeded()) {
 | 
			
		||||
        std::shared_ptr<File> file = *file_res;
 | 
			
		||||
        auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
 | 
			
		||||
        file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
 | 
			
		||||
        cmd_buff[3] = Kernel::g_handle_table
 | 
			
		||||
                          .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
 | 
			
		||||
                          .MoveFrom();
 | 
			
		||||
        rb.PushMoveHandles(Kernel::g_handle_table
 | 
			
		||||
                               .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
 | 
			
		||||
                               .MoveFrom());
 | 
			
		||||
    } else {
 | 
			
		||||
        cmd_buff[3] = 0;
 | 
			
		||||
        rb.PushMoveHandles(0);
 | 
			
		||||
        LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@
 | 
			
		||||
#include <boost/container/flat_map.hpp>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/ipc.h"
 | 
			
		||||
#include "core/hle/ipc_helpers.h"
 | 
			
		||||
#include "core/hle/kernel/client_port.h"
 | 
			
		||||
#include "core/hle/kernel/thread.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
 | 
			
		||||
@ -281,37 +281,39 @@ static void GetTransferEndEvent(Interface* self) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SetSendingY(Interface* self) {
 | 
			
		||||
    u32* cmd_buff = Kernel::GetCommandBuffer();
 | 
			
		||||
    // The helper should be passed by argument to the function
 | 
			
		||||
    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x00100102);
 | 
			
		||||
    conversion.src_Y.address = rp.Pop<u32>();
 | 
			
		||||
    conversion.src_Y.image_size = rp.Pop<u32>();
 | 
			
		||||
    conversion.src_Y.transfer_unit = rp.Pop<u32>();
 | 
			
		||||
    conversion.src_Y.gap = rp.Pop<u32>();
 | 
			
		||||
    Kernel::Handle src_process_handle = rp.PopHandle();
 | 
			
		||||
 | 
			
		||||
    conversion.src_Y.address = cmd_buff[1];
 | 
			
		||||
    conversion.src_Y.image_size = cmd_buff[2];
 | 
			
		||||
    conversion.src_Y.transfer_unit = cmd_buff[3];
 | 
			
		||||
    conversion.src_Y.gap = cmd_buff[4];
 | 
			
		||||
 | 
			
		||||
    cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
 | 
			
		||||
    cmd_buff[1] = RESULT_SUCCESS.raw;
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
 | 
			
		||||
                           "src_process_handle=0x%08X",
 | 
			
		||||
              conversion.src_Y.image_size, conversion.src_Y.transfer_unit, conversion.src_Y.gap,
 | 
			
		||||
              cmd_buff[6]);
 | 
			
		||||
              src_process_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SetSendingU(Interface* self) {
 | 
			
		||||
    u32* cmd_buff = Kernel::GetCommandBuffer();
 | 
			
		||||
    // The helper should be passed by argument to the function
 | 
			
		||||
    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x00110102);
 | 
			
		||||
    conversion.src_U.address = rp.Pop<u32>();
 | 
			
		||||
    conversion.src_U.image_size = rp.Pop<u32>();
 | 
			
		||||
    conversion.src_U.transfer_unit = rp.Pop<u32>();
 | 
			
		||||
    conversion.src_U.gap = rp.Pop<u32>();
 | 
			
		||||
    Kernel::Handle src_process_handle = rp.PopHandle();
 | 
			
		||||
 | 
			
		||||
    conversion.src_U.address = cmd_buff[1];
 | 
			
		||||
    conversion.src_U.image_size = cmd_buff[2];
 | 
			
		||||
    conversion.src_U.transfer_unit = cmd_buff[3];
 | 
			
		||||
    conversion.src_U.gap = cmd_buff[4];
 | 
			
		||||
 | 
			
		||||
    cmd_buff[0] = IPC::MakeHeader(0x11, 1, 0);
 | 
			
		||||
    cmd_buff[1] = RESULT_SUCCESS.raw;
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
 | 
			
		||||
                           "src_process_handle=0x%08X",
 | 
			
		||||
              conversion.src_U.image_size, conversion.src_U.transfer_unit, conversion.src_U.gap,
 | 
			
		||||
              cmd_buff[6]);
 | 
			
		||||
              src_process_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SetSendingV(Interface* self) {
 | 
			
		||||
@ -561,11 +563,10 @@ static void GetAlpha(Interface* self) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SetDitheringWeightParams(Interface* self) {
 | 
			
		||||
    u32* cmd_buff = Kernel::GetCommandBuffer();
 | 
			
		||||
    std::memcpy(&dithering_weight_params, &cmd_buff[1], sizeof(DitheringWeightParams));
 | 
			
		||||
 | 
			
		||||
    cmd_buff[0] = IPC::MakeHeader(0x24, 1, 0);
 | 
			
		||||
    cmd_buff[1] = RESULT_SUCCESS.raw;
 | 
			
		||||
    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x24, 8, 0); // 0x240200
 | 
			
		||||
    rp.PopRaw(dithering_weight_params);
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_Y2R, "called");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user