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); }
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); }
private static int ZcullGetCtxSize(ServiceCtx Context) { long OutputPosition = Context.Request.GetBufferType0x22Position(); NvGpuGpuZcullGetCtxSize Args = new NvGpuGpuZcullGetCtxSize(); Args.Size = 1; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); return(NvResult.Success); }
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); }
private static int GetActiveSlotMask(ServiceCtx Context) { long OutputPosition = Context.Request.GetBufferType0x22Position(); NvGpuGpuGetActiveSlotMask Args = new NvGpuGpuGetActiveSlotMask(); Args.Slot = 0x07; Args.Mask = 0x01; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); return(NvResult.Success); }
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); }
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); }
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); }
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); }
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); }
private static int ZcullGetInfo(ServiceCtx Context) { long OutputPosition = Context.Request.GetBufferType0x22Position(); NvGpuGpuZcullGetInfo Args = new NvGpuGpuZcullGetInfo(); Args.WidthAlignPixels = 0x20; Args.HeightAlignPixels = 0x20; Args.PixelSquaresByAliquots = 0x400; Args.AliquotTotal = 0x800; Args.RegionByteMultiplier = 0x20; Args.RegionHeaderSize = 0x20; Args.SubregionHeaderSize = 0xc0; Args.SubregionWidthAlignPixels = 0x20; Args.SubregionHeightAlignPixels = 0x40; Args.SubregionCount = 0x10; AMemoryHelper.Write(Context.Memory, OutputPosition, Args); Context.Ns.Log.PrintStub(LogClass.ServiceNv, "Stubbed."); return(NvResult.Success); }
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); }
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); }
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); }
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); }
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); }
public void Write <T>(T Value) where T : struct { AMemoryHelper.Write(Memory, Position, Value); Position += Marshal.SizeOf <T>(); }
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); }
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); }
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); }
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); }