Fix remap when handle is 0 (#1882)

* Nvservices cleanup and attempt to fix remap

* Unmap if remap handle is 0

* Remove mapped pool add from Remap
This commit is contained in:
gdkchan 2021-01-09 20:11:31 -03:00 committed by GitHub
parent 71e2a00221
commit 8e0a421264
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 117 deletions

View file

@ -129,11 +129,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
/// <summary> /// <summary>
/// Frees memory that was previously allocated by a map or reserved. /// Unmaps a given range of pages at the specified GPU virtual memory region.
/// </summary> /// </summary>
/// <param name="va">GPU virtual address to free</param> /// <param name="va">GPU virtual address to unmap</param>
/// <param name="size">Size in bytes of the region being freed</param> /// <param name="size">Size in bytes of the region being unmapped</param>
public void Free(ulong va, ulong size) public void Unmap(ulong va, ulong size)
{ {
lock (_pageTable) lock (_pageTable)
{ {

View file

@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
{ {
public Condition Condition { get; } public Condition Condition { get; }
public new static OpCode Create(InstEmitter emitter, ulong address, long opCode) => new OpCodeExit(emitter, address, opCode); public new static OpCode Create(InstEmitter emitter, ulong address, long opCode) => new OpCodeConditional(emitter, address, opCode);
public OpCodeConditional(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) public OpCodeConditional(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
{ {

View file

@ -1,5 +1,4 @@
using Ryujinx.Common.Collections; using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
@ -123,7 +122,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
arguments.Offset = address; arguments.Offset = address;
} }
if (arguments.Offset < 0) if (arguments.Offset == NvMemoryAllocator.PteUnmapped)
{ {
arguments.Offset = 0; arguments.Offset = 0;
@ -153,7 +152,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
if (addressSpaceContext.RemoveReservation(arguments.Offset)) if (addressSpaceContext.RemoveReservation(arguments.Offset))
{ {
_memoryAllocator.DeallocateRange(arguments.Offset, size); _memoryAllocator.DeallocateRange(arguments.Offset, size);
addressSpaceContext.Gmm.Free(arguments.Offset, size); addressSpaceContext.Gmm.Unmap(arguments.Offset, size);
} }
else else
{ {
@ -178,7 +177,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
if (size != 0) if (size != 0)
{ {
_memoryAllocator.DeallocateRange(arguments.Offset, size); _memoryAllocator.DeallocateRange(arguments.Offset, size);
addressSpaceContext.Gmm.Free(arguments.Offset, size); addressSpaceContext.Gmm.Unmap(arguments.Offset, size);
} }
} }
else else
@ -196,22 +195,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context); AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle, true);
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;
}
ulong physicalAddress; ulong physicalAddress;
if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0) if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0)
@ -225,15 +208,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
physicalAddress += arguments.BufferOffset; physicalAddress += arguments.BufferOffset;
addressSpaceContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize); addressSpaceContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize);
if (virtualAddress < 0)
{
string message = string.Format(mapErrorMsg, virtualAddress, arguments.MappingSize, pageSize);
Logger.Warning?.Print(LogClass.ServiceNv, message);
return NvInternalResult.InvalidInput;
}
return NvInternalResult.Success; return NvInternalResult.Success;
} }
else else
@ -245,6 +219,22 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
} }
} }
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; physicalAddress = map.Address + arguments.BufferOffset;
ulong size = arguments.MappingSize; ulong size = arguments.MappingSize;
@ -289,7 +279,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
arguments.Offset = va; arguments.Offset = va;
} }
if (arguments.Offset < 0) if (arguments.Offset == NvMemoryAllocator.PteUnmapped)
{ {
arguments.Offset = 0; arguments.Offset = 0;
@ -322,32 +312,32 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
private NvInternalResult Remap(Span<RemapArguments> arguments) private NvInternalResult Remap(Span<RemapArguments> arguments)
{ {
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
for (int index = 0; index < arguments.Length; index++) for (int index = 0; index < arguments.Length; index++)
{ {
MemoryManager gmm = GetAddressSpaceContext(Context).Gmm; MemoryManager gmm = GetAddressSpaceContext(Context).Gmm;
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments[index].NvMapHandle, true); ulong mapOffs = (ulong)arguments[index].MapOffset << 16;
ulong gpuVa = (ulong)arguments[index].GpuOffset << 16;
ulong size = (ulong)arguments[index].Pages << 16;
if (map == null) if (arguments[index].NvMapHandle == 0)
{ {
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments[index].NvMapHandle:x8}!"); gmm.Unmap(gpuVa, size);
return NvInternalResult.InvalidInput;
} }
else
ulong shiftedGpuOffset = ((ulong)arguments[index].GpuOffset << 16);
gmm.Map(
((ulong)arguments[index].MapOffset << 16) + map.Address,
shiftedGpuOffset,
(ulong)arguments[index].Pages << 16);
if (shiftedGpuOffset < 0)
{ {
Logger.Warning?.Print(LogClass.ServiceNv, NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments[index].NvMapHandle);
$"Page 0x{arguments[index].GpuOffset:x16} size 0x{arguments[index].Pages:x16} not allocated!");
return NvInternalResult.InvalidInput; if (map == null)
{
Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments[index].NvMapHandle:x8}!");
return NvInternalResult.InvalidInput;
}
gmm.Map(mapOffs + map.Address, gpuVa, size);
} }
} }

View file

@ -1,6 +1,4 @@
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
@ -9,37 +7,33 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
{ {
private class Range private class Range
{ {
public ulong Start { get; private set; } public ulong Start { get; }
public ulong End { get; private set; } public ulong End { get; }
public Range(ulong position, ulong size) public Range(ulong address, ulong size)
{ {
Start = position; Start = address;
End = size + Start; End = size + Start;
} }
} }
private class MappedMemory : Range private class MappedMemory : Range
{ {
public ulong PhysicalAddress { get; private set; } public ulong PhysicalAddress { get; }
public bool VaAllocated { get; private set; } public bool VaAllocated { get; }
public MappedMemory( public MappedMemory(ulong address, ulong size, ulong physicalAddress, bool vaAllocated) : base(address, size)
ulong position,
ulong size,
ulong physicalAddress,
bool vaAllocated) : base(position, size)
{ {
PhysicalAddress = physicalAddress; PhysicalAddress = physicalAddress;
VaAllocated = vaAllocated; VaAllocated = vaAllocated;
} }
} }
private SortedList<ulong, Range> _maps;
private SortedList<ulong, Range> _reservations;
public MemoryManager Gmm { get; } public MemoryManager Gmm { get; }
private readonly SortedList<ulong, Range> _maps;
private readonly SortedList<ulong, Range> _reservations;
public AddressSpaceContext(ServiceCtx context) public AddressSpaceContext(ServiceCtx context)
{ {
Gmm = context.Device.Gpu.MemoryManager; Gmm = context.Device.Gpu.MemoryManager;
@ -48,24 +42,24 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
_reservations = new SortedList<ulong, Range>(); _reservations = new SortedList<ulong, Range>();
} }
public bool ValidateFixedBuffer(ulong position, ulong size, ulong alignment) public bool ValidateFixedBuffer(ulong address, ulong size, ulong alignment)
{ {
ulong mapEnd = position + size; ulong mapEnd = address + size;
// Check if size is valid (0 is also not allowed). // Check if size is valid (0 is also not allowed).
if (mapEnd <= position) if (mapEnd <= address)
{ {
return false; return false;
} }
// Check if address is aligned. // Check if address is aligned.
if ((position & (alignment - 1)) != 0) if ((address & (alignment - 1)) != 0)
{ {
return false; return false;
} }
// Check if region is reserved. // Check if region is reserved.
if (BinarySearch(_reservations, position) == null) if (BinarySearch(_reservations, address) == null)
{ {
return false; return false;
} }
@ -73,7 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
// Check for overlap with already mapped buffers. // Check for overlap with already mapped buffers.
Range map = BinarySearchLt(_maps, mapEnd); Range map = BinarySearchLt(_maps, mapEnd);
if (map != null && map.End > position) if (map != null && map.End > address)
{ {
return false; return false;
} }
@ -81,20 +75,16 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
return true; return true;
} }
public void AddMap( public void AddMap(ulong gpuVa, ulong size, ulong physicalAddress, bool vaAllocated)
ulong position,
ulong size,
ulong physicalAddress,
bool vaAllocated)
{ {
_maps.Add(position, new MappedMemory(position, size, physicalAddress, vaAllocated)); _maps.Add(gpuVa, new MappedMemory(gpuVa, size, physicalAddress, vaAllocated));
} }
public bool RemoveMap(ulong position, out ulong size) public bool RemoveMap(ulong gpuVa, out ulong size)
{ {
size = 0; size = 0;
if (_maps.Remove(position, out Range value)) if (_maps.Remove(gpuVa, out Range value))
{ {
MappedMemory map = (MappedMemory)value; MappedMemory map = (MappedMemory)value;
@ -109,36 +99,34 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
return false; return false;
} }
public bool TryGetMapPhysicalAddress(ulong position, out ulong physicalAddress) public bool TryGetMapPhysicalAddress(ulong gpuVa, out ulong physicalAddress)
{ {
Range map = BinarySearch(_maps, position); Range map = BinarySearch(_maps, gpuVa);
if (map != null) if (map != null)
{ {
physicalAddress = ((MappedMemory)map).PhysicalAddress; physicalAddress = ((MappedMemory)map).PhysicalAddress;
return true; return true;
} }
physicalAddress = 0; physicalAddress = 0;
return false; return false;
} }
public void AddReservation(ulong position, ulong size) public void AddReservation(ulong gpuVa, ulong size)
{ {
_reservations.Add(position, new Range(position, size)); _reservations.Add(gpuVa, new Range(gpuVa, size));
} }
public bool RemoveReservation(ulong position) public bool RemoveReservation(ulong gpuVa)
{ {
return _reservations.Remove(position); return _reservations.Remove(gpuVa);
} }
private Range BinarySearch(SortedList<ulong, Range> lst, ulong position) private Range BinarySearch(SortedList<ulong, Range> list, ulong address)
{ {
int left = 0; int left = 0;
int right = lst.Count - 1; int right = list.Count - 1;
while (left <= right) while (left <= right)
{ {
@ -146,14 +134,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
int middle = left + (size >> 1); int middle = left + (size >> 1);
Range rg = lst.Values[middle]; Range rg = list.Values[middle];
if (position >= rg.Start && position < rg.End) if (address >= rg.Start && address < rg.End)
{ {
return rg; return rg;
} }
if (position < rg.Start) if (address < rg.Start)
{ {
right = middle - 1; right = middle - 1;
} }
@ -166,12 +154,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
return null; return null;
} }
private Range BinarySearchLt(SortedList<ulong, Range> lst, ulong position) private Range BinarySearchLt(SortedList<ulong, Range> list, ulong address)
{ {
Range ltRg = null; Range ltRg = null;
int left = 0; int left = 0;
int right = lst.Count - 1; int right = list.Count - 1;
while (left <= right) while (left <= right)
{ {
@ -179,9 +167,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
int middle = left + (size >> 1); int middle = left + (size >> 1);
Range rg = lst.Values[middle]; Range rg = list.Values[middle];
if (position < rg.Start) if (address < rg.Start)
{ {
right = middle - 1; right = middle - 1;
} }
@ -189,7 +177,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
{ {
left = middle + 1; left = middle + 1;
if (position > rg.Start) if (address > rg.Start)
{ {
ltRg = rg; ltRg = rg;
} }

View file

@ -232,14 +232,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
private int CreateHandleFromMap(NvMapHandle map) private int CreateHandleFromMap(NvMapHandle map)
{ {
IdDictionary dict = _maps.GetOrAdd(Owner, (key) => IdDictionary dict = _maps.GetOrAdd(Owner, (key) => new IdDictionary());
{
IdDictionary newDict = new IdDictionary();
newDict.Add(0, new NvMapHandle());
return newDict;
});
return dict.Add(map); return dict.Add(map);
} }
@ -254,14 +247,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
return false; return false;
} }
public static void IncrementMapRefCount(long pid, int handle, bool allowHandleZero = false) public static void IncrementMapRefCount(long pid, int handle)
{ {
GetMapFromHandle(pid, handle, allowHandleZero)?.IncrementRefCount(); GetMapFromHandle(pid, handle)?.IncrementRefCount();
} }
public static bool DecrementMapRefCount(long pid, int handle) public static bool DecrementMapRefCount(long pid, int handle)
{ {
NvMapHandle map = GetMapFromHandle(pid, handle, false); NvMapHandle map = GetMapFromHandle(pid, handle);
if (map == null) if (map == null)
{ {
@ -282,9 +275,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
} }
} }
public static NvMapHandle GetMapFromHandle(long pid, int handle, bool allowHandleZero = false) public static NvMapHandle GetMapFromHandle(long pid, int handle)
{ {
if ((allowHandleZero || handle != 0) && _maps.TryGetValue(pid, out IdDictionary dict)) if (_maps.TryGetValue(pid, out IdDictionary dict))
{ {
return dict.GetData<NvMapHandle>(handle); return dict.GetData<NvMapHandle>(handle);
} }