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) {
state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd);
try {
if (!request.vecBufA.empty() && !request.vecBufB.empty()) {
device::IoctlBuffers input(device::InputBuffer(request.vecBufA[0]), device::OutputBuffer(request.vecBufB[0]));
fdMap.at(fd)->HandleIoctl(cmd, input);
response.WriteValue<u32>(input.status);
} else if (!request.vecBufX.empty() && !request.vecBufC.empty()) {
device::IoctlBuffers input(device::InputBuffer(request.vecBufX[0]), device::OutputBuffer(request.vecBufC[0]));
fdMap.at(fd)->HandleIoctl(cmd, input);
response.WriteValue<u32>(input.status);
} else if (!request.vecBufX.empty()) {
device::IoctlBuffers input(device::InputBuffer(request.vecBufX[0]));
fdMap.at(fd)->HandleIoctl(cmd, input);
response.WriteValue<u32>(input.status);
} else if (!request.vecBufC.empty()) {
device::IoctlBuffers input(device::OutputBuffer(request.vecBufC[0]));
fdMap.at(fd)->HandleIoctl(cmd, input);
response.WriteValue<u32>(input.status);
} else
throw exception("Unknown IOCTL buffer configuration");
if(request.inputBuf.empty() || request.outputBuf.empty()) {
if(request.inputBuf.empty()) {
device::IoctlData data(request.outputBuf.at(0));
fdMap.at(fd)->HandleIoctl(cmd, data);
response.Push<u32>(data.status);
} else {
device::IoctlData data(request.inputBuf.at(0));
fdMap.at(fd)->HandleIoctl(cmd, data);
response.Push<u32>(data.status);
}
} else {
device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0));
fdMap.at(fd)->HandleIoctl(cmd, data);
response.Push<u32>(data.status);
}
} catch (const std::out_of_range &) {
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}
};
/**
* @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)
*/
@ -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 {
std::vector<InputBuffer> input; //!< A vector of all input IOCTL buffers
std::vector<OutputBuffer> output; //!< A vector of all output IOCTL buffers
struct IoctlData {
std::vector<kernel::ipc::InputBuffer> input; //!< A vector of all input 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
/**
@ -140,19 +96,19 @@ namespace skyline::gpu::device {
* @param input An input 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
* @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
* @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
@ -160,7 +116,7 @@ namespace skyline::gpu::device {
* @param input2 The second input 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
@ -168,7 +124,7 @@ namespace skyline::gpu::device {
* @param output1 The first 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 {
protected:
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:
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 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
@ -208,8 +164,8 @@ namespace skyline::gpu::device {
* @param cmd The IOCTL command that was called
* @param input The input to the IOCTL call
*/
void HandleIoctl(u32 cmd, IoctlBuffers &input) {
std::function<void(IoctlBuffers &)> function;
void HandleIoctl(u32 cmd, IoctlData &input) {
std::function<void(IoctlData &)> function;
try {
function = vTable.at(cmd);
} catch (std::out_of_range &) {

View File

@ -12,15 +12,15 @@ namespace skyline::gpu::device {
{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);
switch (priority) {
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)
*/
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)
*/
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)
*/
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)
*/
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)
*/
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)
*/
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)
*/
void SetUserData(IoctlBuffers &buffer);
void SetUserData(IoctlData &buffer);
};
}

View File

@ -10,12 +10,12 @@ namespace skyline::gpu::device {
{0x80084714, NFUNC(NvHostCtrlGpu::GetActiveSlotMask)}
}) {}
void NvHostCtrlGpu::ZCullGetCtxSize(IoctlBuffers &buffer) {
void NvHostCtrlGpu::ZCullGetCtxSize(IoctlData &buffer) {
u32 size = 0x1;
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 {
u32 widthAlignPixels{0x20};
u32 heightAlignPixels{0x20};
@ -31,7 +31,7 @@ namespace skyline::gpu::device {
state.thisProcess->WriteMemory(zCullInfo, buffer.output[0].address);
}
void NvHostCtrlGpu::GetCharacteristics(IoctlBuffers &buffer) {
void NvHostCtrlGpu::GetCharacteristics(IoctlData &buffer) {
struct GpuCharacteristics {
u32 arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
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);
}
void NvHostCtrlGpu::GetTpcMasks(IoctlBuffers &buffer) {
void NvHostCtrlGpu::GetTpcMasks(IoctlData &buffer) {
struct Data {
u32 maskBufSize; // In
u32 reserved[3]; // In
@ -125,7 +125,7 @@ namespace skyline::gpu::device {
state.thisProcess->WriteMemory(data, buffer.output[0].address);
}
void NvHostCtrlGpu::GetActiveSlotMask(IoctlBuffers &buffer) {
void NvHostCtrlGpu::GetActiveSlotMask(IoctlData &buffer) {
struct Data {
u32 slot; // 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)
*/
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)
*/
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)
*/
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)
*/
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)
*/
void GetActiveSlotMask(IoctlBuffers &buffer);
void GetActiveSlotMask(IoctlData &buffer);
};
}

View File

@ -13,7 +13,7 @@ namespace skyline::gpu::device {
{0xC008010E, NFUNC(NvMap::GetId)}
}) {}
void NvMap::Create(IoctlBuffers &buffer) {
void NvMap::Create(IoctlData &buffer) {
struct Data {
u32 size; // In
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);
}
void NvMap::FromId(skyline::gpu::device::IoctlBuffers &buffer) {
void NvMap::FromId(skyline::gpu::device::IoctlData &buffer) {
struct Data {
u32 id; // In
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);
}
void NvMap::Alloc(IoctlBuffers &buffer) {
void NvMap::Alloc(IoctlData &buffer) {
struct Data {
u32 handle; // 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);
}
void NvMap::Free(skyline::gpu::device::IoctlBuffers &buffer) {
void NvMap::Free(skyline::gpu::device::IoctlData &buffer) {
struct Data {
u32 handle; // In
u32 _pad0_;
@ -85,7 +85,7 @@ namespace skyline::gpu::device {
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
struct Data {
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);
}
void NvMap::GetId(skyline::gpu::device::IoctlBuffers &buffer) {
void NvMap::GetId(skyline::gpu::device::IoctlData &buffer) {
struct Data {
u32 id; // Out
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)
*/
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)
*/
void FromId(IoctlBuffers &buffer);
void FromId(IoctlData &buffer);
/**
* @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)
*/
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)
*/
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)
*/
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);
}
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) {}
@ -49,7 +49,7 @@ namespace skyline::gpu {
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);
i64 slot{-1};
for (auto &buffer : queue) {
@ -60,7 +60,7 @@ namespace skyline::gpu {
}
if (slot == -1) {
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);
return true;
}
@ -130,12 +130,12 @@ namespace skyline::gpu {
else {
auto context = waitVec.begin();
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();
gpu::Parcel out(state);
DequeueOut output(slotNo);
out.WriteData(output);
out.WriteParcel(context->address, context->size, context->thread->pid);
out.WriteParcel(context->buffer, context->thread->pid);
slot->status = BufferStatus::Dequeued;
waitVec.erase(context);
break;

View File

@ -160,16 +160,14 @@ namespace skyline::gpu {
struct WaitContext {
std::shared_ptr<kernel::type::KThread> thread; //!< The thread that is waiting on a buffer
DequeueIn input; //!< The input of DequeueBuffer
u64 address; //!< The address of the parcel buffer
u64 size; //!< The size of the parcel buffer
kernel::ipc::OutputBuffer buffer; //!< The output buffer to write the parcel into
/**
* @param thread The thread that is waiting on a buffer
* @param input The input of DequeueBuffer
* @param address The address of the parcel buffer
* @param size The size of the parcel buffer
* @param buffer The output buffer to write the parcel into
*/
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
@ -189,11 +187,10 @@ namespace skyline::gpu {
/**
* @brief This returns the slot of a free buffer
* @param address The address of the parcel buffer
* @param size The size of the parcel buffer
* @param buffer The output parcel buffer
* @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

View File

@ -3,9 +3,7 @@
#include <kernel/types/KProcess.h>
namespace skyline::gpu {
Parcel::Parcel(kernel::ipc::BufferDescriptorABW *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(kernel::ipc::InputBuffer &buffer, const DeviceState &state) : Parcel(buffer.address, buffer.size, state) {}
Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) {
state.thisProcess->ReadMemory(&header, address, sizeof(ParcelHeader));
@ -19,12 +17,8 @@ namespace skyline::gpu {
Parcel::Parcel(const DeviceState &state) : state(state) {}
u64 Parcel::WriteParcel(kernel::ipc::BufferDescriptorABW *buffer, pid_t 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(kernel::ipc::OutputBuffer& buffer, pid_t process) {
return WriteParcel(buffer.address, buffer.size, 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 state The state of the device
*/
Parcel(kernel::ipc::BufferDescriptorABW *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);
Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state);
/**
* @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 process The process to write the Parcel to
* @return The total size of the message
*/
u64 WriteParcel(kernel::ipc::BufferDescriptorABW *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);
u64 WriteParcel(kernel::ipc::OutputBuffer& buffer, pid_t process = 0);
/**
* @brief Writes the Parcel object into the process's memory

View File

@ -2,6 +2,16 @@
#include "types/KProcess.h"
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() {
u8 *currPtr = tls.data();
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++) {
auto bufX = reinterpret_cast<BufferDescriptorX *>(currPtr);
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()));
}
currPtr += sizeof(BufferDescriptorX);
@ -34,7 +44,7 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Ano > index; index++) {
auto bufA = reinterpret_cast<BufferDescriptorABW *>(currPtr);
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()));
}
currPtr += sizeof(BufferDescriptorABW);
@ -43,7 +53,7 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Bno > index; index++) {
auto bufB = reinterpret_cast<BufferDescriptorABW *>(currPtr);
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()));
}
currPtr += sizeof(BufferDescriptorABW);
@ -52,7 +62,8 @@ namespace skyline::kernel::ipc {
for (uint index = 0; header->Wno > index; index++) {
auto bufW = reinterpret_cast<BufferDescriptorABW *>(currPtr);
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()));
}
currPtr += sizeof(BufferDescriptorABW);
@ -85,6 +96,8 @@ namespace skyline::kernel::ipc {
currPtr += cmdArgSz;
}
payloadOffset = cmdArg;
if (payload->magic != constant::SfciMagic && header->type != CommandType::Control)
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) {
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));
}
} else if (header->cFlag > BufferCFlag::SingleDescriptor) {
for (uint index = 0; (static_cast<u8>(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present
auto bufC = reinterpret_cast<BufferDescriptorC *>(currPtr);
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));
}
currPtr += sizeof(BufferDescriptorC);
@ -106,7 +121,7 @@ namespace skyline::kernel::ipc {
}
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)
state.logger->Debug("Handle Descriptor: Send PID: {}, Copy Count: {}, Move Count: {}", bool(handleDesc->sendPid), u32(handleDesc->copyCount), u32(handleDesc->moveCount));
if (isDomain)
@ -117,7 +132,7 @@ namespace skyline::kernel::ipc {
IpcResponse::IpcResponse(bool isDomain, const DeviceState &state) : isDomain(isDomain), state(state) {}
void IpcResponse::WriteTls() {
void IpcResponse::WriteResponse() {
std::array<u8, constant::TlsIpcSize> tls{};
u8 *currPtr = tls.data();
auto header = reinterpret_cast<CommandHeader *>(currPtr);

View File

@ -168,12 +168,70 @@ namespace skyline::kernel::ipc {
};
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)
*/
class IpcRequest {
private:
const DeviceState &state; //!< The state of the device
u8 *payloadOffset; //!< This is the offset of the data read from the payload
public:
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> 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<BufferDescriptorX *> vecBufX; //!< This is a vector of pointers to X Buffer Descriptors
std::vector<BufferDescriptorABW *> vecBufA; //!< This is a vector of pointers to A Buffer Descriptors
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
std::vector<InputBuffer> inputBuf; //!< This is a vector of input buffers
std::vector<OutputBuffer> outputBuf; //!< This is a vector of output buffers
/**
* @param isDomain If the following request is a domain request
* @param state The state of the device
*/
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
* @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>
void WriteValue(const ValueType &value) {
inline void Push(const ValueType &value) {
argVec.reserve(argVec.size() + sizeof(ValueType));
auto item = reinterpret_cast<const u8 *>(&value);
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
*/
void WriteTls();
void WriteResponse();
};
}

View File

@ -460,6 +460,8 @@ namespace skyline::kernel::svc {
void OutputDebugString(DeviceState &state) {
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));
if(debug.back() == '\n')
debug.pop_back();
state.logger->Info("Debug Output: {}", debug);
state.nce->SetRegister(Wreg::W0, constant::status::Success);
}

View File

@ -2,9 +2,6 @@
#include <nce.h>
#include <os.h>
constexpr const char *ASHMEM_NAME_DEF = "dev/ashmem";
constexpr int ASHMEM_SET_SIZE = 0x40087703;
namespace skyline::kernel::type {
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)

View File

@ -30,20 +30,20 @@ namespace skyline::service::am {
response.errorCode = constant::status::NoMessages;
return;
}
response.WriteValue<u32>(static_cast<u32>(messageQueue.front()));
response.Push<u32>(static_cast<u32>(messageQueue.front()));
messageQueue.pop();
}
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) {
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) {
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) {
@ -77,7 +77,7 @@ namespace skyline::service::am {
if (state.gpu->layerStatus == gpu::LayerStatus::Initialized)
throw exception("The application is creating more than one layer");
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, {
@ -86,7 +86,7 @@ namespace skyline::service::am {
}) {}
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) {}
@ -105,7 +105,7 @@ namespace skyline::service::am {
}) {}
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, {

View File

@ -15,16 +15,14 @@ namespace skyline::service::apm {
}) {}
void ISession::SetPerformanceConfiguration(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
u32 mode;
u32 config;
} *performance = reinterpret_cast<InputStruct *>(request.cmdArg);
performanceConfig[performance->mode] = performance->config;
state.logger->Info("SetPerformanceConfiguration called with 0x{:X} ({})", performance->config, performance->mode ? "Docked" : "Handheld");
auto mode = request.Pop<u32>();
auto config = request.Pop<u32>();
performanceConfig[mode] = config;
state.logger->Info("SetPerformanceConfiguration called with 0x{:X} ({})", config, mode ? "Docked" : "Handheld");
}
void ISession::GetPerformanceConfiguration(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u32 performanceMode = *reinterpret_cast<u32 *>(request.cmdArg);
response.WriteValue<u32>(performanceConfig[performanceMode]);
u32 performanceMode = request.Pop<u32>();
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) {
struct InputStruct {
u32 styleSet;
u64 appletUserId;
} *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));
auto styleSet = request.Pop<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) {
const auto &buffer = request.vecBufX[0];
uint numId = buffer->size / sizeof(NpadId);
u64 address = buffer->Address();
for (uint i = 0; i < numId; i++) {
const auto &buffer = request.inputBuf.at(0);
size_t numId = buffer.size / sizeof(NpadId);
u64 address = buffer.address;
for (size_t i = 0; i < numId; i++) {
auto id = state.thisProcess->ReadMemory<NpadId>(address);
deviceMap[id] = JoyConDevice(id);
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::SetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
NpadId controllerId;
u64 appletUserId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
deviceMap[input->controllerId].assignment = JoyConAssignment::Single;
deviceMap[request.Pop<NpadId>()].assignment = JoyConAssignment::Single;
}
void hid::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
u64 appletUserId;
JoyConOrientation orientation;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
orientation = input->orientation;
orientation = request.Pop<JoyConOrientation>();
}
void hid::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
NpadId controllerId;
u64 appletUserId;
JoyConSide joyDeviceType;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
deviceMap[input->controllerId].assignment = JoyConAssignment::Single;
deviceMap[input->controllerId].side = input->joyDeviceType;
auto controllerId = request.Pop<NpadId>();
auto appletUserId = request.Pop<u64>();
deviceMap[controllerId].assignment = JoyConAssignment::Single;
deviceMap[controllerId].side = request.Pop<JoyConSide>();
}
void hid::SetNpadJoyAssignmentModeDual(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
NpadId controllerType;
u64 appletUserId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
deviceMap[input->controllerType].assignment = JoyConAssignment::Dual;
deviceMap[request.Pop<NpadId>()].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) {
auto aBuf = request.vecBufA[0];
std::string path(aBuf->Size(), '\0');
state.thisProcess->ReadMemory(path.data(), aBuf->Address(), aBuf->Size());
response.WriteValue<u32>(state.gpu->OpenDevice(path));
response.WriteValue<u32>(constant::status::Success);
auto buffer = request.inputBuf.at(0);
std::string path(buffer.size, '\0');
state.thisProcess->ReadMemory(path.data(), buffer.address, buffer.size);
response.Push<u32>(state.gpu->OpenDevice(path));
response.Push<u32>(constant::status::Success);
}
void nvdrv::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
u32 fd;
u32 cmd;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.gpu->Ioctl(input->fd, input->cmd, request, response);
auto fd = request.Pop<u32>();
auto cmd = request.Pop<u32>();
state.gpu->Ioctl(fd, cmd, request, response);
}
void nvdrv::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u32 fd = *reinterpret_cast<u32 *>(request.cmdArg);
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) {
response.WriteValue<u32>(constant::status::Success);
response.Push<u32>(constant::status::Success);
}
void nvdrv::QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
u32 fd;
u32 eventId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
auto fd = request.Pop<u32>();
auto eventId = request.Pop<u32>();
auto event = std::make_shared<type::KEvent>(state);
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);
}
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) {
struct InputStruct {
u32 layerId;
TransactionCode code;
} *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);
auto layerId = request.Pop<u32>();
auto code = request.Pop<TransactionCode>();
gpu::Parcel in(request.inputBuf.at(0), state);
gpu::Parcel out(state);
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", input->layerId, input->code);
switch (input->code) {
state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code);
switch (code) {
case TransactionCode::RequestBuffer:
state.gpu->bufferQueue.RequestBuffer(*in, out);
state.gpu->bufferQueue.RequestBuffer(in, out);
break;
case TransactionCode::DequeueBuffer: {
if (request.vecBufA.empty()) {
if (state.gpu->bufferQueue.DequeueBuffer(*in, out, request.vecBufC[0]->address, request.vecBufC[0]->size))
if (state.gpu->bufferQueue.DequeueBuffer(in, out, request.outputBuf.at(0)))
return;
} else {
if (state.gpu->bufferQueue.DequeueBuffer(*in, out, request.vecBufB[0]->Address(), request.vecBufB[0]->Size()))
return;
}
break;
}
case TransactionCode::QueueBuffer:
state.gpu->bufferQueue.QueueBuffer(*in, out);
state.gpu->bufferQueue.QueueBuffer(in, out);
break;
case TransactionCode::CancelBuffer:
state.gpu->bufferQueue.CancelBuffer(*in);
state.gpu->bufferQueue.CancelBuffer(in);
break;
case TransactionCode::Query:
out.WriteData<u64>(0);
@ -59,30 +48,25 @@ namespace skyline::service::nvnflinger {
case TransactionCode::Disconnect:
break;
case TransactionCode::SetPreallocatedBuffer:
state.gpu->bufferQueue.SetPreallocatedBuffer(*in);
state.gpu->bufferQueue.SetPreallocatedBuffer(in);
break;
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.vecBufC[0]);
else
out.WriteParcel(request.vecBufB[0]);
out.WriteParcel(request.outputBuf.at(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) {
handle_t handle = state.thisProcess->InsertItem(state.gpu->bufferEvent);
state.logger->Debug("BufferEvent Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);
response.WriteValue<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");
response.Push<u32>(constant::status::Success);
}
}

View File

@ -50,14 +50,14 @@ namespace skyline::service::nvnflinger {
*/
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)
*/
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
session->serviceObject->HandleRequest(*session, request, response);
if (!response.nWrite)
response.WriteTls();
response.WriteResponse();
break;
case ipc::CommandType::Control:
@ -207,19 +207,19 @@ namespace skyline::service {
state.logger->Debug("Control IPC Message: 0x{:X}", request.payload->value);
switch (static_cast<ipc::ControlCommand>(request.payload->value)) {
case ipc::ControlCommand::ConvertCurrentObjectToDomain:
response.WriteValue(session->ConvertDomain());
response.Push(session->ConvertDomain());
break;
case ipc::ControlCommand::CloneCurrentObject:
case ipc::ControlCommand::CloneCurrentObjectEx:
response.WriteValue(state.thisProcess->InsertItem(session));
response.Push(state.thisProcess->InsertItem(session));
break;
case ipc::ControlCommand::QueryPointerBufferSize:
response.WriteValue<u32>(0x1000);
response.Push<u32>(0x1000);
break;
default:
throw exception("Unknown Control Command: {}", request.payload->value);
}
response.WriteTls();
response.WriteResponse();
break;
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) {
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) {
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, {
@ -46,7 +46,7 @@ namespace skyline::service::time {
.minute = static_cast<u8>(calender.tm_min),
.second = static_cast<u8>(calender.tm_sec)
};
response.WriteValue(calendarTime);
response.Push(calendarTime);
CalendarAdditionalInfo calendarInfo{
.day_week = static_cast<u32>(calender.tm_wday),
.day_month = static_cast<u32>(calender.tm_mday),
@ -54,6 +54,6 @@ namespace skyline::service::time {
.dst = static_cast<i32>(calender.tm_isdst),
.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) {
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);
LayerParcel data{
.type = 0x20,
@ -25,7 +25,7 @@ namespace skyline::service::vi {
.string = "dispdrv"
};
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, {
@ -61,7 +61,7 @@ namespace skyline::service::vi {
std::string displayName(reinterpret_cast<char *>(request.cmdArg));
state.logger->Debug("Setting display as: {}", 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) {
@ -74,9 +74,9 @@ namespace skyline::service::vi {
char displayName[0x40];
u64 layerId;
u64 userId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input->displayName, input->layerId, input->userId);
std::string name(input->displayName);
} input = request.Pop<InputStruct>();
state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input.displayName, input.layerId, input.userId);
std::string name(input.displayName);
gpu::Parcel parcel(state);
LayerParcel data{
.type = 0x20,
@ -86,24 +86,22 @@ namespace skyline::service::vi {
};
parcel.WriteData(data);
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) {
u64 layerId = *reinterpret_cast<u64 *>(request.cmdArg);
u64 layerId = request.Pop<u64>();
state.logger->Debug("Closing Layer: {}", layerId);
if (state.gpu->layerStatus == gpu::LayerStatus::Uninitialized)
state.logger->Warn("The application is destroying an uninitialized layer");
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) {
struct InputStruct {
u64 scalingMode;
u64 layerId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", input->scalingMode, input->layerId);
auto scalingMode = request.Pop<u64>();
auto layerId = request.Pop<u64>();
state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId);
}
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) {
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, {
@ -129,16 +127,13 @@ namespace skyline::service::vi {
}) {}
void IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct InputStruct {
u32 _unk0_;
u64 displayId;
u64 userId;
} *input = reinterpret_cast<InputStruct *>(request.cmdArg);
state.logger->Debug("Creating Managed Layer: {}", input->displayId);
request.Skip<u32>();
u64 displayId = request.Pop<u64>();
state.logger->Debug("Creating Managed Layer: {}", displayId);
if (state.gpu->layerStatus == gpu::LayerStatus::Initialized)
throw exception("The application is creating more than one layer");
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) {
@ -146,10 +141,10 @@ namespace skyline::service::vi {
if (state.gpu->layerStatus == gpu::LayerStatus::Uninitialized)
state.logger->Warn("The application is destroying an uninitialized layer");
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) {
response.WriteValue<u32>(constant::status::Success);
response.Push<u32>(constant::status::Success);
}
}