| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- using Ryujinx.Common.Logging;
- using Ryujinx.Graphics.Gpu.Memory;
- using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
- using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
- using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
- using Ryujinx.Memory;
- using System;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
- {
- class NvHostAsGpuDeviceFile : NvDeviceFile
- {
- private const uint SmallPageSize = 0x1000;
- private const uint BigPageSize = 0x10000;
- private static readonly uint[] _pageSizes = new uint[] { SmallPageSize, BigPageSize };
- private const ulong SmallRegionLimit = 0x400000000UL; // 16 GB
- private const ulong DefaultUserSize = 1UL << 37;
- private struct VmRegion
- {
- public ulong Start { get; }
- public ulong Limit { get; }
- public VmRegion(ulong start, ulong limit)
- {
- Start = start;
- Limit = limit;
- }
- }
- private static readonly VmRegion[] _vmRegions = new VmRegion[]
- {
- new VmRegion((ulong)BigPageSize << 16, SmallRegionLimit),
- new VmRegion(SmallRegionLimit, DefaultUserSize)
- };
- private readonly AddressSpaceContext _asContext;
- private readonly NvMemoryAllocator _memoryAllocator;
- public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
- {
- _asContext = new AddressSpaceContext(context.Device.Gpu.CreateMemoryManager(owner));
- _memoryAllocator = new NvMemoryAllocator();
- }
- public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
- {
- NvInternalResult result = NvInternalResult.NotImplemented;
- if (command.Type == NvIoctl.NvGpuAsMagic)
- {
- switch (command.Number)
- {
- case 0x01:
- result = CallIoctlMethod<BindChannelArguments>(BindChannel, arguments);
- break;
- case 0x02:
- result = CallIoctlMethod<AllocSpaceArguments>(AllocSpace, arguments);
- break;
- case 0x03:
- result = CallIoctlMethod<FreeSpaceArguments>(FreeSpace, arguments);
- break;
- case 0x05:
- result = CallIoctlMethod<UnmapBufferArguments>(UnmapBuffer, arguments);
- break;
- case 0x06:
- result = CallIoctlMethod<MapBufferExArguments>(MapBufferEx, arguments);
- break;
- case 0x08:
- result = CallIoctlMethod<GetVaRegionsArguments>(GetVaRegions, arguments);
- break;
- case 0x09:
- result = CallIoctlMethod<InitializeExArguments>(InitializeEx, arguments);
- break;
- case 0x14:
- result = CallIoctlMethod<RemapArguments>(Remap, arguments);
- break;
- }
- }
- return result;
- }
- public override NvInternalResult Ioctl3(NvIoctl command, Span<byte> arguments, Span<byte> inlineOutBuffer)
- {
- NvInternalResult result = NvInternalResult.NotImplemented;
- if (command.Type == NvIoctl.NvGpuAsMagic)
- {
- switch (command.Number)
- {
- case 0x08:
- // This is the same as the one in ioctl as inlineOutBuffer is empty.
- result = CallIoctlMethod<GetVaRegionsArguments>(GetVaRegions, arguments);
- break;
- }
- }
- return result;
- }
- private NvInternalResult BindChannel(ref BindChannelArguments arguments)
- {
- var channelDeviceFile = INvDrvServices.DeviceFileIdRegistry.GetData<NvHostChannelDeviceFile>(arguments.Fd);
- if (channelDeviceFile == null)
- {
- // TODO: Return invalid Fd error.
- }
- channelDeviceFile.Channel.BindMemory(_asContext.Gmm);
- return NvInternalResult.Success;
- }
- private NvInternalResult AllocSpace(ref AllocSpaceArguments arguments)
- {
- ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
- NvInternalResult result = NvInternalResult.Success;
- lock (_asContext)
- {
- // Note: When the fixed offset flag is not set,
- // the Offset field holds the alignment size instead.
- if ((arguments.Flags & AddressSpaceFlags.FixedOffset) != 0)
- {
- bool regionInUse = _memoryAllocator.IsRegionInUse(arguments.Offset, size, out ulong freeAddressStartPosition);
- ulong address;
- if (!regionInUse)
- {
- _memoryAllocator.AllocateRange(arguments.Offset, size, freeAddressStartPosition);
- address = freeAddressStartPosition;
- }
- else
- {
- address = NvMemoryAllocator.PteUnmapped;
- }
- arguments.Offset = address;
- }
- else
- {
- ulong address = _memoryAllocator.GetFreeAddress(size, out ulong freeAddressStartPosition, arguments.Offset);
- if (address != NvMemoryAllocator.PteUnmapped)
- {
- _memoryAllocator.AllocateRange(address, size, freeAddressStartPosition);
- }
- arguments.Offset = address;
- }
- if (arguments.Offset == NvMemoryAllocator.PteUnmapped)
- {
- arguments.Offset = 0;
- Logger.Warning?.Print(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!");
- result = NvInternalResult.OutOfMemory;
- }
- else
- {
- _asContext.AddReservation(arguments.Offset, size);
- }
- }
- return result;
- }
- private NvInternalResult FreeSpace(ref FreeSpaceArguments arguments)
- {
- ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
- NvInternalResult result = NvInternalResult.Success;
- lock (_asContext)
- {
- if (_asContext.RemoveReservation(arguments.Offset))
- {
- _memoryAllocator.DeallocateRange(arguments.Offset, size);
- _asContext.Gmm.Unmap(arguments.Offset, size);
- }
- else
- {
- Logger.Warning?.Print(LogClass.ServiceNv,
- $"Failed to free offset 0x{arguments.Offset:x16} size 0x{size:x16}!");
- result = NvInternalResult.InvalidInput;
- }
- }
- return result;
- }
- private NvInternalResult UnmapBuffer(ref UnmapBufferArguments arguments)
- {
- lock (_asContext)
- {
- if (_asContext.RemoveMap(arguments.Offset, out ulong size))
- {
- if (size != 0)
- {
- _memoryAllocator.DeallocateRange(arguments.Offset, size);
- _asContext.Gmm.Unmap(arguments.Offset, size);
- }
- }
- else
- {
- Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid buffer offset {arguments.Offset:x16}!");
- }
- }
- return NvInternalResult.Success;
- }
- 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}!";
- ulong physicalAddress;
- if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0)
- {
- lock (_asContext)
- {
- if (_asContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress))
- {
- ulong virtualAddress = arguments.Offset + arguments.BufferOffset;
- physicalAddress += arguments.BufferOffset;
- _asContext.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 (_asContext)
- {
- // 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 (_asContext.ValidateFixedBuffer(arguments.Offset, size, pageSize))
- {
- _asContext.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);
- }
- _asContext.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
- {
- _asContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated);
- }
- }
- return result;
- }
- private NvInternalResult GetVaRegions(ref GetVaRegionsArguments arguments)
- {
- int vaRegionStructSize = Unsafe.SizeOf<VaRegion>();
- Debug.Assert(vaRegionStructSize == 0x18);
- Debug.Assert(_pageSizes.Length == 2);
- uint writeEntries = (uint)(arguments.BufferSize / vaRegionStructSize);
- if (writeEntries > _pageSizes.Length)
- {
- writeEntries = (uint)_pageSizes.Length;
- }
- for (uint i = 0; i < writeEntries; i++)
- {
- ref var region = ref arguments.Regions[(int)i];
- var vmRegion = _vmRegions[i];
- uint pageSize = _pageSizes[i];
- region.PageSize = pageSize;
- region.Offset = vmRegion.Start;
- region.Pages = (vmRegion.Limit - vmRegion.Start) / pageSize;
- region.Padding = 0;
- }
- arguments.BufferSize = (uint)(_pageSizes.Length * vaRegionStructSize);
- return NvInternalResult.Success;
- }
- private NvInternalResult InitializeEx(ref InitializeExArguments arguments)
- {
- Logger.Stub?.PrintStub(LogClass.ServiceNv);
- return NvInternalResult.Success;
- }
- private NvInternalResult Remap(Span<RemapArguments> arguments)
- {
- MemoryManager gmm = _asContext.Gmm;
- for (int index = 0; index < arguments.Length; index++)
- {
- ulong mapOffs = (ulong)arguments[index].MapOffset << 16;
- ulong gpuVa = (ulong)arguments[index].GpuOffset << 16;
- ulong size = (ulong)arguments[index].Pages << 16;
- if (arguments[index].NvMapHandle == 0)
- {
- gmm.Unmap(gpuVa, size);
- }
- else
- {
- NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments[index].NvMapHandle);
- 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);
- }
- }
- return NvInternalResult.Success;
- }
- public override void Close() { }
- }
- }
|