private NvInternalResult FreeSpace(ref FreeSpaceArguments arguments) { AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner); NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize; if (addressSpaceContext.RemoveReservation(arguments.Offset)) { addressSpaceContext.Vmm.Free(arguments.Offset, (long)size); } else { Logger.PrintWarning(LogClass.ServiceNv, $"Failed to free offset 0x{arguments.Offset:x16} size 0x{size:x16}!"); result = NvInternalResult.InvalidInput; } } return(result); }
// QueryEvent(s32 fd, u32 event_id) -> (u32, handle<copy, event>) public ResultCode QueryEvent(ServiceCtx context) { NvResult errorCode = EnsureInitialized(); if (errorCode == NvResult.Success) { int fd = context.RequestData.ReadInt32(); uint eventId = context.RequestData.ReadUInt32(); errorCode = GetDeviceFileFromFd(fd, out NvDeviceFile deviceFile); if (errorCode == NvResult.Success) { NvInternalResult internalResult = deviceFile.QueryEvent(out int eventHandle, eventId); if (internalResult == NvInternalResult.NotImplemented) { throw new NvQueryEventNotImplementedException(context, deviceFile, eventId); } errorCode = ConvertInternalErrorCode(internalResult); if (errorCode == NvResult.Success) { context.Response.HandleDesc = IpcHandleDesc.MakeCopy(eventHandle); } } } context.ResponseData.Write((uint)errorCode); return(ResultCode.Success); }
private NvInternalResult FreeSpace(ref FreeSpaceArguments arguments) { AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context); NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize; if (addressSpaceContext.RemoveReservation(arguments.Offset)) { _memoryAllocator.DeallocateRange(arguments.Offset, size); addressSpaceContext.Gmm.Unmap(arguments.Offset, size); } else { Logger.Warning?.Print(LogClass.ServiceNv, $"Failed to free offset 0x{arguments.Offset:x16} size 0x{size:x16}!"); result = NvInternalResult.InvalidInput; } } return(result); }
private NvInternalResult AllocSpace(ref AllocSpaceArguments arguments) { AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context); ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize; NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. if ((arguments.Flags & AddressSpaceFlags.FixedOffset) != 0) { bool regionInUse = _memoryAllocator.IsRegionInUse(arguments.Offset, size, out ulong freeAddressStartPosition); ulong address; if (!regionInUse) { _memoryAllocator.AllocateRange(arguments.Offset, size, freeAddressStartPosition); address = freeAddressStartPosition; } else { address = NvMemoryAllocator.PteUnmapped; } arguments.Offset = address; } else { ulong address = _memoryAllocator.GetFreeAddress(size, out ulong freeAddressStartPosition, arguments.Offset); if (address != NvMemoryAllocator.PteUnmapped) { _memoryAllocator.AllocateRange(address, size, freeAddressStartPosition); } arguments.Offset = address; } if (arguments.Offset == NvMemoryAllocator.PteUnmapped) { arguments.Offset = 0; Logger.Warning?.Print(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!"); result = NvInternalResult.OutOfMemory; } else { addressSpaceContext.AddReservation(arguments.Offset, size); } } return(result); }
public override NvInternalResult Ioctl(NvIoctl command, Span <byte> arguments) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvHostCustomMagic) { switch (command.Number) { case 0x14: result = CallIoctlMethod <NvFence>(SyncptRead, arguments); break; case 0x15: result = CallIoctlMethod <uint>(SyncptIncr, arguments); break; case 0x16: result = CallIoctlMethod <SyncptWaitArguments>(SyncptWait, arguments); break; case 0x19: result = CallIoctlMethod <SyncptWaitExArguments>(SyncptWaitEx, arguments); break; case 0x1a: result = CallIoctlMethod <NvFence>(SyncptReadMax, arguments); break; case 0x1b: // As Marshal cannot handle unaligned arrays, we do everything by hand here. GetConfigurationArguments configArgument = GetConfigurationArguments.FromSpan(arguments); result = GetConfig(configArgument); if (result == NvInternalResult.Success) { configArgument.CopyTo(arguments); } break; case 0x1d: result = CallIoctlMethod <EventWaitArguments>(EventWait, arguments); break; case 0x1e: result = CallIoctlMethod <EventWaitArguments>(EventWaitAsync, arguments); break; case 0x1f: result = CallIoctlMethod <uint>(EventRegister, arguments); break; } } return(result); }
private NvInternalResult EventRegister(ref uint userEventId) { NvInternalResult result = EventUnregister(ref userEventId); if (result == NvInternalResult.Success) { _events[userEventId] = new NvHostEvent(_device.System.HostSyncpoint, userEventId, _device.System); } return(result); }
public NvInternalResult RegisterEvent(uint eventId) { NvInternalResult result = UnregisterEvent(eventId); if (result == NvInternalResult.Success) { Events[eventId] = new NvHostEvent(this, eventId, _device.System); } return(result); }
private NvInternalResult Alloc(ref NvMapAlloc arguments) { NvMapHandle map = GetMapFromHandle(Owner, arguments.Handle); if (map == null) { Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{arguments.Handle:x8}!"); return(NvInternalResult.InvalidInput); } if ((arguments.Align & (arguments.Align - 1)) != 0) { Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid alignment 0x{arguments.Align:x8}!"); return(NvInternalResult.InvalidInput); } if ((uint)arguments.Align < MemoryManager.PageSize) { arguments.Align = (int)MemoryManager.PageSize; } NvInternalResult result = NvInternalResult.Success; if (!map.Allocated) { map.Allocated = true; map.Align = arguments.Align; map.Kind = (byte)arguments.Kind; int size = BitUtils.AlignUp(map.Size, (int)MemoryManager.PageSize); long address = arguments.Address; if (address == 0) { // When the address is zero, we need to allocate // our own backing memory for the NvMap. // TODO: Is this allocation inside the transfer memory? result = NvInternalResult.OutOfMemory; } if (result == NvInternalResult.Success) { map.Size = size; map.Address = address; } } return(result); }
public override NvInternalResult Ioctl(NvIoctl command, Span <byte> arguments) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvMapCustomMagic) { switch (command.Number) { case 0x01: result = CallIoctlMethod <NvMapCreate>(Create, arguments); break; case 0x03: result = CallIoctlMethod <NvMapFromId>(FromId, arguments); break; case 0x04: result = CallIoctlMethod <NvMapAlloc>(Alloc, arguments); break; case 0x05: result = CallIoctlMethod <NvMapFree>(Free, arguments); break; case 0x09: result = CallIoctlMethod <NvMapParam>(Param, arguments); break; case 0x0e: result = CallIoctlMethod <NvMapGetId>(GetId, arguments); break; case 0x02: case 0x06: case 0x07: case 0x08: case 0x0a: case 0x0c: case 0x0d: case 0x0f: case 0x10: case 0x11: result = NvInternalResult.NotSupported; break; } } return(result); }
public override NvInternalResult Ioctl2(NvIoctl command, Span <byte> arguments, Span <byte> inlineInBuffer) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvHostMagic) { switch (command.Number) { case 0x1b: result = CallIoctlMethod <SubmitGpfifoArguments, ulong>(SubmitGpfifoEx, arguments, inlineInBuffer); break; } } return(result); }
[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); }
public override NvInternalResult Ioctl3(NvIoctl command, Span <byte> arguments, Span <byte> inlineOutBuffer) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvGpuAsMagic) { switch (command.Number) { case 0x08: // This is the same as the one in ioctl as inlineOutBuffer is empty. result = CallIoctlMethod <GetVaRegionsArguments>(GetVaRegions, arguments); break; } } return(result); }
public override NvInternalResult Ioctl(NvIoctl command, Span <byte> arguments) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvGpuAsMagic) { switch (command.Number) { case 0x01: result = CallIoctlMethod <BindChannelArguments>(BindChannel, arguments); break; case 0x02: result = CallIoctlMethod <AllocSpaceArguments>(AllocSpace, arguments); break; case 0x03: result = CallIoctlMethod <FreeSpaceArguments>(FreeSpace, arguments); break; case 0x05: result = CallIoctlMethod <UnmapBufferArguments>(UnmapBuffer, arguments); break; case 0x06: result = CallIoctlMethod <MapBufferExArguments>(MapBufferEx, arguments); break; case 0x08: result = CallIoctlMethod <GetVaRegionsArguments>(GetVaRegions, arguments); break; case 0x09: result = CallIoctlMethod <InitializeExArguments>(InitializeEx, arguments); break; case 0x14: result = CallIoctlMethod <RemapArguments>(Remap, arguments); break; } } return(result); }
public NvInternalResult KillEvent(ulong eventMask) { NvInternalResult result = NvInternalResult.Success; for (uint eventId = 0; eventId < EventsCount; eventId++) { if ((eventMask & (1UL << (int)eventId)) != 0) { NvInternalResult tmp = UnregisterEvent(eventId); if (tmp != NvInternalResult.Success) { result = tmp; } } } return(result); }
private NvInternalResult EventKill(ref ulong eventMask) { NvInternalResult result = NvInternalResult.Success; for (uint eventId = 0; eventId < EventsCount; eventId++) { if ((eventMask & (1UL << (int)eventId)) != 0) { NvInternalResult tmp = EventUnregister(ref eventId); if (tmp != NvInternalResult.Success) { result = tmp; } } } return(result); }
public override NvInternalResult Ioctl3(NvIoctl command, Span <byte> arguments, Span <byte> inlineOutBuffer) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvGpuMagic) { switch (command.Number) { case 0x05: result = CallIoctlMethod <GetCharacteristicsArguments, GpuCharacteristics>(GetCharacteristics, arguments, inlineOutBuffer); break; case 0x06: result = CallIoctlMethod <GetTpcMasksArguments, int>(GetTpcMasks, arguments, inlineOutBuffer); break; } } return(result); }
public override NvInternalResult Ioctl(NvIoctl command, Span <byte> arguments) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvGpuMagic) { switch (command.Number) { case 0x01: result = CallIoctlMethod <ZcullGetCtxSizeArguments>(ZcullGetCtxSize, arguments); break; case 0x02: result = CallIoctlMethod <ZcullGetInfoArguments>(ZcullGetInfo, arguments); break; case 0x03: result = CallIoctlMethod <ZbcSetTableArguments>(ZbcSetTable, arguments); break; case 0x05: result = CallIoctlMethod <GetCharacteristicsArguments>(GetCharacteristics, arguments); break; case 0x06: result = CallIoctlMethod <GetTpcMasksArguments>(GetTpcMasks, arguments); break; case 0x14: result = CallIoctlMethod <GetActiveSlotMaskArguments>(GetActiveSlotMask, arguments); break; case 0x1c: result = CallIoctlMethod <GetGpuTimeArguments>(GetGpuTime, arguments); break; } } return(result); }
private NvInternalResult AllocSpace(ref AllocSpaceArguments arguments) { AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context); ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize; NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. if ((arguments.Flags & AddressSpaceFlags.FixedOffset) != 0) { arguments.Offset = (long)addressSpaceContext.Gmm.ReserveFixed((ulong)arguments.Offset, size); } else { arguments.Offset = (long)addressSpaceContext.Gmm.Reserve((ulong)size, (ulong)arguments.Offset); } if (arguments.Offset < 0) { arguments.Offset = 0; Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!"); result = NvInternalResult.OutOfMemory; } else { addressSpaceContext.AddReservation(arguments.Offset, (long)size); } } return(result); }
private static NvResult ConvertInternalErrorCode(NvInternalResult errorCode) { switch (errorCode) { case NvInternalResult.Success: return(NvResult.Success); case NvInternalResult.Unknown0x72: return(NvResult.AlreadyAllocated); case NvInternalResult.TimedOut: case NvInternalResult.TryAgain: case NvInternalResult.Interrupted: return(NvResult.Timeout); case NvInternalResult.InvalidAddress: return(NvResult.InvalidAddress); case NvInternalResult.NotSupported: case NvInternalResult.Unknown0x18: return(NvResult.NotSupported); case NvInternalResult.InvalidState: return(NvResult.InvalidState); case NvInternalResult.ReadOnlyAttribute: return(NvResult.ReadOnlyAttribute); case NvInternalResult.NoSpaceLeft: case NvInternalResult.FileTooBig: return(NvResult.InvalidSize); case NvInternalResult.FileTableOverflow: case NvInternalResult.BadFileNumber: return(NvResult.FileOperationFailed); case NvInternalResult.InvalidInput: return(NvResult.InvalidValue); case NvInternalResult.NotADirectory: return(NvResult.DirectoryOperationFailed); case NvInternalResult.Busy: return(NvResult.Busy); case NvInternalResult.BadAddress: return(NvResult.InvalidAddress); case NvInternalResult.AccessDenied: case NvInternalResult.OperationNotPermitted: return(NvResult.AccessDenied); case NvInternalResult.OutOfMemory: return(NvResult.InsufficientMemory); case NvInternalResult.DeviceNotFound: return(NvResult.ModuleNotPresent); case NvInternalResult.IoError: return(NvResult.ResourceError); default: return(NvResult.IoctlFailed); } }
private static NvInternalResult PrintResult(MethodInfo info, NvInternalResult result) { Logger.Debug?.Print(LogClass.ServiceNv, $"{info.Name} returned result {result}"); return(result); }
private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments) { const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16}, size 0x{1:x16} and alignment 0x{2:x16}!"; AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context); ulong physicalAddress; if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0) { lock (addressSpaceContext) { if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress)) { ulong virtualAddress = arguments.Offset + arguments.BufferOffset; physicalAddress += arguments.BufferOffset; addressSpaceContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize); return(NvInternalResult.Success); } else { Logger.Warning?.Print(LogClass.ServiceNv, $"Address 0x{arguments.Offset:x16} not mapped!"); return(NvInternalResult.InvalidInput); } } } NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle); if (map == null) { Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!"); return(NvInternalResult.InvalidInput); } ulong pageSize = (ulong)arguments.PageSize; if (pageSize == 0) { pageSize = (ulong)map.Align; } physicalAddress = map.Address + arguments.BufferOffset; ulong size = arguments.MappingSize; if (size == 0) { size = (uint)map.Size; } NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. bool virtualAddressAllocated = (arguments.Flags & AddressSpaceFlags.FixedOffset) == 0; if (!virtualAddressAllocated) { if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size, pageSize)) { addressSpaceContext.Gmm.Map(physicalAddress, arguments.Offset, size); } else { string message = string.Format(mapErrorMsg, arguments.Offset, size, pageSize); Logger.Warning?.Print(LogClass.ServiceNv, message); result = NvInternalResult.InvalidInput; } } else { ulong va = _memoryAllocator.GetFreeAddress(size, out ulong freeAddressStartPosition, pageSize); if (va != NvMemoryAllocator.PteUnmapped) { _memoryAllocator.AllocateRange(va, size, freeAddressStartPosition); } addressSpaceContext.Gmm.Map(physicalAddress, va, size); arguments.Offset = va; } if (arguments.Offset == NvMemoryAllocator.PteUnmapped) { arguments.Offset = 0; Logger.Warning?.Print(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); result = NvInternalResult.InvalidInput; } else { addressSpaceContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated); } } return(result); }
private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments) { const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner); NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle, true); if (map == null) { Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!"); return(NvInternalResult.InvalidInput); } long physicalAddress; if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0) { lock (addressSpaceContext) { if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress)) { long virtualAddress = arguments.Offset + arguments.BufferOffset; physicalAddress += arguments.BufferOffset; if (addressSpaceContext.Vmm.Map(physicalAddress, virtualAddress, arguments.MappingSize) < 0) { string message = string.Format(mapErrorMsg, virtualAddress, arguments.MappingSize); Logger.PrintWarning(LogClass.ServiceNv, message); return(NvInternalResult.InvalidInput); } return(NvInternalResult.Success); } else { Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{arguments.Offset:x16} not mapped!"); return(NvInternalResult.InvalidInput); } } } physicalAddress = map.Address + arguments.BufferOffset; long size = arguments.MappingSize; if (size == 0) { size = (uint)map.Size; } NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. bool virtualAddressAllocated = (arguments.Flags & AddressSpaceFlags.FixedOffset) == 0; if (!virtualAddressAllocated) { if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size)) { arguments.Offset = addressSpaceContext.Vmm.Map(physicalAddress, arguments.Offset, size); } else { string message = string.Format(mapErrorMsg, arguments.Offset, size); Logger.PrintWarning(LogClass.ServiceNv, message); result = NvInternalResult.InvalidInput; } } else { arguments.Offset = addressSpaceContext.Vmm.Map(physicalAddress, size); } if (arguments.Offset < 0) { arguments.Offset = 0; Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); result = NvInternalResult.InvalidInput; } else { addressSpaceContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated); } } return(result); }
public override NvInternalResult Ioctl(NvIoctl command, Span <byte> arguments) { NvInternalResult result = NvInternalResult.NotImplemented; if (command.Type == NvIoctl.NvHostCustomMagic) { switch (command.Number) { case 0x01: result = Submit(arguments); break; case 0x02: result = CallIoctlMethod <GetParameterArguments>(GetSyncpoint, arguments); break; case 0x03: result = CallIoctlMethod <GetParameterArguments>(GetWaitBase, arguments); break; case 0x07: result = CallIoctlMethod <uint>(SetSubmitTimeout, arguments); break; case 0x09: result = MapCommandBuffer(arguments); break; case 0x0a: result = UnmapCommandBuffer(arguments); break; } } else if (command.Type == NvIoctl.NvHostMagic) { switch (command.Number) { case 0x01: result = CallIoctlMethod <int>(SetNvMapFd, arguments); break; case 0x03: result = CallIoctlMethod <uint>(SetTimeout, arguments); break; case 0x08: result = SubmitGpfifo(arguments); break; case 0x09: result = CallIoctlMethod <AllocObjCtxArguments>(AllocObjCtx, arguments); break; case 0x0b: result = CallIoctlMethod <ZcullBindArguments>(ZcullBind, arguments); break; case 0x0c: result = CallIoctlMethod <SetErrorNotifierArguments>(SetErrorNotifier, arguments); break; case 0x0d: result = CallIoctlMethod <NvChannelPriority>(SetPriority, arguments); break; case 0x18: result = CallIoctlMethod <AllocGpfifoExArguments>(AllocGpfifoEx, arguments); break; case 0x1a: result = CallIoctlMethod <AllocGpfifoExArguments>(AllocGpfifoEx2, arguments); break; case 0x1d: result = CallIoctlMethod <uint>(SetTimeslice, arguments); break; } } else if (command.Type == NvIoctl.NvGpuMagic) { switch (command.Number) { case 0x14: result = CallIoctlMethod <ulong>(SetUserData, arguments); break; } } return(result); }