From 016fc64b3df8e039e62f3022139244061a00ec30 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sat, 11 Sep 2021 17:39:02 -0300
Subject: [PATCH] Implement GetVaRegions on nvservices (#2621)

* Implement GetVaRegions on nvservices

* This would just result in 0
---
 .../NvHostAsGpu/NvHostAsGpuDeviceFile.cs      | 54 ++++++++++++++++++-
 .../Types/GetVaRegionsArguments.cs            | 16 +++---
 2 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
index b3be6fba75..49c768b4e1 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
@@ -5,11 +5,39 @@ 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;
 
@@ -296,7 +324,31 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
 
         private NvInternalResult GetVaRegions(ref GetVaRegionsArguments arguments)
         {
-            Logger.Stub?.PrintStub(LogClass.ServiceNv);
+            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;
         }
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs
index b3a9cf26cd..dcb5b49efb 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/GetVaRegionsArguments.cs
@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
 {
@@ -6,18 +7,17 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
     struct VaRegion
     {
         public ulong Offset;
-        public uint  PageSize;
-        public uint  Padding;
+        public uint PageSize;
+        public uint Padding;
         public ulong Pages;
     }
 
     [StructLayout(LayoutKind.Sequential)]
     struct GetVaRegionsArguments
     {
-        public ulong    Unused;
-        public uint     BufferSize;
-        public uint     Padding;
-        public VaRegion Region0;
-        public VaRegion Region1;
+        public ulong Unused;
+        public uint BufferSize;
+        public uint Padding;
+        public Array2<VaRegion> Regions;
     }
 }