Beispiel #1
0
        private NvInternalResult MapCommandBuffer(Span <byte> arguments)
        {
            int headerSize = Unsafe.SizeOf <MapCommandBufferArguments>();
            MapCommandBufferArguments  commandBufferHeader  = MemoryMarshal.Cast <byte, MapCommandBufferArguments>(arguments)[0];
            Span <CommandBufferHandle> commandBufferEntries = MemoryMarshal.Cast <byte, CommandBufferHandle>(arguments.Slice(headerSize)).Slice(0, commandBufferHeader.NumEntries);
            MemoryManager gmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Context).Gmm;

            foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
            {
                NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);

                if (map == null)
                {
                    Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");

                    return(NvInternalResult.InvalidInput);
                }

                lock (map)
                {
                    if (map.DmaMapAddress == 0)
                    {
                        ulong va = _memoryAllocator.GetFreeAddress((ulong)map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize);

                        if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue)
                        {
                            _memoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition);
                            gmm.Map((ulong)map.Address, va, (uint)map.Size);
                            map.DmaMapAddress = (long)va;
                        }
                        else
                        {
                            map.DmaMapAddress = unchecked ((long)NvMemoryAllocator.PteUnmapped);
                        }
                    }

                    commandBufferEntry.MapAddress = (int)map.DmaMapAddress;
                }
            }

            return(NvInternalResult.Success);
        }
Beispiel #2
0
        private NvInternalResult Submit(Span <byte> arguments)
        {
            SubmitArguments      submitHeader   = GetSpanAndSkip <SubmitArguments>(ref arguments, 1)[0];
            Span <CommandBuffer> commandBuffers = GetSpanAndSkip <CommandBuffer>(ref arguments, submitHeader.CmdBufsCount);
            Span <Reloc>         relocs         = GetSpanAndSkip <Reloc>(ref arguments, submitHeader.RelocsCount);
            Span <uint>          relocShifts    = GetSpanAndSkip <uint>(ref arguments, submitHeader.RelocsCount);
            Span <SyncptIncr>    syncptIncrs    = GetSpanAndSkip <SyncptIncr>(ref arguments, submitHeader.SyncptIncrsCount);
            Span <SyncptIncr>    waitChecks     = GetSpanAndSkip <SyncptIncr>(ref arguments, submitHeader.SyncptIncrsCount); // ?
            Span <Fence>         fences         = GetSpanAndSkip <Fence>(ref arguments, submitHeader.FencesCount);

            lock (_device)
            {
                for (int i = 0; i < syncptIncrs.Length; i++)
                {
                    SyncptIncr syncptIncr = syncptIncrs[i];

                    uint id = syncptIncr.Id;

                    fences[i].Id     = id;
                    fences[i].Thresh = Context.Device.System.HostSyncpoint.IncrementSyncpointMax(id, syncptIncr.Incrs);
                }

                foreach (CommandBuffer commandBuffer in commandBuffers)
                {
                    NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBuffer.Mem);

                    var data = _memory.GetSpan((ulong)map.Address + commandBuffer.Offset, commandBuffer.WordsCount * 4);

                    _device.Host1x.Submit(MemoryMarshal.Cast <byte, int>(data));
                }
            }

            fences[0].Thresh = Context.Device.System.HostSyncpoint.IncrementSyncpointMax(fences[0].Id, 1);

            Span <int> tmpCmdBuff = stackalloc int[1];

            tmpCmdBuff[0] = (4 << 28) | (int)fences[0].Id;

            _device.Host1x.Submit(tmpCmdBuff);

            return(NvInternalResult.Success);
        }
Beispiel #3
0
        private static int Remap(ServiceCtx Context)
        {
            long InputPosition = Context.Request.GetBufferType0x21().Position;

            NvGpuASRemap Args = AMemoryHelper.Read <NvGpuASRemap>(Context.Memory, InputPosition);

            NvGpuVmm Vmm = GetVmm(Context);

            NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle);

            if (Map == null)
            {
                Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!");

                return(NvResult.InvalidInput);
            }

            //FIXME: This is most likely wrong...
            Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16,
                    (long)(uint)Args.Pages << 16);

            return(NvResult.Success);
        }
        private NvInternalResult Submit(Span <byte> arguments)
        {
            int                  headerSize           = Unsafe.SizeOf <SubmitArguments>();
            SubmitArguments      submitHeader         = MemoryMarshal.Cast <byte, SubmitArguments>(arguments)[0];
            Span <CommandBuffer> commandBufferEntries = MemoryMarshal.Cast <byte, CommandBuffer>(arguments.Slice(headerSize)).Slice(0, submitHeader.CmdBufsCount);
            MemoryManager        gmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Context).Gmm;

            foreach (CommandBuffer commandBufferEntry in commandBufferEntries)
            {
                NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MemoryId);

                int[] commandBufferData = new int[commandBufferEntry.WordsCount];

                for (int offset = 0; offset < commandBufferData.Length; offset++)
                {
                    commandBufferData[offset] = _memory.ReadInt32(map.Address + commandBufferEntry.Offset + offset * 4);
                }

                // TODO: Submit command to engines.
            }

            return(NvInternalResult.Success);
        }
Beispiel #5
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 #6
0
        private void PostFrameBuffer(Layer layer, BufferItem item)
        {
            int frameBufferWidth  = item.GraphicBuffer.Object.Width;
            int frameBufferHeight = item.GraphicBuffer.Object.Height;

            int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;

            if (nvMapHandle == 0)
            {
                nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId;
            }

            ulong bufferOffset = (ulong)item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset;

            NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle);

            ulong frameBufferAddress = map.Address + bufferOffset;

            Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);

            int bytesPerPixel =
                format == Format.B5G6R5Unorm ||
                format == Format.R4G4B4A4Unorm ? 2 : 4;

            int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;

            // Note: Rotation is being ignored.
            Rect cropRect = item.Crop;

            bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
            bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);

            AspectRatio aspectRatio = _device.Configuration.AspectRatio;
            bool        isStretched = aspectRatio == AspectRatio.Stretched;

            ImageCrop crop = new ImageCrop(
                cropRect.Left,
                cropRect.Right,
                cropRect.Top,
                cropRect.Bottom,
                flipX,
                flipY,
                isStretched,
                aspectRatio.ToFloatX(),
                aspectRatio.ToFloatY());

            TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation
            {
                Layer = layer,
                Item  = item
            };

            _device.Gpu.Window.EnqueueFrameThreadSafe(
                layer.Owner,
                frameBufferAddress,
                frameBufferWidth,
                frameBufferHeight,
                0,
                false,
                gobBlocksInY,
                format,
                bytesPerPixel,
                crop,
                AcquireBuffer,
                ReleaseBuffer,
                textureCallbackInformation);

            if (item.Fence.FenceCount == 0)
            {
                _device.Gpu.Window.SignalFrameReady();
                _device.Gpu.GPFifo.Interrupt();
            }
            else
            {
                item.Fence.RegisterCallback(_device.Gpu, (x) =>
                {
                    _device.Gpu.Window.SignalFrameReady();
                    _device.Gpu.GPFifo.Interrupt();
                });
            }
        }
Beispiel #7
0
        private void PostFrameBuffer(Layer layer, BufferItem item)
        {
            int frameBufferWidth  = item.GraphicBuffer.Object.Width;
            int frameBufferHeight = item.GraphicBuffer.Object.Height;

            int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;

            if (nvMapHandle == 0)
            {
                nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId;
            }

            int bufferOffset = item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset;

            NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle);

            ulong frameBufferAddress = (ulong)(map.Address + bufferOffset);

            Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);

            int bytesPerPixel =
                format == Format.B5G6R5Unorm ||
                format == Format.R4G4B4A4Unorm ? 2 : 4;

            int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;

            // Note: Rotation is being ignored.
            Rect cropRect = item.Crop;

            bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
            bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);

            ImageCrop crop = new ImageCrop(
                cropRect.Left,
                cropRect.Right,
                cropRect.Top,
                cropRect.Bottom,
                flipX,
                flipY);

            // Enforce that dequeueBuffer wait for the next vblank
            _vblankFence.NvFences[0].Value++;

            TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation
            {
                Layer = layer,
                Item  = item,
                Fence = _vblankFence
            };

            _device.Gpu.Window.EnqueueFrameThreadSafe(
                frameBufferAddress,
                frameBufferWidth,
                frameBufferHeight,
                0,
                false,
                gobBlocksInY,
                format,
                bytesPerPixel,
                crop,
                AcquireBuffer,
                ReleaseBuffer,
                textureCallbackInformation);
        }
Beispiel #8
0
        private static int MapBufferEx(ServiceCtx Context)
        {
            const string MapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!";

            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

            NvGpuASMapBufferEx Args = AMemoryHelper.Read <NvGpuASMapBufferEx>(Context.Memory, InputPosition);

            NvGpuASCtx ASCtx = GetASCtx(Context);

            NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle);

            if (Map == null)
            {
                Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!");

                return(NvResult.InvalidInput);
            }

            long PA;

            if ((Args.Flags & FlagRemapSubRange) != 0)
            {
                lock (ASCtx)
                {
                    if (ASCtx.TryGetMapPhysicalAddress(Args.Offset, out PA))
                    {
                        long VA = Args.Offset + Args.BufferOffset;

                        PA += Args.BufferOffset;

                        if (ASCtx.Vmm.Map(PA, VA, Args.MappingSize) < 0)
                        {
                            string Msg = string.Format(MapErrorMsg, VA, Args.MappingSize);

                            Context.Ns.Log.PrintWarning(LogClass.ServiceNv, Msg);

                            return(NvResult.InvalidInput);
                        }

                        return(NvResult.Success);
                    }
                    else
                    {
                        Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Address 0x{Args.Offset:x16} not mapped!");

                        return(NvResult.InvalidInput);
                    }
                }
            }

            PA = Map.Address + Args.BufferOffset;

            long Size = Args.MappingSize;

            if (Size == 0)
            {
                Size = (uint)Map.Size;
            }

            int Result = NvResult.Success;

            lock (ASCtx)
            {
                //Note: When the fixed offset flag is not set,
                //the Offset field holds the alignment size instead.
                bool VaAllocated = (Args.Flags & FlagFixedOffset) == 0;

                if (!VaAllocated)
                {
                    if (ASCtx.ValidateFixedBuffer(Args.Offset, Size))
                    {
                        Args.Offset = ASCtx.Vmm.Map(PA, Args.Offset, Size);
                    }
                    else
                    {
                        string Msg = string.Format(MapErrorMsg, Args.Offset, Size);

                        Context.Ns.Log.PrintWarning(LogClass.ServiceNv, Msg);

                        Result = NvResult.InvalidInput;
                    }
                }
                else
                {
                    Args.Offset = ASCtx.Vmm.Map(PA, Size);
                }

                if (Args.Offset < 0)
                {
                    Args.Offset = 0;

                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{Size:x16}!");

                    Result = NvResult.InvalidInput;
                }
                else
                {
                    ASCtx.AddMap(Args.Offset, Size, PA, VaAllocated);
                }
            }

            AMemoryHelper.Write(Context.Memory, OutputPosition, Args);

            return(Result);
        }
Beispiel #9
0
        private static int MapBufferEx(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

            NvGpuASMapBufferEx Args = AMemoryHelper.Read <NvGpuASMapBufferEx>(Context.Memory, InputPosition);

            NvGpuVmm Vmm = GetVmm(Context);

            NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle);

            if (Map == null)
            {
                Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!");

                return(NvResult.InvalidInput);
            }

            long PA = Map.Address + Args.BufferOffset;

            long Size = Args.MappingSize;

            if (Size == 0)
            {
                Size = (uint)Map.Size;
            }

            int Result = NvResult.Success;

            //Note: When the fixed offset flag is not set,
            //the Offset field holds the alignment size instead.
            if ((Args.Flags & FlagFixedOffset) != 0)
            {
                long MapEnd = Args.Offset + Args.MappingSize;

                if ((ulong)MapEnd <= (ulong)Args.Offset)
                {
                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} and size 0x{Args.MappingSize:x16} results in a overflow!");

                    return(NvResult.InvalidInput);
                }

                if ((Args.Offset & NvGpuVmm.PageMask) != 0)
                {
                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} is not page aligned!");

                    return(NvResult.InvalidInput);
                }

                Args.Offset = Vmm.Map(PA, Args.Offset, Size);
            }
            else
            {
                Args.Offset = Vmm.Map(PA, Size);

                if (Args.Offset < 0)
                {
                    Args.Offset = 0;

                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"No memory to map size {Args.MappingSize:x16}!");

                    Result = NvResult.InvalidInput;
                }
            }

            AMemoryHelper.Write(Context.Memory, OutputPosition, Args);

            return(Result);
        }
Beispiel #10
0
        private static int MapBufferEx(ServiceCtx context)
        {
            const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!";

            long inputPosition  = context.Request.GetBufferType0x21().Position;
            long outputPosition = context.Request.GetBufferType0x22().Position;

            NvGpuASMapBufferEx args = MemoryHelper.Read <NvGpuASMapBufferEx>(context.Memory, inputPosition);

            NvGpuASCtx asCtx = GetASCtx(context);

            NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle);

            if (map == null)
            {
                Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!");

                return(NvResult.InvalidInput);
            }

            long pa;

            if ((args.Flags & FlagRemapSubRange) != 0)
            {
                lock (asCtx)
                {
                    if (asCtx.TryGetMapPhysicalAddress(args.Offset, out pa))
                    {
                        long va = args.Offset + args.BufferOffset;

                        pa += args.BufferOffset;

                        if (asCtx.Vmm.Map(pa, va, args.MappingSize) < 0)
                        {
                            string msg = string.Format(mapErrorMsg, va, args.MappingSize);

                            Logger.PrintWarning(LogClass.ServiceNv, msg);

                            return(NvResult.InvalidInput);
                        }

                        return(NvResult.Success);
                    }
                    else
                    {
                        Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{args.Offset:x16} not mapped!");

                        return(NvResult.InvalidInput);
                    }
                }
            }

            pa = map.Address + args.BufferOffset;

            long size = args.MappingSize;

            if (size == 0)
            {
                size = (uint)map.Size;
            }

            int result = NvResult.Success;

            lock (asCtx)
            {
                // Note: When the fixed offset flag is not set,
                // the Offset field holds the alignment size instead.
                bool vaAllocated = (args.Flags & FlagFixedOffset) == 0;

                if (!vaAllocated)
                {
                    if (asCtx.ValidateFixedBuffer(args.Offset, size))
                    {
                        args.Offset = asCtx.Vmm.Map(pa, args.Offset, size);
                    }
                    else
                    {
                        string msg = string.Format(mapErrorMsg, args.Offset, size);

                        Logger.PrintWarning(LogClass.ServiceNv, msg);

                        result = NvResult.InvalidInput;
                    }
                }
                else
                {
                    args.Offset = asCtx.Vmm.Map(pa, size);
                }

                if (args.Offset < 0)
                {
                    args.Offset = 0;

                    Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!");

                    result = NvResult.InvalidInput;
                }
                else
                {
                    asCtx.AddMap(args.Offset, size, pa, vaAllocated);
                }
            }

            MemoryHelper.Write(context.Memory, outputPosition, args);

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