Beispiel #1
0
        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);
        }
Beispiel #2
0
        // 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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        public NvInternalResult RegisterEvent(uint eventId)
        {
            NvInternalResult result = UnregisterEvent(eventId);

            if (result == NvInternalResult.Success)
            {
                Events[eventId] = new NvHostEvent(this, eventId, _device.System);
            }

            return(result);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        [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);
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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);
        }
Beispiel #19
0
        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);
            }
        }
Beispiel #20
0
        private static NvInternalResult PrintResult(MethodInfo info, NvInternalResult result)
        {
            Logger.Debug?.Print(LogClass.ServiceNv, $"{info.Name} returned result {result}");

            return(result);
        }
Beispiel #21
0
        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);
        }
Beispiel #22
0
        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);
        }