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); }
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); }