private NvResult GetIoctlArgument(ServiceCtx context, NvIoctl ioctlCommand, out Span <byte> arguments) { (long inputDataPosition, long inputDataSize) = context.Request.GetBufferType0x21(0); (long outputDataPosition, long outputDataSize) = context.Request.GetBufferType0x22(0); NvIoctl.Direction ioctlDirection = ioctlCommand.DirectionValue; uint ioctlSize = ioctlCommand.Size; bool isRead = (ioctlDirection & NvIoctl.Direction.Read) != 0; bool isWrite = (ioctlDirection & NvIoctl.Direction.Write) != 0; if ((isWrite && ioctlSize > outputDataSize) || (isRead && ioctlSize > inputDataSize)) { arguments = null; Logger.Warning?.Print(LogClass.ServiceNv, "Ioctl size inconsistency found!"); return(NvResult.InvalidSize); } if (isRead && isWrite) { if (outputDataSize < inputDataSize) { arguments = null; Logger.Warning?.Print(LogClass.ServiceNv, "Ioctl size inconsistency found!"); return(NvResult.InvalidSize); } byte[] outputData = new byte[outputDataSize]; byte[] temp = new byte[inputDataSize]; context.Memory.Read((ulong)inputDataPosition, temp); Buffer.BlockCopy(temp, 0, outputData, 0, temp.Length); arguments = new Span <byte>(outputData); } else if (isWrite) { byte[] outputData = new byte[outputDataSize]; arguments = new Span <byte>(outputData); } else { byte[] temp = new byte[inputDataSize]; context.Memory.Read((ulong)inputDataPosition, temp); arguments = new Span <byte>(temp); } return(NvResult.Success); }
[Command(12)] // 3.0.0+ // Ioctl3(s32 fd, u32 ioctl_cmd, buffer<bytes, 0x21> in_args) -> (u32 error_code, buffer<bytes, 0x22> out_args, buffer<bytes, 0x22> inline_out_buffer) public ResultCode Ioctl3(ServiceCtx context) { NvResult errorCode = EnsureInitialized(); if (errorCode == NvResult.Success) { int fd = context.RequestData.ReadInt32(); NvIoctl ioctlCommand = context.RequestData.ReadStruct <NvIoctl>(); (long inlineOutBufferPosition, long inlineOutBufferSize) = context.Request.GetBufferType0x22(1); errorCode = GetIoctlArgument(context, ioctlCommand, out Span <byte> arguments); byte[] temp = new byte[inlineOutBufferSize]; context.Memory.Read((ulong)inlineOutBufferPosition, temp); Span <byte> inlineOutBuffer = new Span <byte>(temp); if (errorCode == NvResult.Success) { errorCode = GetDeviceFileFromFd(fd, out NvDeviceFile deviceFile); if (errorCode == NvResult.Success) { NvInternalResult internalResult = deviceFile.Ioctl3(ioctlCommand, arguments, inlineOutBuffer); if (internalResult == NvInternalResult.NotImplemented) { throw new NvIoctlNotImplementedException(context, deviceFile, ioctlCommand); } errorCode = ConvertInternalErrorCode(internalResult); if ((ioctlCommand.DirectionValue & NvIoctl.Direction.Write) != 0) { context.Memory.Write((ulong)context.Request.GetBufferType0x22(0).Position, arguments.ToArray()); context.Memory.Write((ulong)inlineOutBufferPosition, inlineOutBuffer.ToArray()); } } } } context.ResponseData.Write((uint)errorCode); return(ResultCode.Success); }