Improve IPC interface

This commit changes how IPC is interacted with in two ways:
* Simplify all buffers into just InputBuffer and OutputBuffer
* Use pushing/popping for data payload
This commit is contained in:
◱ PixelyIon 2019-11-24 00:18:22 +05:30 committed by ◱ PixelyIon
parent 745cb208a6
commit 38716989ae
26 changed files with 284 additions and 312 deletions

View File

@ -122,24 +122,21 @@ namespace skyline::gpu {
void GPU::Ioctl(u32 fd, u32 cmd, kernel::ipc::IpcRequest &request, kernel::ipc::IpcResponse &response) { void GPU::Ioctl(u32 fd, u32 cmd, kernel::ipc::IpcRequest &request, kernel::ipc::IpcResponse &response) {
state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd); state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd);
try { try {
if (!request.vecBufA.empty() && !request.vecBufB.empty()) { if(request.inputBuf.empty() || request.outputBuf.empty()) {
device::IoctlBuffers input(device::InputBuffer(request.vecBufA[0]), device::OutputBuffer(request.vecBufB[0])); if(request.inputBuf.empty()) {
fdMap.at(fd)->HandleIoctl(cmd, input); device::IoctlData data(request.outputBuf.at(0));
response.WriteValue<u32>(input.status); fdMap.at(fd)->HandleIoctl(cmd, data);
} else if (!request.vecBufX.empty() && !request.vecBufC.empty()) { response.Push<u32>(data.status);
device::IoctlBuffers input(device::InputBuffer(request.vecBufX[0]), device::OutputBuffer(request.vecBufC[0])); } else {
fdMap.at(fd)->HandleIoctl(cmd, input); device::IoctlData data(request.inputBuf.at(0));
response.WriteValue<u32>(input.status); fdMap.at(fd)->HandleIoctl(cmd, data);
} else if (!request.vecBufX.empty()) { response.Push<u32>(data.status);
device::IoctlBuffers input(device::InputBuffer(request.vecBufX[0])); }
fdMap.at(fd)->HandleIoctl(cmd, input); } else {
response.WriteValue<u32>(input.status); device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0));
} else if (!request.vecBufC.empty()) { fdMap.at(fd)->HandleIoctl(cmd, data);
device::IoctlBuffers input(device::OutputBuffer(request.vecBufC[0])); response.Push<u32>(data.status);
fdMap.at(fd)->HandleIoctl(cmd, input); }
response.WriteValue<u32>(input.status);
} else
throw exception("Unknown IOCTL buffer configuration");
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception("IOCTL was requested on an invalid file descriptor"); throw exception("IOCTL was requested on an invalid file descriptor");
} }

View File

@ -54,50 +54,6 @@ namespace skyline::gpu::device {
{"/dev/nvhost-ctrl-gpu", NvDeviceType::nvhost_ctrl_gpu} {"/dev/nvhost-ctrl-gpu", NvDeviceType::nvhost_ctrl_gpu}
}; };
/**
* @brief Describes a buffer by holding the address and size
*/
struct IoctlBuffer {
u64 address; //!< The address of the buffer
size_t size; //!< The size of the buffer
/**
* @param address The address of the buffer
* @param size The size of the buffer
*/
IoctlBuffer(u64 address, size_t size) : address(address), size(size) {}
};
/**
* @brief Wrapper around IoctlBuffer that loads in the address from a A Buffer Descriptor
*/
struct InputBuffer : public IoctlBuffer {
/**
* @param aBuf The A Buffer Descriptor that has contains the input data
*/
InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf) : IoctlBuffer(aBuf->Address(), aBuf->Size()) {}
/**
* @param aBuf The X Buffer Descriptor that has contains the input data
*/
InputBuffer(kernel::ipc::BufferDescriptorX *xBuf) : IoctlBuffer(xBuf->Address(), xBuf->size) {}
};
/**
* @brief Wrapper around IoctlBuffer that loads in the address from a B Buffer Descriptor
*/
struct OutputBuffer : public IoctlBuffer {
/**
* @param aBuf The B Buffer Descriptor that has to be outputted to
*/
OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf) : IoctlBuffer(bBuf->Address(), bBuf->Size()) {}
/**
* @param xBuf The C Buffer Descriptor that has to be outputted to
*/
OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf) : IoctlBuffer(cBuf->address, cBuf->size) {}
};
/** /**
* @brief This enumerates all the possible error codes returned by the Nvidia driver (https://switchbrew.org/wiki/NV_services#Errors) * @brief This enumerates all the possible error codes returned by the Nvidia driver (https://switchbrew.org/wiki/NV_services#Errors)
*/ */
@ -128,11 +84,11 @@ namespace skyline::gpu::device {
}; };
/** /**
* @brief This holds all the IoctlBuffer objects in a coherent container * @brief This holds all the input and output data for an IOCTL function
*/ */
struct IoctlBuffers { struct IoctlData {
std::vector<InputBuffer> input; //!< A vector of all input IOCTL buffers std::vector<kernel::ipc::InputBuffer> input; //!< A vector of all input IOCTL buffers
std::vector<OutputBuffer> output; //!< A vector of all output IOCTL buffers std::vector<kernel::ipc::OutputBuffer> output; //!< A vector of all output IOCTL buffers
NvStatus status{NvStatus::Success}; //!< The error code that is returned to the application NvStatus status{NvStatus::Success}; //!< The error code that is returned to the application
/** /**
@ -140,19 +96,19 @@ namespace skyline::gpu::device {
* @param input An input buffer * @param input An input buffer
* @param output An output buffer * @param output An output buffer
*/ */
IoctlBuffers(InputBuffer input, OutputBuffer output) : input({input}), output({output}) {} IoctlData(kernel::ipc::InputBuffer input, kernel::ipc::OutputBuffer output) : input({input}), output({output}) {}
/** /**
* @brief This constructor takes 1 input buffer, it's used for Ioctl sometimes * @brief This constructor takes 1 input buffer, it's used for Ioctl sometimes
* @param output An output buffer * @param output An output buffer
*/ */
IoctlBuffers(InputBuffer input) : input({input}) {} IoctlData(kernel::ipc::InputBuffer input) : input({input}) {}
/** /**
* @brief This constructor takes 1 output buffer, it's used for Ioctl sometimes * @brief This constructor takes 1 output buffer, it's used for Ioctl sometimes
* @param output An output buffer * @param output An output buffer
*/ */
IoctlBuffers(OutputBuffer output) : output({output}) {} IoctlData(kernel::ipc::OutputBuffer output) : output({output}) {}
/** /**
* @brief This constructor takes 2 input buffers and 1 output buffer, it's used for Ioctl1 * @brief This constructor takes 2 input buffers and 1 output buffer, it's used for Ioctl1
@ -160,7 +116,7 @@ namespace skyline::gpu::device {
* @param input2 The second input buffer * @param input2 The second input buffer
* @param output An output buffer * @param output An output buffer
*/ */
IoctlBuffers(InputBuffer input1, InputBuffer input2, OutputBuffer output) : input({input1, input2}), output({output}) {} IoctlData(kernel::ipc::InputBuffer input1, kernel::ipc::InputBuffer input2, kernel::ipc::OutputBuffer output) : input({input1, input2}), output({output}) {}
/** /**
* @brief This constructor takes 1 input buffer and 2 output buffers, it's used for Ioctl2 * @brief This constructor takes 1 input buffer and 2 output buffers, it's used for Ioctl2
@ -168,7 +124,7 @@ namespace skyline::gpu::device {
* @param output1 The first output buffer * @param output1 The first output buffer
* @param output2 The second output buffer * @param output2 The second output buffer
*/ */
IoctlBuffers(InputBuffer input, OutputBuffer output1, OutputBuffer output2) : input({input}), output({output1, output2}) {} IoctlData(kernel::ipc::InputBuffer input, kernel::ipc::OutputBuffer output1, kernel::ipc::OutputBuffer output2) : input({input}), output({output1, output2}) {}
}; };
/** /**
@ -177,7 +133,7 @@ namespace skyline::gpu::device {
class NvDevice { class NvDevice {
protected: protected:
const DeviceState &state; //!< The state of the device const DeviceState &state; //!< The state of the device
std::unordered_map<u32, std::function<void(IoctlBuffers &)>> vTable; //!< This holds the mapping from an Ioctl to the actual function std::unordered_map<u32, std::function<void(IoctlData &)>> vTable; //!< This holds the mapping from an Ioctl to the actual function
public: public:
u16 refCount{1}; //!< The amount of handles to the device u16 refCount{1}; //!< The amount of handles to the device
@ -188,7 +144,7 @@ namespace skyline::gpu::device {
* @param deviceType The type of the device * @param deviceType The type of the device
* @param vTable The functions in this device * @param vTable The functions in this device
*/ */
NvDevice(const DeviceState &state, NvDeviceType deviceType, std::unordered_map<u32, std::function<void(IoctlBuffers &)>> vTable) : state(state), deviceType(deviceType), vTable(vTable) {} NvDevice(const DeviceState &state, NvDeviceType deviceType, std::unordered_map<u32, std::function<void(IoctlData &)>> vTable) : state(state), deviceType(deviceType), vTable(vTable) {}
/** /**
* @brief This returns the name of the current service * @brief This returns the name of the current service
@ -208,8 +164,8 @@ namespace skyline::gpu::device {
* @param cmd The IOCTL command that was called * @param cmd The IOCTL command that was called
* @param input The input to the IOCTL call * @param input The input to the IOCTL call
*/ */
void HandleIoctl(u32 cmd, IoctlBuffers &input) { void HandleIoctl(u32 cmd, IoctlData &input) {
std::function<void(IoctlBuffers &)> function; std::function<void(IoctlData &)> function;
try { try {
function = vTable.at(cmd); function = vTable.at(cmd);
} catch (std::out_of_range &) { } catch (std::out_of_range &) {

View File

@ -12,15 +12,15 @@ namespace skyline::gpu::device {
{0x40084714, NFUNC(NvHostChannel::SetUserData)} {0x40084714, NFUNC(NvHostChannel::SetUserData)}
}) {} }) {}
void NvHostChannel::SetNvmapFd(skyline::gpu::device::IoctlBuffers &buffer) {} void NvHostChannel::SetNvmapFd(skyline::gpu::device::IoctlData &buffer) {}
void NvHostChannel::AllocObjCtx(skyline::gpu::device::IoctlBuffers &buffer) {} void NvHostChannel::AllocObjCtx(skyline::gpu::device::IoctlData &buffer) {}
void NvHostChannel::ZcullBind(IoctlBuffers &buffer) {} void NvHostChannel::ZcullBind(IoctlData &buffer) {}
void NvHostChannel::SetErrorNotifier(skyline::gpu::device::IoctlBuffers &buffer) {} void NvHostChannel::SetErrorNotifier(skyline::gpu::device::IoctlData &buffer) {}
void NvHostChannel::SetPriority(skyline::gpu::device::IoctlBuffers &buffer) { void NvHostChannel::SetPriority(skyline::gpu::device::IoctlData &buffer) {
auto priority = state.thisProcess->ReadMemory<NvChannelPriority>(buffer.input[0].address); auto priority = state.thisProcess->ReadMemory<NvChannelPriority>(buffer.input[0].address);
switch (priority) { switch (priority) {
case NvChannelPriority::Low: case NvChannelPriority::Low:
@ -35,8 +35,8 @@ namespace skyline::gpu::device {
} }
} }
void NvHostChannel::AllocGpfifoEx2(skyline::gpu::device::IoctlBuffers &buffer) {} void NvHostChannel::AllocGpfifoEx2(skyline::gpu::device::IoctlData &buffer) {}
void NvHostChannel::SetUserData(skyline::gpu::device::IoctlBuffers &buffer) {} void NvHostChannel::SetUserData(skyline::gpu::device::IoctlData &buffer) {}
} }

View File

@ -22,36 +22,36 @@ namespace skyline::gpu::device {
/** /**
* @brief This sets the nvmap file descriptor (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD) * @brief This sets the nvmap file descriptor (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD)
*/ */
void SetNvmapFd(IoctlBuffers &buffer); void SetNvmapFd(IoctlData &buffer);
/** /**
* @brief This allocates a graphic context object (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX) * @brief This allocates a graphic context object (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX)
*/ */
void AllocObjCtx(IoctlBuffers &buffer); void AllocObjCtx(IoctlData &buffer);
/** /**
* @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND) * @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND)
*/ */
void ZcullBind(IoctlBuffers &buffer); void ZcullBind(IoctlData &buffer);
/** /**
* @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER) * @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER)
*/ */
void SetErrorNotifier(IoctlBuffers &buffer); void SetErrorNotifier(IoctlData &buffer);
/** /**
* @brief This sets the priority of the channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY) * @brief This sets the priority of the channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY)
*/ */
void SetPriority(IoctlBuffers &buffer); void SetPriority(IoctlData &buffer);
/** /**
* @brief This allocates a GPFIFO entry (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2) * @brief This allocates a GPFIFO entry (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2)
*/ */
void AllocGpfifoEx2(IoctlBuffers &buffer); void AllocGpfifoEx2(IoctlData &buffer);
/** /**
* @brief This sets the user specific data (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA) * @brief This sets the user specific data (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA)
*/ */
void SetUserData(IoctlBuffers &buffer); void SetUserData(IoctlData &buffer);
}; };
} }

View File

@ -10,12 +10,12 @@ namespace skyline::gpu::device {
{0x80084714, NFUNC(NvHostCtrlGpu::GetActiveSlotMask)} {0x80084714, NFUNC(NvHostCtrlGpu::GetActiveSlotMask)}
}) {} }) {}
void NvHostCtrlGpu::ZCullGetCtxSize(IoctlBuffers &buffer) { void NvHostCtrlGpu::ZCullGetCtxSize(IoctlData &buffer) {
u32 size = 0x1; u32 size = 0x1;
state.thisProcess->WriteMemory(size, buffer.output[0].address); state.thisProcess->WriteMemory(size, buffer.output[0].address);
} }
void NvHostCtrlGpu::ZCullGetInfo(skyline::gpu::device::IoctlBuffers &buffer) { void NvHostCtrlGpu::ZCullGetInfo(skyline::gpu::device::IoctlData &buffer) {
struct { struct {
u32 widthAlignPixels{0x20}; u32 widthAlignPixels{0x20};
u32 heightAlignPixels{0x20}; u32 heightAlignPixels{0x20};
@ -31,7 +31,7 @@ namespace skyline::gpu::device {
state.thisProcess->WriteMemory(zCullInfo, buffer.output[0].address); state.thisProcess->WriteMemory(zCullInfo, buffer.output[0].address);
} }
void NvHostCtrlGpu::GetCharacteristics(IoctlBuffers &buffer) { void NvHostCtrlGpu::GetCharacteristics(IoctlData &buffer) {
struct GpuCharacteristics { struct GpuCharacteristics {
u32 arch; // 0x120 (NVGPU_GPU_ARCH_GM200) u32 arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
u32 impl; // 0xB (NVGPU_GPU_IMPL_GM20B) or 0xE (NVGPU_GPU_IMPL_GM20B_B) u32 impl; // 0xB (NVGPU_GPU_IMPL_GM20B) or 0xE (NVGPU_GPU_IMPL_GM20B_B)
@ -114,7 +114,7 @@ namespace skyline::gpu::device {
state.thisProcess->WriteMemory(data, buffer.output[0].address); state.thisProcess->WriteMemory(data, buffer.output[0].address);
} }
void NvHostCtrlGpu::GetTpcMasks(IoctlBuffers &buffer) { void NvHostCtrlGpu::GetTpcMasks(IoctlData &buffer) {
struct Data { struct Data {
u32 maskBufSize; // In u32 maskBufSize; // In
u32 reserved[3]; // In u32 reserved[3]; // In
@ -125,7 +125,7 @@ namespace skyline::gpu::device {
state.thisProcess->WriteMemory(data, buffer.output[0].address); state.thisProcess->WriteMemory(data, buffer.output[0].address);
} }
void NvHostCtrlGpu::GetActiveSlotMask(IoctlBuffers &buffer) { void NvHostCtrlGpu::GetActiveSlotMask(IoctlData &buffer) {
struct Data { struct Data {
u32 slot; // Out u32 slot; // Out
u32 mask; // Out u32 mask; // Out

View File

@ -13,26 +13,26 @@ namespace skyline::gpu::device {
/** /**
* @brief This returns a u32 GPU ZCULL Context Size (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE) * @brief This returns a u32 GPU ZCULL Context Size (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE)
*/ */
void ZCullGetCtxSize(IoctlBuffers &buffer); void ZCullGetCtxSize(IoctlData &buffer);
/** /**
* @brief This returns a the GPU ZCULL Information (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_INFO) * @brief This returns a the GPU ZCULL Information (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_INFO)
*/ */
void ZCullGetInfo(IoctlBuffers &buffer); void ZCullGetInfo(IoctlData &buffer);
/** /**
* @brief This returns a struct with certain GPU characteristics (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_CHARACTERISTICS) * @brief This returns a struct with certain GPU characteristics (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_CHARACTERISTICS)
*/ */
void GetCharacteristics(IoctlBuffers &buffer); void GetCharacteristics(IoctlData &buffer);
/** /**
* @brief This returns the TPC mask value for each GPC (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_TPC_MASKS) * @brief This returns the TPC mask value for each GPC (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_TPC_MASKS)
*/ */
void GetTpcMasks(IoctlBuffers &buffer); void GetTpcMasks(IoctlData &buffer);
/** /**
* @brief This returns the mask value for a ZBC slot (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZBC_GET_ACTIVE_SLOT_MASK) * @brief This returns the mask value for a ZBC slot (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZBC_GET_ACTIVE_SLOT_MASK)
*/ */
void GetActiveSlotMask(IoctlBuffers &buffer); void GetActiveSlotMask(IoctlData &buffer);
}; };
} }

View File

@ -13,7 +13,7 @@ namespace skyline::gpu::device {
{0xC008010E, NFUNC(NvMap::GetId)} {0xC008010E, NFUNC(NvMap::GetId)}
}) {} }) {}
void NvMap::Create(IoctlBuffers &buffer) { void NvMap::Create(IoctlData &buffer) {
struct Data { struct Data {
u32 size; // In u32 size; // In
u32 handle; // Out u32 handle; // Out
@ -24,7 +24,7 @@ namespace skyline::gpu::device {
state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status); state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status);
} }
void NvMap::FromId(skyline::gpu::device::IoctlBuffers &buffer) { void NvMap::FromId(skyline::gpu::device::IoctlData &buffer) {
struct Data { struct Data {
u32 id; // In u32 id; // In
u32 handle; // Out u32 handle; // Out
@ -44,7 +44,7 @@ namespace skyline::gpu::device {
state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status);
} }
void NvMap::Alloc(IoctlBuffers &buffer) { void NvMap::Alloc(IoctlData &buffer) {
struct Data { struct Data {
u32 handle; // In u32 handle; // In
u32 heapMask; // In u32 heapMask; // In
@ -64,7 +64,7 @@ namespace skyline::gpu::device {
state.logger->Debug("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status); state.logger->Debug("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status);
} }
void NvMap::Free(skyline::gpu::device::IoctlBuffers &buffer) { void NvMap::Free(skyline::gpu::device::IoctlData &buffer) {
struct Data { struct Data {
u32 handle; // In u32 handle; // In
u32 _pad0_; u32 _pad0_;
@ -85,7 +85,7 @@ namespace skyline::gpu::device {
state.thisProcess->WriteMemory(data, buffer.output[0].address); state.thisProcess->WriteMemory(data, buffer.output[0].address);
} }
void NvMap::Param(IoctlBuffers &buffer) { void NvMap::Param(IoctlData &buffer) {
enum class Parameter : u32 { Size = 1, Alignment = 2, Base = 3, HeapMask = 4, Kind = 5, Compr = 6 }; // https://android.googlesource.com/kernel/tegra/+/refs/heads/android-tegra-flounder-3.10-marshmallow/include/linux/nvmap.h#102 enum class Parameter : u32 { Size = 1, Alignment = 2, Base = 3, HeapMask = 4, Kind = 5, Compr = 6 }; // https://android.googlesource.com/kernel/tegra/+/refs/heads/android-tegra-flounder-3.10-marshmallow/include/linux/nvmap.h#102
struct Data { struct Data {
u32 handle; // In u32 handle; // In
@ -128,7 +128,7 @@ namespace skyline::gpu::device {
state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status); state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status);
} }
void NvMap::GetId(skyline::gpu::device::IoctlBuffers &buffer) { void NvMap::GetId(skyline::gpu::device::IoctlData &buffer) {
struct Data { struct Data {
u32 id; // Out u32 id; // Out
u32 handle; // In u32 handle; // In

View File

@ -41,31 +41,31 @@ namespace skyline::gpu::device {
/** /**
* @brief This creates an NvMapObject and returns an handle to it (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_CREATE) * @brief This creates an NvMapObject and returns an handle to it (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_CREATE)
*/ */
void Create(IoctlBuffers &buffer); void Create(IoctlData &buffer);
/** /**
* @brief This returns the handle of an NvMapObject from it's ID (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FROM_ID) * @brief This returns the handle of an NvMapObject from it's ID (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FROM_ID)
*/ */
void FromId(IoctlBuffers &buffer); void FromId(IoctlData &buffer);
/** /**
* @brief This allocates memory for an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_ALLOC) * @brief This allocates memory for an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_ALLOC)
*/ */
void Alloc(IoctlBuffers &buffer); void Alloc(IoctlData &buffer);
/** /**
* @brief This frees previously allocated memory (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FREE) * @brief This frees previously allocated memory (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FREE)
*/ */
void Free(IoctlBuffers &buffer); void Free(IoctlData &buffer);
/** /**
* @brief This returns a particular parameter from an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_PARAM) * @brief This returns a particular parameter from an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_PARAM)
*/ */
void Param(IoctlBuffers &buffer); void Param(IoctlData &buffer);
/** /**
* @brief This returns the ID of an NvMapObject from it's handle (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_GET_ID) * @brief This returns the ID of an NvMapObject from it's handle (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_GET_ID)
*/ */
void GetId(IoctlBuffers &buffer); void GetId(IoctlData &buffer);
}; };
} }

View File

@ -34,7 +34,7 @@ namespace skyline::gpu {
state.thisProcess->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size); state.thisProcess->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size);
} }
BufferQueue::WaitContext::WaitContext(std::shared_ptr<kernel::type::KThread> thread, DequeueIn input, u64 address, u64 size) : thread(std::move(thread)), input(input), address(address), size(size) {} BufferQueue::WaitContext::WaitContext(std::shared_ptr<kernel::type::KThread> thread, DequeueIn input, kernel::ipc::OutputBuffer& buffer) : thread(std::move(thread)), input(input), buffer(buffer) {}
BufferQueue::DequeueOut::DequeueOut(u32 slot) : slot(slot), _unk0_(0x1), _unk1_(0x24) {} BufferQueue::DequeueOut::DequeueOut(u32 slot) : slot(slot), _unk0_(0x1), _unk1_(0x24) {}
@ -49,7 +49,7 @@ namespace skyline::gpu {
state.logger->Debug("RequestBuffer: Slot: {}", slot, sizeof(GbpBuffer)); state.logger->Debug("RequestBuffer: Slot: {}", slot, sizeof(GbpBuffer));
} }
bool BufferQueue::DequeueBuffer(Parcel &in, Parcel &out, u64 address, u64 size) { bool BufferQueue::DequeueBuffer(Parcel &in, Parcel &out, kernel::ipc::OutputBuffer& buffer) {
auto *data = reinterpret_cast<DequeueIn *>(in.data.data() + constant::TokenLength); auto *data = reinterpret_cast<DequeueIn *>(in.data.data() + constant::TokenLength);
i64 slot{-1}; i64 slot{-1};
for (auto &buffer : queue) { for (auto &buffer : queue) {
@ -60,7 +60,7 @@ namespace skyline::gpu {
} }
if (slot == -1) { if (slot == -1) {
state.thisThread->Sleep(); state.thisThread->Sleep();
waitVec.emplace_back(state.thisThread, *data, address, size); waitVec.emplace_back(state.thisThread, *data, buffer);
state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamps: {}, No Free Buffers", data->width, data->height, data->format, data->usage, data->timestamps); state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamps: {}, No Free Buffers", data->width, data->height, data->format, data->usage, data->timestamps);
return true; return true;
} }
@ -130,12 +130,12 @@ namespace skyline::gpu {
else { else {
auto context = waitVec.begin(); auto context = waitVec.begin();
while (context != waitVec.end()) { while (context != waitVec.end()) {
if (slot->resolution.width == context->input.width && slot->resolution.height == context->input.height && slot->gbpBuffer.format == context->input.format && slot->gbpBuffer.usage == context->input.usage) { if (slot->resolution.width == context->input.width && slot->resolution.height == context->input.height && slot->gbpBuffer.usage == context->input.usage) {
context->thread->WakeUp(); context->thread->WakeUp();
gpu::Parcel out(state); gpu::Parcel out(state);
DequeueOut output(slotNo); DequeueOut output(slotNo);
out.WriteData(output); out.WriteData(output);
out.WriteParcel(context->address, context->size, context->thread->pid); out.WriteParcel(context->buffer, context->thread->pid);
slot->status = BufferStatus::Dequeued; slot->status = BufferStatus::Dequeued;
waitVec.erase(context); waitVec.erase(context);
break; break;

View File

@ -160,16 +160,14 @@ namespace skyline::gpu {
struct WaitContext { struct WaitContext {
std::shared_ptr<kernel::type::KThread> thread; //!< The thread that is waiting on a buffer std::shared_ptr<kernel::type::KThread> thread; //!< The thread that is waiting on a buffer
DequeueIn input; //!< The input of DequeueBuffer DequeueIn input; //!< The input of DequeueBuffer
u64 address; //!< The address of the parcel buffer kernel::ipc::OutputBuffer buffer; //!< The output buffer to write the parcel into
u64 size; //!< The size of the parcel buffer
/** /**
* @param thread The thread that is waiting on a buffer * @param thread The thread that is waiting on a buffer
* @param input The input of DequeueBuffer * @param input The input of DequeueBuffer
* @param address The address of the parcel buffer * @param buffer The output buffer to write the parcel into
* @param size The size of the parcel buffer
*/ */
WaitContext(std::shared_ptr<kernel::type::KThread> thread, DequeueIn input, u64 address, u64 size); WaitContext(std::shared_ptr<kernel::type::KThread> thread, DequeueIn input, kernel::ipc::OutputBuffer& buffer);
}; };
std::vector<WaitContext> waitVec; //!< A vector of shared pointers to threads waiting on a buffer std::vector<WaitContext> waitVec; //!< A vector of shared pointers to threads waiting on a buffer
@ -189,11 +187,10 @@ namespace skyline::gpu {
/** /**
* @brief This returns the slot of a free buffer * @brief This returns the slot of a free buffer
* @param address The address of the parcel buffer * @param buffer The output parcel buffer
* @param size The size of the parcel buffer
* @return If the process is waiting for a buffer or not * @return If the process is waiting for a buffer or not
*/ */
bool DequeueBuffer(Parcel &in, Parcel &out, u64 address, u64 size); bool DequeueBuffer(Parcel &in, Parcel &out, kernel::ipc::OutputBuffer& buffer);
/** /**
* @brief This queues a buffer to be displayed * @brief This queues a buffer to be displayed

View File

@ -3,9 +3,7 @@
#include <kernel/types/KProcess.h> #include <kernel/types/KProcess.h>
namespace skyline::gpu { namespace skyline::gpu {
Parcel::Parcel(kernel::ipc::BufferDescriptorABW *buffer, const DeviceState &state) : Parcel(buffer->Address(), buffer->Size(), state) {} Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state) : Parcel(buffer.address, buffer.size, state) {}
Parcel::Parcel(kernel::ipc::BufferDescriptorX *buffer, const DeviceState &state) : Parcel(buffer->Address(), buffer->size, state) {}
Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) { Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) {
state.thisProcess->ReadMemory(&header, address, sizeof(ParcelHeader)); state.thisProcess->ReadMemory(&header, address, sizeof(ParcelHeader));
@ -19,12 +17,8 @@ namespace skyline::gpu {
Parcel::Parcel(const DeviceState &state) : state(state) {} Parcel::Parcel(const DeviceState &state) : state(state) {}
u64 Parcel::WriteParcel(kernel::ipc::BufferDescriptorABW *buffer, pid_t process) { u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process) {
return WriteParcel(buffer->Address(), buffer->Size(), process); return WriteParcel(buffer.address, buffer.size, process);
}
u64 Parcel::WriteParcel(kernel::ipc::BufferDescriptorC *buffer, pid_t process) {
return WriteParcel(buffer->address, buffer->size, process);
} }
u64 Parcel::WriteParcel(u64 address, u64 maxSize, pid_t process) { u64 Parcel::WriteParcel(u64 address, u64 maxSize, pid_t process) {

View File

@ -31,14 +31,7 @@ namespace skyline::gpu {
* @param buffer The buffer that contains the parcel * @param buffer The buffer that contains the parcel
* @param state The state of the device * @param state The state of the device
*/ */
Parcel(kernel::ipc::BufferDescriptorABW *buffer, const DeviceState &state); Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state);
/**
* @brief This constructor fills in the Parcel object with data from a IPC buffer
* @param buffer The buffer that contains the parcel
* @param state The state of the device
*/
Parcel(kernel::ipc::BufferDescriptorX *buffer, const DeviceState &state);
/** /**
* @brief This constructor fills in the Parcel object with data from a Parcel on a remote process * @brief This constructor fills in the Parcel object with data from a Parcel on a remote process
@ -85,20 +78,12 @@ namespace skyline::gpu {
} }
/** /**
* @brief Writes the Parcel object into a particular B buffer on a process * @brief Writes the Parcel object into a particular output buffer on a process
* @param buffer The buffer to write into * @param buffer The buffer to write into
* @param process The process to write the Parcel to * @param process The process to write the Parcel to
* @return The total size of the message * @return The total size of the message
*/ */
u64 WriteParcel(kernel::ipc::BufferDescriptorABW *buffer, pid_t process = 0); u64 WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process = 0);
/**
* @brief Writes the Parcel object into a particular C buffer on a process
* @param buffer The buffer to write into
* @param process The process to write the Parcel to
* @return The total size of the message
*/
u64 WriteParcel(kernel::ipc::BufferDescriptorC *buffer, pid_t process = 0);
/** /**
* @brief Writes the Parcel object into the process's memory * @brief Writes the Parcel object into the process's memory

View File

@ -2,6 +2,16 @@
#include "types/KProcess.h" #include "types/KProcess.h"
namespace skyline::kernel::ipc { namespace skyline::kernel::ipc {
IpcBuffer::IpcBuffer(u64 address, size_t size, IpcBufferType type) : address(address), size(size), type(type) {}
InputBuffer::InputBuffer(kernel::ipc::BufferDescriptorX *xBuf) : IpcBuffer(xBuf->Address(), xBuf->size, IpcBufferType::X) {}
InputBuffer::InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf, IpcBufferType type) : IpcBuffer(aBuf->Address(), aBuf->Size(), type) {}
OutputBuffer::OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf, IpcBufferType type) : IpcBuffer(bBuf->Address(), bBuf->Size(), type) {}
OutputBuffer::OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf) : IpcBuffer(cBuf->address, cBuf->size, IpcBufferType::C) {}
IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state), tls() { IpcRequest::IpcRequest(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state), tls() {
u8 *currPtr = tls.data(); u8 *currPtr = tls.data();
state.thisProcess->ReadMemory(currPtr, state.thisThread->tls, constant::TlsIpcSize); state.thisProcess->ReadMemory(currPtr, state.thisThread->tls, constant::TlsIpcSize);
@ -25,7 +35,7 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Xno > index; index++) { for (uint index = 0; header->Xno > index; index++) {
auto bufX = reinterpret_cast<BufferDescriptorX *>(currPtr); auto bufX = reinterpret_cast<BufferDescriptorX *>(currPtr);
if (bufX->Address()) { if (bufX->Address()) {
vecBufX.push_back(bufX); inputBuf.emplace_back(bufX);
state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Address()), u16(bufX->size), u16(bufX->Counter())); state.logger->Debug("Buf X #{} AD: 0x{:X} SZ: 0x{:X} CTR: {}", index, u64(bufX->Address()), u16(bufX->size), u16(bufX->Counter()));
} }
currPtr += sizeof(BufferDescriptorX); currPtr += sizeof(BufferDescriptorX);
@ -34,7 +44,7 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Ano > index; index++) { for (uint index = 0; header->Ano > index; index++) {
auto bufA = reinterpret_cast<BufferDescriptorABW *>(currPtr); auto bufA = reinterpret_cast<BufferDescriptorABW *>(currPtr);
if (bufA->Address()) { if (bufA->Address()) {
vecBufA.push_back(bufA); inputBuf.emplace_back(bufA);
state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size())); state.logger->Debug("Buf A #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufA->Address()), u64(bufA->Size()));
} }
currPtr += sizeof(BufferDescriptorABW); currPtr += sizeof(BufferDescriptorABW);
@ -43,7 +53,7 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Bno > index; index++) { for (uint index = 0; header->Bno > index; index++) {
auto bufB = reinterpret_cast<BufferDescriptorABW *>(currPtr); auto bufB = reinterpret_cast<BufferDescriptorABW *>(currPtr);
if (bufB->Address()) { if (bufB->Address()) {
vecBufB.push_back(bufB); outputBuf.emplace_back(bufB);
state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size())); state.logger->Debug("Buf B #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufB->Address()), u64(bufB->Size()));
} }
currPtr += sizeof(BufferDescriptorABW); currPtr += sizeof(BufferDescriptorABW);
@ -52,7 +62,8 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Wno > index; index++) { for (uint index = 0; header->Wno > index; index++) {
auto bufW = reinterpret_cast<BufferDescriptorABW *>(currPtr); auto bufW = reinterpret_cast<BufferDescriptorABW *>(currPtr);
if (bufW->Address()) { if (bufW->Address()) {
vecBufW.push_back(bufW); inputBuf.emplace_back(bufW, IpcBufferType::W);
outputBuf.emplace_back(bufW, IpcBufferType::W);
state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Address()), u16(bufW->Size())); state.logger->Debug("Buf W #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufW->Address()), u16(bufW->Size()));
} }
currPtr += sizeof(BufferDescriptorABW); currPtr += sizeof(BufferDescriptorABW);
@ -85,6 +96,8 @@ namespace skyline::kernel::ipc {
currPtr += cmdArgSz; currPtr += cmdArgSz;
} }
payloadOffset = cmdArg;
if (payload->magic != constant::SfciMagic && header->type != CommandType::Control) if (payload->magic != constant::SfciMagic && header->type != CommandType::Control)
state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic)); state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));
@ -92,13 +105,15 @@ namespace skyline::kernel::ipc {
if (header->cFlag == BufferCFlag::SingleDescriptor) { if (header->cFlag == BufferCFlag::SingleDescriptor) {
auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr); auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr);
vecBufC.push_back(bufC); if (bufC->address) {
outputBuf.emplace_back(bufC);
state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size)); state.logger->Debug("Buf C: AD: 0x{:X} SZ: 0x{:X}", u64(bufC->address), u16(bufC->size));
}
} else if (header->cFlag > BufferCFlag::SingleDescriptor) { } else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr); auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr);
if (bufC->address) { if (bufC->address) {
vecBufC.push_back(bufC); outputBuf.emplace_back(bufC);
state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size)); state.logger->Debug("Buf C #{} AD: 0x{:X} SZ: 0x{:X}", index, u64(bufC->address), u16(bufC->size));
} }
currPtr += sizeof(BufferDescriptorC); currPtr += sizeof(BufferDescriptorC);
@ -106,7 +121,7 @@ namespace skyline::kernel::ipc {
} }
if (header->type == CommandType::Request) { if (header->type == CommandType::Request) {
state.logger->Debug("Header: X No: {}, A No: {}, B No: {}, W No: {}, C No: {}, Raw Size: {}", u8(header->Xno), u8(header->Ano), u8(header->Bno), u8(header->Wno), u8(vecBufC.size()), u64(cmdArgSz)); state.logger->Debug("Header: Input No: {}, Output No: {}, Raw Size: {}", inputBuf.size(), outputBuf.size(), u64(cmdArgSz));
if (header->handleDesc) if (header->handleDesc)
state.logger->Debug("Handle Descriptor: Send PID: {}, Copy Count: {}, Move Count: {}", bool(handleDesc->sendPid), u32(handleDesc->copyCount), u32(handleDesc->moveCount)); state.logger->Debug("Handle Descriptor: Send PID: {}, Copy Count: {}, Move Count: {}", bool(handleDesc->sendPid), u32(handleDesc->copyCount), u32(handleDesc->moveCount));
if (isDomain) if (isDomain)
@ -117,7 +132,7 @@ namespace skyline::kernel::ipc {
IpcResponse::IpcResponse(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {} IpcResponse::IpcResponse(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {}
void IpcResponse::WriteTls() { void IpcResponse::WriteResponse() {
std::array<u8, constant::TlsIpcSize> tls{}; std::array<u8, constant::TlsIpcSize> tls{};
u8 *currPtr = tls.data(); u8 *currPtr = tls.data();
auto header = reinterpret_cast<CommandHeader *>(currPtr); auto header = reinterpret_cast<CommandHeader *>(currPtr);

View File

@ -168,12 +168,70 @@ namespace skyline::kernel::ipc {
}; };
static_assert(sizeof(BufferDescriptorC) == 8); static_assert(sizeof(BufferDescriptorC) == 8);
/**
* @brief This enumerates the types of IPC buffers
*/
enum class IpcBufferType {
X, //!< This is a type-X buffer
A, //!< This is a type-A buffer
B, //!< This is a type-B buffer
W, //!< This is a type-W buffer
C //!< This is a type-C buffer
};
/**
* @brief Describes a buffer by holding the address and size
*/
struct IpcBuffer {
u64 address; //!< The address of the buffer
size_t size; //!< The size of the buffer
IpcBufferType type; //!< The type of the buffer
/**
* @param address The address of the buffer
* @param size The size of the buffer
* @param type The type of the buffer
*/
IpcBuffer(u64 address, size_t size, IpcBufferType type);
};
/**
* @brief This holds an input IPC buffer
*/
struct InputBuffer : public IpcBuffer {
/**
* @param aBuf The X Buffer Descriptor that has contains the input data
*/
InputBuffer(kernel::ipc::BufferDescriptorX *xBuf);
/**
* @param aBuf The A or W Buffer Descriptor that has contains the input data
*/
InputBuffer(kernel::ipc::BufferDescriptorABW *aBuf, IpcBufferType type = IpcBufferType::A);
};
/**
* @brief This holds an output IPC buffer
*/
struct OutputBuffer : public IpcBuffer {
/**
* @param bBuf The B or W Buffer Descriptor that has to be outputted to
*/
OutputBuffer(kernel::ipc::BufferDescriptorABW *bBuf, IpcBufferType type = IpcBufferType::B);
/**
* @param cBuf The C Buffer Descriptor that has to be outputted to
*/
OutputBuffer(kernel::ipc::BufferDescriptorC *cBuf);
};
/** /**
* @brief This class encapsulates an IPC Request (https://switchbrew.org/wiki/IPC_Marshalling) * @brief This class encapsulates an IPC Request (https://switchbrew.org/wiki/IPC_Marshalling)
*/ */
class IpcRequest { class IpcRequest {
private: private:
const DeviceState &state; //!< The state of the device const DeviceState &state; //!< The state of the device
u8 *payloadOffset; //!< This is the offset of the data read from the payload
public: public:
std::array<u8, constant::TlsIpcSize> tls; //!< A static-sized array where TLS data is actually copied to std::array<u8, constant::TlsIpcSize> tls; //!< A static-sized array where TLS data is actually copied to
@ -187,17 +245,34 @@ namespace skyline::kernel::ipc {
std::vector<handle_t> copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles) std::vector<handle_t> copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles)
std::vector<handle_t> moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied std::vector<handle_t> moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied
std::vector<handle_t> domainObjects; //!< A vector of all input domain objects std::vector<handle_t> domainObjects; //!< A vector of all input domain objects
std::vector<BufferDescriptorX *> vecBufX; //!< This is a vector of pointers to X Buffer Descriptors std::vector<InputBuffer> inputBuf; //!< This is a vector of input buffers
std::vector<BufferDescriptorABW *> vecBufA; //!< This is a vector of pointers to A Buffer Descriptors std::vector<OutputBuffer> outputBuf; //!< This is a vector of output buffers
std::vector<BufferDescriptorABW *> vecBufB; //!< This is a vector of pointers to B Buffer Descriptors
std::vector<BufferDescriptorABW *> vecBufW; //!< This is a vector of pointers to W Buffer Descriptors
std::vector<BufferDescriptorC *> vecBufC; //!< This is a vector of pointers to C Buffer Descriptors
/** /**
* @param isDomain If the following request is a domain request * @param isDomain If the following request is a domain request
* @param state The state of the device * @param state The state of the device
*/ */
IpcRequest(bool isDomain, const DeviceState &state); IpcRequest(bool isDomain, const DeviceState &state);
/**
* @brief This returns a reference to an item from the top of the payload
* @tparam ValueType The type of the object to read
*/
template<typename ValueType>
inline ValueType& Pop() {
ValueType& value = *reinterpret_cast<ValueType*>(payloadOffset);
payloadOffset += sizeof(ValueType);
return value;
}
/**
* @brief This skips an object to pop off the top
* @tparam ValueType The type of the object to skip
*/
template<typename ValueType>
inline void Skip() {
payloadOffset += sizeof(ValueType);
}
}; };
/** /**
@ -225,10 +300,10 @@ namespace skyline::kernel::ipc {
/** /**
* @brief Writes an object to the payload * @brief Writes an object to the payload
* @tparam ValueType The type of the object to write * @tparam ValueType The type of the object to write
* @param value The object to be written * @param value A reference to the object to be written
*/ */
template<typename ValueType> template<typename ValueType>
void WriteValue(const ValueType &value) { inline void Push(const ValueType &value) {
argVec.reserve(argVec.size() + sizeof(ValueType)); argVec.reserve(argVec.size() + sizeof(ValueType));
auto item = reinterpret_cast<const u8 *>(&value); auto item = reinterpret_cast<const u8 *>(&value);
for (uint index = 0; sizeof(ValueType) > index; index++) { for (uint index = 0; sizeof(ValueType) > index; index++) {
@ -240,6 +315,6 @@ namespace skyline::kernel::ipc {
/** /**
* @brief Writes this IpcResponse object's contents into TLS * @brief Writes this IpcResponse object's contents into TLS
*/ */
void WriteTls(); void WriteResponse();
}; };
} }

View File

@ -460,6 +460,8 @@ namespace skyline::kernel::svc {
void OutputDebugString(DeviceState &state) { void OutputDebugString(DeviceState &state) {
std::string debug(state.nce->GetRegister(Xreg::X1), '\0'); std::string debug(state.nce->GetRegister(Xreg::X1), '\0');
state.os->thisProcess->ReadMemory(debug.data(), state.nce->GetRegister(Xreg::X0), state.nce->GetRegister(Xreg::X1)); state.os->thisProcess->ReadMemory(debug.data(), state.nce->GetRegister(Xreg::X0), state.nce->GetRegister(Xreg::X1));
if(debug.back() == '\n')
debug.pop_back();
state.logger->Info("Debug Output: {}", debug); state.logger->Info("Debug Output: {}", debug);
state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Wreg::W0, constant::status::Success);
} }

View File

@ -2,9 +2,6 @@
#include <nce.h> #include <nce.h>
#include <os.h> #include <os.h>
constexpr const char *ASHMEM_NAME_DEF = "dev/ashmem";
constexpr int ASHMEM_SET_SIZE = 0x40087703;
namespace skyline::kernel::type { namespace skyline::kernel::type {
u64 MapTransferFunc(u64 address, size_t size, u64 perms) { u64 MapTransferFunc(u64 address, size_t size, u64 perms) {
return reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, static_cast<int>(perms), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0)); // NOLINT(hicpp-signed-bitwise) return reinterpret_cast<u64>(mmap(reinterpret_cast<void *>(address), size, static_cast<int>(perms), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0)); // NOLINT(hicpp-signed-bitwise)

View File

@ -30,20 +30,20 @@ namespace skyline::service::am {
response.errorCode = constant::status::NoMessages; response.errorCode = constant::status::NoMessages;
return; return;
} }
response.WriteValue<u32>(static_cast<u32>(messageQueue.front())); response.Push<u32>(static_cast<u32>(messageQueue.front()));
messageQueue.pop(); messageQueue.pop();
} }
void ICommonStateGetter::GetCurrentFocusState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void ICommonStateGetter::GetCurrentFocusState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u8>(static_cast<u8>(focusState)); response.Push<u8>(static_cast<u8>(focusState));
} }
void ICommonStateGetter::GetOperationMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void ICommonStateGetter::GetOperationMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u8>(static_cast<u8>(operationMode)); response.Push<u8>(static_cast<u8>(operationMode));
} }
void ICommonStateGetter::GetPerformanceMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void ICommonStateGetter::GetPerformanceMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u32>(static_cast<u32>(operationMode)); response.Push<u32>(static_cast<u32>(operationMode));
} }
void ICommonStateGetter::GetDefaultDisplayResolution(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response) { void ICommonStateGetter::GetDefaultDisplayResolution(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response) {
@ -77,7 +77,7 @@ namespace skyline::service::am {
if (state.gpu->layerStatus == gpu::LayerStatus::Initialized) if (state.gpu->layerStatus == gpu::LayerStatus::Initialized)
throw exception("The application is creating more than one layer"); throw exception("The application is creating more than one layer");
state.gpu->layerStatus = gpu::LayerStatus::Initialized; state.gpu->layerStatus = gpu::LayerStatus::Initialized;
response.WriteValue<u64>(0); response.Push<u64>(0);
} }
IWindowController::IWindowController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IWindowController, { IWindowController::IWindowController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IWindowController, {
@ -86,7 +86,7 @@ namespace skyline::service::am {
}) {} }) {}
void IWindowController::GetAppletResourceUserId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IWindowController::GetAppletResourceUserId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue(static_cast<u64>(state.thisProcess->mainThread)); response.Push(static_cast<u64>(state.thisProcess->mainThread));
} }
void IWindowController::AcquireForegroundRights(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} void IWindowController::AcquireForegroundRights(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}
@ -105,7 +105,7 @@ namespace skyline::service::am {
}) {} }) {}
void IApplicationFunctions::NotifyRunning(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IApplicationFunctions::NotifyRunning(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u8>(1); response.Push<u8>(1);
} }
IDebugFunctions::IDebugFunctions(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IDebugFunctions, { IDebugFunctions::IDebugFunctions(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IDebugFunctions, {

View File

@ -15,16 +15,14 @@ namespace skyline::service::apm {
}) {} }) {}
void ISession::SetPerformanceConfiguration(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void ISession::SetPerformanceConfiguration(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto mode = request.Pop<u32>();
u32 mode; auto config = request.Pop<u32>();
u32 config; performanceConfig[mode] = config;
} *performance = reinterpret_cast<InputStruct *>(request.cmdArg); state.logger->Info("SetPerformanceConfiguration called with 0x{:X} ({})", config, mode ? "Docked" : "Handheld");
performanceConfig[performance->mode] = performance->config;
state.logger->Info("SetPerformanceConfiguration called with 0x{:X} ({})", performance->config, performance->mode ? "Docked" : "Handheld");
} }
void ISession::GetPerformanceConfiguration(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void ISession::GetPerformanceConfiguration(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u32 performanceMode = *reinterpret_cast<u32 *>(request.cmdArg); u32 performanceMode = request.Pop<u32>();
response.WriteValue<u32>(performanceConfig[performanceMode]); response.Push<u32>(performanceConfig[performanceMode]);
} }
} }

View File

@ -30,20 +30,16 @@ namespace skyline::service::hid {
} }
void hid::SetSupportedNpadStyleSet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void hid::SetSupportedNpadStyleSet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto styleSet = request.Pop<StyleSet>();
u32 styleSet; state.logger->Debug("Controller Support:\nPro-Controller: {}\nJoy-Con: Handheld: {}, Dual: {}, L: {}, R: {}\nGameCube: {}\nPokeBall: {}\nNES: {}, NES Handheld: {}, SNES: {}", static_cast<bool>(styleSet.proController), static_cast<bool>(styleSet.joyconHandheld), static_cast<bool>(styleSet.joyconDual), static_cast<bool>(styleSet.joyconLeft), static_cast<bool>
u64 appletUserId; (styleSet.joyconRight), static_cast<bool>(styleSet.gamecube), static_cast<bool>(styleSet.pokeball), static_cast<bool>(styleSet.nes), static_cast<bool>(styleSet.nesHandheld), static_cast<bool>(styleSet.snes));
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
styleSet = *reinterpret_cast<StyleSet *>(&input->styleSet);
state.logger->Debug("Controller Support:\nPro-Controller: {}\nJoy-Con: Handheld: {}, Dual: {}, L: {}, R: {}\nGameCube: {}\nPokeBall: {}\nNES: {}, NES Handheld: {}, SNES: {}", static_cast<bool>(styleSet->proController), static_cast<bool>(styleSet->joyconHandheld), static_cast<bool>(styleSet->joyconDual), static_cast<bool>(styleSet->joyconLeft), static_cast<bool>
(styleSet->joyconRight), static_cast<bool>(styleSet->gamecube), static_cast<bool>(styleSet->pokeball), static_cast<bool>(styleSet->nes), static_cast<bool>(styleSet->nesHandheld), static_cast<bool>(styleSet->snes));
} }
void hid::SetSupportedNpadIdType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void hid::SetSupportedNpadIdType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
const auto &buffer = request.vecBufX[0]; const auto &buffer = request.inputBuf.at(0);
uint numId = buffer->size / sizeof(NpadId); size_t numId = buffer.size / sizeof(NpadId);
u64 address = buffer->Address(); u64 address = buffer.address;
for (uint i = 0; i < numId; i++) { for (size_t i = 0; i < numId; i++) {
auto id = state.thisProcess->ReadMemory<NpadId>(address); auto id = state.thisProcess->ReadMemory<NpadId>(address);
deviceMap[id] = JoyConDevice(id); deviceMap[id] = JoyConDevice(id);
address += sizeof(NpadId); address += sizeof(NpadId);
@ -53,36 +49,21 @@ namespace skyline::service::hid {
void hid::ActivateNpad(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {} void hid::ActivateNpad(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}
void hid::SetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void hid::SetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { deviceMap[request.Pop<NpadId>()].assignment = JoyConAssignment::Single;
NpadId controllerId;
u64 appletUserId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
deviceMap[input->controllerId].assignment = JoyConAssignment::Single;
} }
void hid::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void hid::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { orientation = request.Pop<JoyConOrientation>();
u64 appletUserId;
JoyConOrientation orientation;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
orientation = input->orientation;
} }
void hid::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void hid::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto controllerId = request.Pop<NpadId>();
NpadId controllerId; auto appletUserId = request.Pop<u64>();
u64 appletUserId; deviceMap[controllerId].assignment = JoyConAssignment::Single;
JoyConSide joyDeviceType; deviceMap[controllerId].side = request.Pop<JoyConSide>();
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
deviceMap[input->controllerId].assignment = JoyConAssignment::Single;
deviceMap[input->controllerId].side = input->joyDeviceType;
} }
void hid::SetNpadJoyAssignmentModeDual(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void hid::SetNpadJoyAssignmentModeDual(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { deviceMap[request.Pop<NpadId>()].assignment = JoyConAssignment::Dual;
NpadId controllerType;
u64 appletUserId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
deviceMap[input->controllerType].assignment = JoyConAssignment::Dual;
} }
} }

View File

@ -12,43 +12,39 @@ namespace skyline::service::nvdrv {
}) {} }) {}
void nvdrv::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void nvdrv::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto aBuf = request.vecBufA[0]; auto buffer = request.inputBuf.at(0);
std::string path(aBuf->Size(), '\0'); std::string path(buffer.size, '\0');
state.thisProcess->ReadMemory(path.data(), aBuf->Address(), aBuf->Size()); state.thisProcess->ReadMemory(path.data(), buffer.address, buffer.size);
response.WriteValue<u32>(state.gpu->OpenDevice(path)); response.Push<u32>(state.gpu->OpenDevice(path));
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
void nvdrv::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void nvdrv::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto fd = request.Pop<u32>();
u32 fd; auto cmd = request.Pop<u32>();
u32 cmd; state.gpu->Ioctl(fd, cmd, request, response);
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.gpu->Ioctl(input->fd, input->cmd, request, response);
} }
void nvdrv::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void nvdrv::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u32 fd = *reinterpret_cast<u32 *>(request.cmdArg); u32 fd = *reinterpret_cast<u32 *>(request.cmdArg);
state.gpu->CloseDevice(fd); state.gpu->CloseDevice(fd);
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
void nvdrv::Initialize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void nvdrv::Initialize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
void nvdrv::QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void nvdrv::QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto fd = request.Pop<u32>();
u32 fd; auto eventId = request.Pop<u32>();
u32 eventId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
auto event = std::make_shared<type::KEvent>(state); auto event = std::make_shared<type::KEvent>(state);
auto handle = state.thisProcess->InsertItem<type::KEvent>(event); auto handle = state.thisProcess->InsertItem<type::KEvent>(event);
state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", input->fd, input->eventId, handle); state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", fd, eventId, handle);
response.copyHandles.push_back(handle); response.copyHandles.push_back(handle);
} }
void nvdrv::SetAruidByPID(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void nvdrv::SetAruidByPID(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
} }

View File

@ -11,36 +11,25 @@ namespace skyline::service::nvnflinger {
}) {} }) {}
void dispdrv::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void dispdrv::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto layerId = request.Pop<u32>();
u32 layerId; auto code = request.Pop<TransactionCode>();
TransactionCode code; gpu::Parcel in(request.inputBuf.at(0), state);
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
std::shared_ptr<gpu::Parcel> in{};
if (request.vecBufA.empty())
in = std::make_shared<gpu::Parcel>(request.vecBufX[0], state);
else
in = std::make_shared<gpu::Parcel>(request.vecBufA[0], state);
gpu::Parcel out(state); gpu::Parcel out(state);
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", input->layerId, input->code); state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code);
switch (input->code) { switch (code) {
case TransactionCode::RequestBuffer: case TransactionCode::RequestBuffer:
state.gpu->bufferQueue.RequestBuffer(*in, out); state.gpu->bufferQueue.RequestBuffer(in, out);
break; break;
case TransactionCode::DequeueBuffer: { case TransactionCode::DequeueBuffer: {
if (request.vecBufA.empty()) { if (state.gpu->bufferQueue.DequeueBuffer(in, out, request.outputBuf.at(0)))
if (state.gpu->bufferQueue.DequeueBuffer(*in, out, request.vecBufC[0]->address, request.vecBufC[0]->size))
return; return;
} else {
if (state.gpu->bufferQueue.DequeueBuffer(*in, out, request.vecBufB[0]->Address(), request.vecBufB[0]->Size()))
return;
}
break; break;
} }
case TransactionCode::QueueBuffer: case TransactionCode::QueueBuffer:
state.gpu->bufferQueue.QueueBuffer(*in, out); state.gpu->bufferQueue.QueueBuffer(in, out);
break; break;
case TransactionCode::CancelBuffer: case TransactionCode::CancelBuffer:
state.gpu->bufferQueue.CancelBuffer(*in); state.gpu->bufferQueue.CancelBuffer(in);
break; break;
case TransactionCode::Query: case TransactionCode::Query:
out.WriteData<u64>(0); out.WriteData<u64>(0);
@ -59,30 +48,25 @@ namespace skyline::service::nvnflinger {
case TransactionCode::Disconnect: case TransactionCode::Disconnect:
break; break;
case TransactionCode::SetPreallocatedBuffer: case TransactionCode::SetPreallocatedBuffer:
state.gpu->bufferQueue.SetPreallocatedBuffer(*in); state.gpu->bufferQueue.SetPreallocatedBuffer(in);
break; break;
default: default:
throw exception("An unimplemented transaction was called: {}", static_cast<u32>(input->code)); throw exception("An unimplemented transaction was called: {}", static_cast<u32>(code));
} }
if (request.vecBufA.empty()) out.WriteParcel(request.outputBuf.at(0));
out.WriteParcel(request.vecBufC[0]); }
else
out.WriteParcel(request.vecBufB[0]); void dispdrv::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
request.Skip<u32>();
auto addVal = request.Pop<i32>();
auto type = request.Pop<i32>();
state.logger->Debug("Reference Change: {} {} reference", addVal, type ? "strong" : "weak");
} }
void dispdrv::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void dispdrv::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
handle_t handle = state.thisProcess->InsertItem(state.gpu->bufferEvent); handle_t handle = state.thisProcess->InsertItem(state.gpu->bufferEvent);
state.logger->Debug("BufferEvent Handle: 0x{:X}", handle); state.logger->Debug("BufferEvent Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle); response.copyHandles.push_back(handle);
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
}
void dispdrv::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
u32 layerId;
i32 addVal;
i32 type;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.logger->Debug("Reference Change: {} {} reference", input->addVal, input->type ? "strong" : "weak");
} }
} }

View File

@ -50,14 +50,14 @@ namespace skyline::service::nvnflinger {
*/ */
void TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); void TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief This adjusts the reference counts to the underlying binder, it is stubbed as we aren't using the real symbols (https://switchbrew.org/wiki/Nvnflinger_services#GetNativeHandle)
*/
void GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/** /**
* @brief This adjusts the reference counts to the underlying binder, it is stubbed as we aren't using the real symbols (https://switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount) * @brief This adjusts the reference counts to the underlying binder, it is stubbed as we aren't using the real symbols (https://switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount)
*/ */
void AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); void AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief This adjusts the reference counts to the underlying binder, it is stubbed as we aren't using the real symbols (https://switchbrew.org/wiki/Nvnflinger_services#GetNativeHandle)
*/
void GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
}; };
} }

View File

@ -199,7 +199,7 @@ namespace skyline::service {
} else } else
session->serviceObject->HandleRequest(*session, request, response); session->serviceObject->HandleRequest(*session, request, response);
if (!response.nWrite) if (!response.nWrite)
response.WriteTls(); response.WriteResponse();
break; break;
case ipc::CommandType::Control: case ipc::CommandType::Control:
@ -207,19 +207,19 @@ namespace skyline::service {
state.logger->Debug("Control IPC Message: 0x{:X}", request.payload->value); state.logger->Debug("Control IPC Message: 0x{:X}", request.payload->value);
switch (static_cast<ipc::ControlCommand>(request.payload->value)) { switch (static_cast<ipc::ControlCommand>(request.payload->value)) {
case ipc::ControlCommand::ConvertCurrentObjectToDomain: case ipc::ControlCommand::ConvertCurrentObjectToDomain:
response.WriteValue(session->ConvertDomain()); response.Push(session->ConvertDomain());
break; break;
case ipc::ControlCommand::CloneCurrentObject: case ipc::ControlCommand::CloneCurrentObject:
case ipc::ControlCommand::CloneCurrentObjectEx: case ipc::ControlCommand::CloneCurrentObjectEx:
response.WriteValue(state.thisProcess->InsertItem(session)); response.Push(state.thisProcess->InsertItem(session));
break; break;
case ipc::ControlCommand::QueryPointerBufferSize: case ipc::ControlCommand::QueryPointerBufferSize:
response.WriteValue<u32>(0x1000); response.Push<u32>(0x1000);
break; break;
default: default:
throw exception("Unknown Control Command: {}", request.payload->value); throw exception("Unknown Control Command: {}", request.payload->value);
} }
response.WriteTls(); response.WriteResponse();
break; break;
case ipc::CommandType::Close: case ipc::CommandType::Close:

View File

@ -6,6 +6,6 @@ namespace skyline::service::set {
void sys::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void sys::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
SysVerTitle title{.minor=9, .major=0, .micro=0, .revMajor=4, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"}; SysVerTitle title{.minor=9, .major=0, .micro=0, .revMajor=4, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
state.thisProcess->WriteMemory(title, request.vecBufC[0]->address); state.thisProcess->WriteMemory(title, request.outputBuf.at(0).address);
} }
} }

View File

@ -29,7 +29,7 @@ namespace skyline::service::time {
}) {} }) {}
void ISystemClock::GetCurrentTime(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void ISystemClock::GetCurrentTime(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u64>(static_cast<u64>(std::time(nullptr))); response.Push<u64>(static_cast<u64>(std::time(nullptr)));
} }
ITimeZoneService::ITimeZoneService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::time_ITimeZoneService, { ITimeZoneService::ITimeZoneService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::time_ITimeZoneService, {
@ -46,7 +46,7 @@ namespace skyline::service::time {
.minute = static_cast<u8>(calender.tm_min), .minute = static_cast<u8>(calender.tm_min),
.second = static_cast<u8>(calender.tm_sec) .second = static_cast<u8>(calender.tm_sec)
}; };
response.WriteValue(calendarTime); response.Push(calendarTime);
CalendarAdditionalInfo calendarInfo{ CalendarAdditionalInfo calendarInfo{
.day_week = static_cast<u32>(calender.tm_wday), .day_week = static_cast<u32>(calender.tm_wday),
.day_month = static_cast<u32>(calender.tm_mday), .day_month = static_cast<u32>(calender.tm_mday),
@ -54,6 +54,6 @@ namespace skyline::service::time {
.dst = static_cast<i32>(calender.tm_isdst), .dst = static_cast<i32>(calender.tm_isdst),
.utc_rel = static_cast<u32>(calender.tm_gmtoff) .utc_rel = static_cast<u32>(calender.tm_gmtoff)
}; };
response.WriteValue(calendarInfo); response.Push(calendarInfo);
} }
} }

View File

@ -16,7 +16,7 @@ namespace skyline::service::vi {
void IDisplayService::CreateStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IDisplayService::CreateStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.logger->Debug("Creating Stray Layer"); state.logger->Debug("Creating Stray Layer");
response.WriteValue<u64>(0); // There's only one layer response.Push<u64>(0); // There's only one layer
gpu::Parcel parcel(state); gpu::Parcel parcel(state);
LayerParcel data{ LayerParcel data{
.type = 0x20, .type = 0x20,
@ -25,7 +25,7 @@ namespace skyline::service::vi {
.string = "dispdrv" .string = "dispdrv"
}; };
parcel.WriteData(data); parcel.WriteData(data);
response.WriteValue<u64>(parcel.WriteParcel(request.vecBufB[0])); response.Push<u64>(parcel.WriteParcel(request.outputBuf.at(0)));
} }
IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager, Service::vi_IApplicationDisplayService, { IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager, Service::vi_IApplicationDisplayService, {
@ -61,7 +61,7 @@ namespace skyline::service::vi {
std::string displayName(reinterpret_cast<char *>(request.cmdArg)); std::string displayName(reinterpret_cast<char *>(request.cmdArg));
state.logger->Debug("Setting display as: {}", displayName); state.logger->Debug("Setting display as: {}", displayName);
state.gpu->SetDisplay(displayName); state.gpu->SetDisplay(displayName);
response.WriteValue<u64>(0); // There's only one display response.Push<u64>(0); // There's only one display
} }
void IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
@ -74,9 +74,9 @@ namespace skyline::service::vi {
char displayName[0x40]; char displayName[0x40];
u64 layerId; u64 layerId;
u64 userId; u64 userId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg); } input = request.Pop<InputStruct>();
state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input->displayName, input->layerId, input->userId); state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input.displayName, input.layerId, input.userId);
std::string name(input->displayName); std::string name(input.displayName);
gpu::Parcel parcel(state); gpu::Parcel parcel(state);
LayerParcel data{ LayerParcel data{
.type = 0x20, .type = 0x20,
@ -86,24 +86,22 @@ namespace skyline::service::vi {
}; };
parcel.WriteData(data); parcel.WriteData(data);
parcel.objects.resize(4); parcel.objects.resize(4);
response.WriteValue(parcel.WriteParcel(request.vecBufB[0])); response.Push(parcel.WriteParcel(request.outputBuf.at(0)));
} }
void IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u64 layerId = *reinterpret_cast<u64 *>(request.cmdArg); u64 layerId = request.Pop<u64>();
state.logger->Debug("Closing Layer: {}", layerId); state.logger->Debug("Closing Layer: {}", layerId);
if (state.gpu->layerStatus == gpu::LayerStatus::Uninitialized) if (state.gpu->layerStatus == gpu::LayerStatus::Uninitialized)
state.logger->Warn("The application is destroying an uninitialized layer"); state.logger->Warn("The application is destroying an uninitialized layer");
state.gpu->layerStatus = gpu::LayerStatus::Uninitialized; state.gpu->layerStatus = gpu::LayerStatus::Uninitialized;
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
void IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { auto scalingMode = request.Pop<u64>();
u64 scalingMode; auto layerId = request.Pop<u64>();
u64 layerId; state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId);
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", input->scalingMode, input->layerId);
} }
void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
@ -118,7 +116,7 @@ namespace skyline::service::vi {
}) {} }) {}
void ISystemDisplayService::SetLayerZ(skyline::kernel::type::KSession &session, skyline::kernel::ipc::IpcRequest &request, skyline::kernel::ipc::IpcResponse &response) { void ISystemDisplayService::SetLayerZ(skyline::kernel::type::KSession &session, skyline::kernel::ipc::IpcRequest &request, skyline::kernel::ipc::IpcResponse &response) {
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager, Service::vi_IManagerDisplayService, { IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager, Service::vi_IManagerDisplayService, {
@ -129,16 +127,13 @@ namespace skyline::service::vi {
}) {} }) {}
void IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct { request.Skip<u32>();
u32 _unk0_; u64 displayId = request.Pop<u64>();
u64 displayId; state.logger->Debug("Creating Managed Layer: {}", displayId);
u64 userId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.logger->Debug("Creating Managed Layer: {}", input->displayId);
if (state.gpu->layerStatus == gpu::LayerStatus::Initialized) if (state.gpu->layerStatus == gpu::LayerStatus::Initialized)
throw exception("The application is creating more than one layer"); throw exception("The application is creating more than one layer");
state.gpu->layerStatus = gpu::LayerStatus::Initialized; state.gpu->layerStatus = gpu::LayerStatus::Initialized;
response.WriteValue<u64>(0); // There's only one layer response.Push<u64>(0); // There's only one layer
} }
void IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { void IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
@ -146,10 +141,10 @@ namespace skyline::service::vi {
if (state.gpu->layerStatus == gpu::LayerStatus::Uninitialized) if (state.gpu->layerStatus == gpu::LayerStatus::Uninitialized)
state.logger->Warn("The application is destroying an uninitialized layer"); state.logger->Warn("The application is destroying an uninitialized layer");
state.gpu->layerStatus = gpu::LayerStatus::Uninitialized; state.gpu->layerStatus = gpu::LayerStatus::Uninitialized;
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
void IManagerDisplayService::AddToLayerStack(skyline::kernel::type::KSession &session, skyline::kernel::ipc::IpcRequest &request, skyline::kernel::ipc::IpcResponse &response) { void IManagerDisplayService::AddToLayerStack(skyline::kernel::type::KSession &session, skyline::kernel::ipc::IpcRequest &request, skyline::kernel::ipc::IpcResponse &response) {
response.WriteValue<u32>(constant::status::Success); response.Push<u32>(constant::status::Success);
} }
} }