예제 #1
0
        private static int Remap(ServiceCtx Context, int Cmd)
        {
            int Count = ((Cmd >> 16) & 0xff) / 0x14;

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

            for (int Index = 0; Index < Count; Index++, InputPosition += 0x14)
            {
                NvGpuASRemap Args = AMemoryHelper.Read <NvGpuASRemap>(Context.Memory, InputPosition);

                NvGpuVmm Vmm = GetASCtx(Context).Vmm;

                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 Result = Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16,
                                      (long)(uint)Args.Pages << 16);

                if (Result < 0)
                {
                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv,
                                                $"Page 0x{Args.Offset:x16} size 0x{Args.Pages:x16} not allocated!");

                    return(NvResult.InvalidInput);
                }
            }

            return(NvResult.Success);
        }
예제 #2
0
        private static int SyncptReadMinOrMax(ServiceCtx Context, bool Max)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
            {
                return(NvResult.InvalidInput);
            }

            if (Max)
            {
                Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id);
            }
            else
            {
                Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id);
            }

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

            return(NvResult.Success);
        }
예제 #3
0
        private static int UnmapBuffer(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuASCtx ASCtx = GetASCtx(Context);

            lock (ASCtx)
            {
                if (ASCtx.RemoveMap(Args.Offset, out long Size))
                {
                    if (Size != 0)
                    {
                        ASCtx.Vmm.Free(Args.Offset, Size);
                    }
                }
                else
                {
                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!");
                }
            }

            return(NvResult.Success);
        }
예제 #4
0
        private static int SubmitGpfifo(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21Position();
            long OutputPosition = Context.Request.GetBufferType0x22Position();

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

            NvGpuVmm Vmm = NvGpuASIoctl.GetVmm(Context);

            for (int Index = 0; Index < Args.NumEntries; Index++)
            {
                long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8);

                long VA = Gpfifo & 0xff_ffff_ffff;

                int Size = (int)(Gpfifo >> 40) & 0x7ffffc;

                byte[] Data = Vmm.ReadBytes(VA, Size);

                NvGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data);

                Context.Ns.Gpu.Fifo.PushBuffer(Vmm, PushBuffer);
            }

            Args.SyncptId    = 0;
            Args.SyncptValue = 0;

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

            return(NvResult.Success);
        }
예제 #5
0
        private static int FreeSpace(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuASCtx ASCtx = GetASCtx(Context);

            int Result = NvResult.Success;

            lock (ASCtx)
            {
                ulong Size = (ulong)Args.Pages *
                             (ulong)Args.PageSize;

                if (ASCtx.RemoveReservation(Args.Offset))
                {
                    ASCtx.Vmm.Free(Args.Offset, (long)Size);
                }
                else
                {
                    Context.Ns.Log.PrintWarning(LogClass.ServiceNv,
                                                $"Failed to free offset 0x{Args.Offset:x16} size 0x{Size:x16}!");

                    Result = NvResult.InvalidInput;
                }
            }

            return(Result);
        }
예제 #6
0
        public T Read <T>() where T : struct
        {
            T Value = AMemoryHelper.Read <T>(Memory, Position);

            Position += Marshal.SizeOf <T>();

            return(Value);
        }
예제 #7
0
        private static int GetCharacteristics(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21Position();
            long OutputPosition = Context.Request.GetBufferType0x22Position();

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

            Args.BufferSize = 0xa0;

            Args.Arch                   = 0x120;
            Args.Impl                   = 0xb;
            Args.Rev                    = 0xa1;
            Args.NumGpc                 = 0x1;
            Args.L2CacheSize            = 0x40000;
            Args.OnBoardVideoMemorySize = 0x0;
            Args.NumTpcPerGpc           = 0x2;
            Args.BusType                = 0x20;
            Args.BigPageSize            = 0x20000;
            Args.CompressionPageSize    = 0x20000;
            Args.PdeCoverageBitCount    = 0x1b;
            Args.AvailableBigPageSizes  = 0x30000;
            Args.GpcMask                = 0x1;
            Args.SmArchSmVersion        = 0x503;
            Args.SmArchSpaVersion       = 0x503;
            Args.SmArchWarpCount        = 0x80;
            Args.GpuVaBitCount          = 0x28;
            Args.Reserved               = 0x0;
            Args.Flags                  = 0x55;
            Args.TwodClass              = 0x902d;
            Args.ThreedClass            = 0xb197;
            Args.ComputeClass           = 0xb1c0;
            Args.GpfifoClass            = 0xb06f;
            Args.InlineToMemoryClass    = 0xa140;
            Args.DmaCopyClass           = 0xb0b5;
            Args.MaxFbpsCount           = 0x1;
            Args.FbpEnMask              = 0x0;
            Args.MaxLtcPerFbp           = 0x2;
            Args.MaxLtsPerLtc           = 0x1;
            Args.MaxTexPerTpc           = 0x0;
            Args.MaxGpcCount            = 0x1;
            Args.RopL2EnMask0           = 0x21d70;
            Args.RopL2EnMask1           = 0x0;
            Args.ChipName               = 0x6230326d67;
            Args.GrCompbitStoreBaseHw   = 0x0;

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

            return(NvResult.Success);
        }
예제 #8
0
        private static int GetTpcMasks(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21Position();
            long OutputPosition = Context.Request.GetBufferType0x22Position();

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

            if (Args.MaskBufferSize != 0)
            {
                Args.TpcMask = 3;
            }

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

            return(NvResult.Success);
        }
예제 #9
0
파일: IAudioOut.cs 프로젝트: cin619/Ryujinx
        public long AppendAudioOutBufferImpl(ServiceCtx Context, long Position)
        {
            long Tag = Context.RequestData.ReadInt64();

            AudioOutData Data = AMemoryHelper.Read <AudioOutData>(
                Context.Memory,
                Position);

            byte[] Buffer = Context.Memory.ReadBytes(
                Data.SampleBufferPtr,
                Data.SampleBufferSize);

            AudioOut.AppendBuffer(Track, Tag, Buffer);

            return(0);
        }
예제 #10
0
        private static int FreeSpace(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuVmm Vmm = GetVmm(Context);

            ulong Size = (ulong)Args.Pages *
                         (ulong)Args.PageSize;

            Vmm.Free(Args.Offset, (long)Size);

            return(NvResult.Success);
        }
예제 #11
0
        private static int UnmapBuffer(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuVmm Vmm = GetVmm(Context);

            if (!Vmm.Unmap(Args.Offset))
            {
                Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!");
            }

            return(NvResult.Success);
        }
예제 #12
0
        public T[] Read <T>(int Size) where T : struct
        {
            int StructSize = Marshal.SizeOf <T>();

            int Count = Size / StructSize;

            T[] Output = new T[Count];

            for (int Index = 0; Index < Count; Index++)
            {
                Output[Index] = AMemoryHelper.Read <T>(Memory, Position);

                Position += StructSize;
            }

            return(Output);
        }
예제 #13
0
        private static int AllocSpace(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuASCtx ASCtx = GetASCtx(Context);

            ulong Size = (ulong)Args.Pages *
                         (ulong)Args.PageSize;

            int Result = NvResult.Success;

            lock (ASCtx)
            {
                //Note: When the fixed offset flag is not set,
                //the Offset field holds the alignment size instead.
                if ((Args.Flags & FlagFixedOffset) != 0)
                {
                    Args.Offset = ASCtx.Vmm.ReserveFixed(Args.Offset, (long)Size);
                }
                else
                {
                    Args.Offset = ASCtx.Vmm.Reserve((long)Size, Args.Offset);
                }

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

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

                    Result = NvResult.OutOfMemory;
                }
                else
                {
                    ASCtx.AddReservation(Args.Offset, (long)Size);
                }
            }

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

            return(Result);
        }
예제 #14
0
        private static int GetId(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvMapHandle Map = GetNvMap(Context, Args.Handle);

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

                return(NvResult.InvalidInput);
            }

            Args.Id = Args.Handle;

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

            return(NvResult.Success);
        }
예제 #15
0
        private static int Free(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvMapHandle Map = GetNvMap(Context, Args.Handle);

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

                return(NvResult.InvalidInput);
            }

            long OldRefCount = Map.DecrementRefCount();

            if (OldRefCount <= 1)
            {
                DeleteNvMap(Context, Args.Handle);

                Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!");

                Args.Flags = 0;
            }
            else
            {
                Args.Flags = FlagNotFreedYet;
            }

            Args.RefCount = OldRefCount;
            Args.Size     = Map.Size;

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

            return(NvResult.Success);
        }
예제 #16
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);
        }
예제 #17
0
        private static int SubmitGpfifo(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;;

            for (int Index = 0; Index < Args.NumEntries; Index++)
            {
                long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8);

                PushGpfifo(Context, Vmm, Gpfifo);
            }

            Args.SyncptId    = 0;
            Args.SyncptValue = 0;

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

            return(NvResult.Success);
        }
예제 #18
0
        private static int Param(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvMapHandle Map = GetNvMap(Context, Args.Handle);

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

                return(NvResult.InvalidInput);
            }

            switch ((NvMapHandleParam)Args.Param)
            {
            case NvMapHandleParam.Size:  Args.Result = Map.Size;   break;

            case NvMapHandleParam.Align: Args.Result = Map.Align;  break;

            case NvMapHandleParam.Heap:  Args.Result = 0x40000000; break;

            case NvMapHandleParam.Kind:  Args.Result = Map.Kind;   break;

            case NvMapHandleParam.Compr: Args.Result = 0;          break;

            //Note: Base is not supported and returns an error.
            //Any other value also returns an error.
            default: return(NvResult.InvalidInput);
            }

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

            return(NvResult.Success);
        }
예제 #19
0
        private static int AllocSpace(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvGpuVmm Vmm = GetVmm(Context);

            ulong Size = (ulong)Args.Pages *
                         (ulong)Args.PageSize;

            if ((Args.Flags & FlagFixedOffset) != 0)
            {
                Args.Offset = Vmm.Reserve(Args.Offset, (long)Size, 1);
            }
            else
            {
                Args.Offset = Vmm.Reserve((long)Size, 1);
            }

            int Result = NvResult.Success;

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

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

                Result = NvResult.OutOfMemory;
            }

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

            return(Result);
        }
예제 #20
0
        private static int FromId(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21Position();
            long OutputPosition = Context.Request.GetBufferType0x22Position();

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

            NvMapHandle Map = GetNvMap(Context, Args.Id);

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

                return(NvResult.InvalidInput);
            }

            Map.IncrementRefCount();

            Args.Handle = Args.Id;

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

            return(NvResult.Success);
        }
예제 #21
0
        private static int Create(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            if (Args.Size == 0)
            {
                Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!");

                return(NvResult.InvalidInput);
            }

            int Size = IntUtils.AlignUp(Args.Size, NvGpuVmm.PageSize);

            Args.Handle = AddNvMap(Context, new NvMapHandle(Size));

            Context.Ns.Log.PrintInfo(LogClass.ServiceNv, $"Created map {Args.Handle} with size 0x{Size:x8}!");

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

            return(NvResult.Success);
        }
예제 #22
0
        public long RequestUpdateAudioRenderer(ServiceCtx Context)
        {
            long OutputPosition = Context.Request.ReceiveBuff[0].Position;
            long OutputSize     = Context.Request.ReceiveBuff[0].Size;

            AMemoryHelper.FillWithZeros(Context.Memory, OutputPosition, (int)OutputSize);

            long InputPosition = Context.Request.SendBuff[0].Position;

            UpdateDataHeader InputDataHeader = AMemoryHelper.Read <UpdateDataHeader>(Context.Memory, InputPosition);

            UpdateDataHeader OutputDataHeader = new UpdateDataHeader();

            int UpdateHeaderSize = Marshal.SizeOf <UpdateDataHeader>();

            OutputDataHeader.Revision               = Params.Revision;
            OutputDataHeader.BehaviorSize           = 0xb0;
            OutputDataHeader.MemoryPoolsSize        = (Params.EffectCount + Params.VoiceCount * 4) * 0x10;
            OutputDataHeader.VoicesSize             = Params.VoiceCount * 0x10;
            OutputDataHeader.EffectsSize            = Params.EffectCount * 0x10;
            OutputDataHeader.SinksSize              = Params.SinkCount * 0x20;
            OutputDataHeader.PerformanceManagerSize = 0x10;
            OutputDataHeader.TotalSize              = UpdateHeaderSize +
                                                      OutputDataHeader.BehaviorSize +
                                                      OutputDataHeader.MemoryPoolsSize +
                                                      OutputDataHeader.VoicesSize +
                                                      OutputDataHeader.EffectsSize +
                                                      OutputDataHeader.SinksSize +
                                                      OutputDataHeader.PerformanceManagerSize;

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

            int InMemoryPoolOffset = UpdateHeaderSize + InputDataHeader.BehaviorSize;

            int OutMemoryPoolOffset = UpdateHeaderSize;

            for (int Offset = 0; Offset < OutputDataHeader.MemoryPoolsSize; Offset += 0x10, InMemoryPoolOffset += 0x20)
            {
                MemoryPoolState PoolState = (MemoryPoolState)Context.Memory.ReadInt32(InputPosition + InMemoryPoolOffset + 0x10);

                //TODO: Figure out what the other values does.
                if (PoolState == MemoryPoolState.RequestAttach)
                {
                    Context.Memory.WriteInt32(OutputPosition + OutMemoryPoolOffset + Offset, (int)MemoryPoolState.Attached);
                }
                else if (PoolState == MemoryPoolState.RequestDetach)
                {
                    Context.Memory.WriteInt32(OutputPosition + OutMemoryPoolOffset + Offset, (int)MemoryPoolState.Detached);
                }
            }

            int OutVoicesOffset = OutMemoryPoolOffset + OutputDataHeader.MemoryPoolsSize;

            for (int Offset = 0; Offset < OutputDataHeader.VoicesSize; Offset += 0x10)
            {
                Context.Memory.WriteInt32(OutputPosition + OutVoicesOffset + Offset + 8, (int)VoicePlaybackState.Finished);
            }

            //TODO: We shouldn't be signaling this here.
            UpdateEvent.WaitEvent.Set();

            return(0);
        }
예제 #23
0
        private static int SyncptWait(ServiceCtx Context, bool Extended)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt;

            if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
            {
                return(NvResult.InvalidInput);
            }

            int Result;

            if (Syncpt.MinCompare(Args.Id, Args.Thresh))
            {
                Result = NvResult.Success;
            }
            else if (Args.Timeout == 0)
            {
                Result = NvResult.TryAgain;
            }
            else
            {
                Logger.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + Args.Timeout + "ms...");

                using (ManualResetEvent WaitEvent = new ManualResetEvent(false))
                {
                    Syncpt.AddWaiter(Args.Thresh, WaitEvent);

                    //Note: Negative (> INT_MAX) timeouts aren't valid on .NET,
                    //in this case we just use the maximum timeout possible.
                    int Timeout = Args.Timeout;

                    if (Timeout < -1)
                    {
                        Timeout = int.MaxValue;
                    }

                    if (Timeout == -1)
                    {
                        WaitEvent.WaitOne();

                        Result = NvResult.Success;
                    }
                    else if (WaitEvent.WaitOne(Timeout))
                    {
                        Result = NvResult.Success;
                    }
                    else
                    {
                        Result = NvResult.TimedOut;
                    }
                }

                Logger.PrintDebug(LogClass.ServiceNv, "Resuming...");
            }

            if (Extended)
            {
                Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id));
            }

            return(Result);
        }
예제 #24
0
        private static int EventWait(ServiceCtx Context, bool Async)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
            {
                return(NvResult.InvalidInput);
            }

            void WriteArgs()
            {
                AMemoryHelper.Write(Context.Memory, OutputPosition, Args);
            }

            NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt;

            if (Syncpt.MinCompare(Args.Id, Args.Thresh))
            {
                Args.Value = Syncpt.GetMin(Args.Id);

                WriteArgs();

                return(NvResult.Success);
            }

            if (!Async)
            {
                Args.Value = 0;
            }

            if (Args.Timeout == 0)
            {
                WriteArgs();

                return(NvResult.TryAgain);
            }

            NvHostEvent Event;

            int Result, EventIndex;

            if (Async)
            {
                EventIndex = Args.Value;

                if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount)
                {
                    return(NvResult.InvalidInput);
                }

                Event = GetUserCtx(Context).Events[EventIndex];
            }
            else
            {
                Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex);
            }

            if (Event != null &&
                (Event.State == NvHostEventState.Registered ||
                 Event.State == NvHostEventState.Free))
            {
                Event.Id     = Args.Id;
                Event.Thresh = Args.Thresh;

                Event.State = NvHostEventState.Waiting;

                if (!Async)
                {
                    Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000;
                }
                else
                {
                    Args.Value = Args.Id << 4;
                }

                Args.Value |= EventIndex;

                Result = NvResult.TryAgain;
            }
            else
            {
                Result = NvResult.InvalidInput;
            }

            WriteArgs();

            return(Result);
        }
예제 #25
0
        private static int Alloc(ServiceCtx Context)
        {
            long InputPosition  = Context.Request.GetBufferType0x21().Position;
            long OutputPosition = Context.Request.GetBufferType0x22().Position;

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

            NvMapHandle Map = GetNvMap(Context, Args.Handle);

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

                return(NvResult.InvalidInput);
            }

            if ((Args.Align & (Args.Align - 1)) != 0)
            {
                Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{Args.Align:x8}!");

                return(NvResult.InvalidInput);
            }

            if ((uint)Args.Align < NvGpuVmm.PageSize)
            {
                Args.Align = NvGpuVmm.PageSize;
            }

            int Result = NvResult.Success;

            if (!Map.Allocated)
            {
                Map.Allocated = true;

                Map.Align = Args.Align;
                Map.Kind  = (byte)Args.Kind;

                int Size = IntUtils.AlignUp(Map.Size, NvGpuVmm.PageSize);

                long Address = Args.Address;

                if (Address == 0)
                {
                    //When the address is zero, we need to allocate
                    //our own backing memory for the NvMap.
                    if (!Context.Ns.Os.Allocator.TryAllocate((uint)Size, out Address))
                    {
                        Result = NvResult.OutOfMemory;
                    }
                }

                if (Result == NvResult.Success)
                {
                    Map.Size    = Size;
                    Map.Address = Address;
                }
            }

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

            return(Result);
        }
예제 #26
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);
        }
예제 #27
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);
        }