Change SvcGetInfo 5 to return actual heap size, remove AMemoryAlloc since it is no longer needed with direct memory access, move some memory management logic out of AMemoryMgr, change default virtual filesystem path to AppData

This commit is contained in:
gdkchan 2018-02-27 20:45:07 -03:00
parent 708761963e
commit f876bd2a80
17 changed files with 251 additions and 337 deletions

View file

@ -96,7 +96,7 @@ namespace Ryujinx.Core.Loaders
MemoryType Type,
AMemoryPerm Perm)
{
Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write);
Memory.Manager.Map(Position, Data.Count, (int)Type, AMemoryPerm.Write);
for (int Index = 0; Index < Data.Count; Index++)
{
@ -108,7 +108,7 @@ namespace Ryujinx.Core.Loaders
private void MapBss(long Position, long Size)
{
Memory.Manager.MapPhys(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW);
Memory.Manager.Map(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW);
}
private ElfRel GetRelocation(long Position)

View file

@ -12,7 +12,7 @@ namespace Ryujinx.Core.OsHle.Handles
public EventHandler<EventArgs> MemoryMapped;
public EventHandler<EventArgs> MemoryUnmapped;
public HSharedMem(long PhysPos)
public HSharedMem()
{
Positions = new List<long>();
}

View file

@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle
//http://switchbrew.org/index.php?title=Homebrew_ABI
public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle)
{
Memory.Manager.MapPhys(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW);
Memory.Manager.Map(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW);
//MainThreadHandle
WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle);

View file

@ -1,4 +1,3 @@
using ChocolArm64.Memory;
using Ryujinx.Core.Loaders.Executables;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Utilities;
@ -16,9 +15,6 @@ namespace Ryujinx.Core.OsHle
internal int HidHandle { get; private set; }
internal int FontHandle { get; private set; }
public long HidOffset { get; private set; }
public long FontOffset { get; private set; }
internal IdPool IdGen { get; private set; }
internal IdPool NvMapIds { get; private set; }
@ -33,8 +29,6 @@ namespace Ryujinx.Core.OsHle
private HSharedMem HidSharedMem;
private AMemoryAlloc Allocator;
private Switch Ns;
public Horizon(Switch Ns)
@ -53,18 +47,13 @@ namespace Ryujinx.Core.OsHle
Processes = new ConcurrentDictionary<int, Process>();
Allocator = new AMemoryAlloc();
HidOffset = Allocator.Alloc(HidSize);
FontOffset = Allocator.Alloc(FontSize);
HidSharedMem = new HSharedMem(HidOffset);
HidSharedMem = new HSharedMem();
HidSharedMem.MemoryMapped += HidInit;
HidHandle = Handles.GenerateId(HidSharedMem);
FontHandle = Handles.GenerateId(new HSharedMem(FontOffset));
FontHandle = Handles.GenerateId(new HSharedMem());
}
public void LoadCart(string ExeFsDir, string RomFsFile = null)
@ -76,7 +65,7 @@ namespace Ryujinx.Core.OsHle
int ProcessId = IdGen.GenerateId();
Process MainProcess = new Process(Ns, Allocator, ProcessId);
Process MainProcess = new Process(Ns, ProcessId);
void LoadNso(string FileName)
{
@ -106,7 +95,6 @@ namespace Ryujinx.Core.OsHle
LoadNso("subsdk*");
LoadNso("sdk");
MainProcess.InitializeHeap();
MainProcess.Run();
Processes.TryAdd(ProcessId, MainProcess);
@ -118,7 +106,7 @@ namespace Ryujinx.Core.OsHle
int ProcessId = IdGen.GenerateId();
Process MainProcess = new Process(Ns, Allocator, ProcessId);
Process MainProcess = new Process(Ns, ProcessId);
using (FileStream Input = new FileStream(FileName, FileMode.Open))
{
@ -128,7 +116,6 @@ namespace Ryujinx.Core.OsHle
}
MainProcess.SetEmptyArgs();
MainProcess.InitializeHeap();
MainProcess.Run(IsNro);
Processes.TryAdd(ProcessId, MainProcess);
@ -186,7 +173,7 @@ namespace Ryujinx.Core.OsHle
if (SharedMem.TryGetLastVirtualPosition(out long Position))
{
Logging.Info($"HID shared memory successfully mapped to {Position:x16}!");
Logging.Info($"HID shared memory successfully mapped to 0x{Position:x16}!");
Ns.Hid.Init(Position);
}

View file

@ -1,28 +0,0 @@
using ChocolArm64.Memory;
namespace Ryujinx.Core.OsHle
{
struct MemoryInfo
{
public long BaseAddress;
public long Size;
public int MemType;
public int MemAttr;
public int MemPerm;
public int IpcRefCount;
public int DeviceRefCount;
public int Padding; //SBZ
public MemoryInfo(AMemoryMapInfo MapInfo)
{
BaseAddress = MapInfo.Position;
Size = MapInfo.Size;
MemType = MapInfo.Type;
MemAttr = MapInfo.Attr;
MemPerm = (int)MapInfo.Perm;
IpcRefCount = 0;
DeviceRefCount = 0;
Padding = 0;
}
}
}

View file

@ -1,11 +1,28 @@
using ChocolArm64.Memory;
namespace Ryujinx.Core.OsHle
{
static class MemoryRegions
{
public const long MapRegionAddress = 0x80000000;
public const long AddrSpaceStart = 0x08000000;
public const long MapRegionAddress = 0x10000000;
public const long MapRegionSize = 0x40000000;
public const long MainStackSize = 0x100000;
public const long MainStackAddress = AMemoryMgr.AddrSize - MainStackSize;
public const long TlsPagesSize = 0x4000;
public const long TlsPagesAddress = MainStackAddress - TlsPagesSize;
public const long HeapRegionAddress = MapRegionAddress + MapRegionSize;
public const long HeapRegionSize = 0x40000000;
public const long TotalMemoryUsed = HeapRegionAddress + TlsPagesSize + MainStackSize;
public const long TotalMemoryAvailable = AMemoryMgr.RamSize - AddrSpaceStart;
public const long AddrSpaceSize = AMemoryMgr.AddrSize - AddrSpaceStart;
}
}

View file

@ -15,19 +15,15 @@ namespace Ryujinx.Core.OsHle
{
public class Process : IDisposable
{
private const int MaxStackSize = 8 * 1024 * 1024;
private const int TlsSize = 0x200;
private const int TotalTlsSlots = 32;
private const int TlsTotalSize = TotalTlsSlots * TlsSize;
private const long TlsPageAddr = (AMemoryMgr.AddrSize - TlsTotalSize) & ~AMemoryMgr.PageMask;
private Switch Ns;
private ATranslator Translator;
public int ProcessId { get; private set; }
private ATranslator Translator;
public AMemory Memory { get; private set; }
public KProcessScheduler Scheduler { get; private set; }
@ -44,12 +40,12 @@ namespace Ryujinx.Core.OsHle
private long ImageBase;
public Process(Switch Ns, AMemoryAlloc Allocator, int ProcessId)
public Process(Switch Ns, int ProcessId)
{
this.Ns = Ns;
this.ProcessId = ProcessId;
Memory = new AMemory(Ns.Ram, Allocator);
Memory = new AMemory(Ns.Ram);
Scheduler = new KProcessScheduler();
@ -61,13 +57,12 @@ namespace Ryujinx.Core.OsHle
Executables = new List<Executable>();
ImageBase = 0x8000000;
ImageBase = MemoryRegions.AddrSpaceStart;
Memory.Manager.MapPhys(
TlsPageAddr,
TlsTotalSize,
(int)MemoryType.ThreadLocal,
AMemoryPerm.RW);
MapRWMemRegion(
MemoryRegions.TlsPagesAddress,
MemoryRegions.TlsPagesSize,
MemoryType.ThreadLocal);
}
public void LoadProgram(IExecutable Program)
@ -86,11 +81,6 @@ namespace Ryujinx.Core.OsHle
ImageBase += AMemoryMgr.PageSize;
}
public void InitializeHeap()
{
Memory.Manager.SetHeapAddr(MemoryRegions.HeapRegionAddress);
}
public bool Run(bool UseHbAbi = false)
{
if (Executables.Count == 0)
@ -98,11 +88,14 @@ namespace Ryujinx.Core.OsHle
return false;
}
long StackBot = TlsPageAddr - MaxStackSize;
MapRWMemRegion(
MemoryRegions.MainStackAddress,
MemoryRegions.MainStackSize,
MemoryType.Normal);
long StackTop = MemoryRegions.MainStackAddress + MemoryRegions.MainStackSize;
Memory.Manager.MapPhys(StackBot, MaxStackSize, (int)MemoryType.Normal, AMemoryPerm.RW);
int Handle = MakeThread(Executables[0].ImageBase, TlsPageAddr, 0, 0, 0);
int Handle = MakeThread(Executables[0].ImageBase, StackTop, 0, 0, 0);
if (Handle == -1)
{
@ -113,7 +106,7 @@ namespace Ryujinx.Core.OsHle
if (UseHbAbi)
{
long HbAbiDataPosition = (Executables[0].ImageEnd + 0xfff) & ~0xfff;
long HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd);
Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle);
@ -126,6 +119,11 @@ namespace Ryujinx.Core.OsHle
return true;
}
private void MapRWMemRegion(long Position, long Size, MemoryType Type)
{
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
}
public void StopAllThreads()
{
if (MainThread != null)
@ -188,12 +186,14 @@ namespace Ryujinx.Core.OsHle
return -1;
}
long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * TlsSize;
Thread.ThreadState.Break += BreakHandler;
Thread.ThreadState.SvcCall += SvcHandler.SvcCall;
Thread.ThreadState.Undefined += UndefinedHandler;
Thread.ThreadState.ProcessId = ProcessId;
Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId();
Thread.ThreadState.Tpidr = TlsPageAddr + TlsSlot * TlsSize;
Thread.ThreadState.Tpidr = Tpidr;
Thread.ThreadState.X0 = (ulong)ArgsPtr;
Thread.ThreadState.X1 = (ulong)Handle;
Thread.ThreadState.X31 = (ulong)StackTop;
@ -267,7 +267,7 @@ namespace Ryujinx.Core.OsHle
private int GetTlsSlot(long Position)
{
return (int)((Position - TlsPageAddr) / TlsSize);
return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize);
}
public HThread GetThread(long Tpidr)

View file

@ -17,6 +17,8 @@ namespace Ryujinx.Core.OsHle.Svc
private AMemory Memory;
private static Random Rng;
private ulong CurrentHeapSize;
public SvcHandler(Switch Ns, Process Process)
{
@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle.Svc
{ 0x01, SvcSetHeapSize },
{ 0x03, SvcSetMemoryAttribute },
{ 0x04, SvcMapMemory },
{ 0x05, SvcUnmapMemory },
{ 0x06, SvcQueryMemory },
{ 0x07, SvcExitProcess },
{ 0x08, SvcCreateThread },

View file

@ -10,10 +10,21 @@ namespace Ryujinx.Core.OsHle.Svc
{
uint Size = (uint)ThreadState.X1;
Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap);
long Position = MemoryRegions.HeapRegionAddress;
if (Size > CurrentHeapSize)
{
Memory.Manager.Map(Position, Size, (int)MemoryType.Heap, AMemoryPerm.RW);
}
else
{
Memory.Manager.Unmap(Position + Size, (long)CurrentHeapSize - Size);
}
CurrentHeapSize = Size;
ThreadState.X0 = (int)SvcResult.Success;
ThreadState.X1 = (ulong)Memory.Manager.HeapAddr;
ThreadState.X1 = (ulong)Position;
}
private void SvcSetMemoryAttribute(AThreadState ThreadState)
@ -42,7 +53,30 @@ namespace Ryujinx.Core.OsHle.Svc
long Src = (long)ThreadState.X1;
long Size = (long)ThreadState.X2;
Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory);
AMemoryMapInfo SrcInfo = Memory.Manager.GetMapInfo(Src);
Memory.Manager.Map(Dst, Size, (int)MemoryType.MappedMemory, SrcInfo.Perm);
Memory.Manager.Reprotect(Src, Size, AMemoryPerm.None);
Memory.Manager.SetAttrBit(Src, Size, 0);
ThreadState.X0 = (int)SvcResult.Success;
}
private void SvcUnmapMemory(AThreadState ThreadState)
{
long Dst = (long)ThreadState.X0;
long Src = (long)ThreadState.X1;
long Size = (long)ThreadState.X2;
AMemoryMapInfo DstInfo = Memory.Manager.GetMapInfo(Dst);
Memory.Manager.Unmap(Dst, Size, (int)MemoryType.MappedMemory);
Memory.Manager.Reprotect(Src, Size, DstInfo.Perm);
Memory.Manager.ClearAttrBit(Src, Size, 0);
ThreadState.X0 = (int)SvcResult.Success;
}
@ -54,17 +88,22 @@ namespace Ryujinx.Core.OsHle.Svc
AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position);
MemoryInfo Info = new MemoryInfo(MapInfo);
if (MapInfo == null)
{
//TODO: Correct error code.
ThreadState.X0 = ulong.MaxValue;
Memory.WriteInt64(InfoPtr + 0x00, Info.BaseAddress);
Memory.WriteInt64(InfoPtr + 0x08, Info.Size);
Memory.WriteInt32(InfoPtr + 0x10, Info.MemType);
Memory.WriteInt32(InfoPtr + 0x14, Info.MemAttr);
Memory.WriteInt32(InfoPtr + 0x18, Info.MemPerm);
Memory.WriteInt32(InfoPtr + 0x1c, Info.IpcRefCount);
Memory.WriteInt32(InfoPtr + 0x20, Info.DeviceRefCount);
Memory.WriteInt32(InfoPtr + 0x24, Info.Padding);
return;
}
Memory.WriteInt64(InfoPtr + 0x00, MapInfo.Position);
Memory.WriteInt64(InfoPtr + 0x08, MapInfo.Size);
Memory.WriteInt32(InfoPtr + 0x10, MapInfo.Type);
Memory.WriteInt32(InfoPtr + 0x14, MapInfo.Attr);
Memory.WriteInt32(InfoPtr + 0x18, (int)MapInfo.Perm);
Memory.WriteInt32(InfoPtr + 0x1c, 0);
Memory.WriteInt32(InfoPtr + 0x20, 0);
Memory.WriteInt32(InfoPtr + 0x24, 0);
//TODO: X1.
ThreadState.X0 = (int)SvcResult.Success;
@ -84,7 +123,7 @@ namespace Ryujinx.Core.OsHle.Svc
{
SharedMem.AddVirtualPosition(Src);
Memory.Manager.MapPhys(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm);
Memory.Manager.Map(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm);
ThreadState.X0 = (int)SvcResult.Success;
}

View file

@ -11,7 +11,14 @@ namespace Ryujinx.Core.OsHle.Svc
{
partial class SvcHandler
{
private void SvcExitProcess(AThreadState ThreadState) => Ns.Os.ExitProcess(ThreadState.ProcessId);
private const int AllowedCpuIdBitmask = 0b1111;
private const bool EnableProcessDebugging = false;
private void SvcExitProcess(AThreadState ThreadState)
{
Ns.Os.ExitProcess(ThreadState.ProcessId);
}
private void SvcCloseHandle(AThreadState ThreadState)
{
@ -162,79 +169,62 @@ namespace Ryujinx.Core.OsHle.Svc
switch (InfoType)
{
case 0: ThreadState.X1 = AllowedCpuIdBitmask(); break;
case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break;
case 3: ThreadState.X1 = GetMapRegionSize(); break;
case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break;
case 5: ThreadState.X1 = GetHeapRegionSize(); break;
case 6: ThreadState.X1 = GetTotalMem(); break;
case 7: ThreadState.X1 = GetUsedMem(); break;
case 8: ThreadState.X1 = IsCurrentProcessBeingDebugged(); break;
case 11: ThreadState.X1 = GetRnd64(); break;
case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break;
case 13: ThreadState.X1 = GetAddrSpaceSize(); break;
case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break;
case 15: ThreadState.X1 = GetMapRegionSize(); break;
case 0:
ThreadState.X1 = AllowedCpuIdBitmask;
break;
case 2:
ThreadState.X1 = MemoryRegions.MapRegionAddress;
break;
case 3:
ThreadState.X1 = MemoryRegions.MapRegionSize;
break;
case 4:
ThreadState.X1 = MemoryRegions.HeapRegionAddress;
break;
case 5:
ThreadState.X1 = CurrentHeapSize;
break;
case 6:
ThreadState.X1 = MemoryRegions.TotalMemoryAvailable;
break;
case 7:
ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize;
break;
case 8:
ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
break;
case 11:
ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
break;
case 12:
ThreadState.X1 = MemoryRegions.AddrSpaceStart;
break;
case 13:
ThreadState.X1 = MemoryRegions.AddrSpaceSize;
break;
case 14:
ThreadState.X1 = MemoryRegions.MapRegionAddress;
break;
case 15:
ThreadState.X1 = MemoryRegions.MapRegionSize;
break;
default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}");
}
ThreadState.X0 = (int)SvcResult.Success;
}
private ulong AllowedCpuIdBitmask()
{
return 0xF; //Mephisto value.
}
private ulong GetMapRegionBaseAddr()
{
return MemoryRegions.MapRegionAddress;
}
private ulong GetMapRegionSize()
{
return MemoryRegions.MapRegionSize;
}
private ulong GetHeapRegionBaseAddr()
{
return MemoryRegions.HeapRegionAddress;
}
private ulong GetHeapRegionSize()
{
return MemoryRegions.HeapRegionSize;
}
private ulong GetTotalMem()
{
return (ulong)Memory.Manager.GetTotalMemorySize();
}
private ulong GetUsedMem()
{
return (ulong)Memory.Manager.GetUsedMemorySize();
}
private ulong IsCurrentProcessBeingDebugged()
{
return (ulong)0;
}
private ulong GetRnd64()
{
return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
}
private ulong GetAddrSpaceBaseAddr()
{
return 0x08000000;
}
private ulong GetAddrSpaceSize()
{
return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr();
}
}
}

View file

@ -5,9 +5,9 @@ namespace Ryujinx.Core
{
class VirtualFs : IDisposable
{
private const string BasePath = "Fs";
private const string SavesPath = "Saves";
private const string SdCardPath = "SdCard";
private const string BasePath = "RyuFs";
private const string NandPath = "nand";
private const string SdCardPath = "sdmc";
public Stream RomFs { get; private set; }
@ -35,7 +35,7 @@ namespace Ryujinx.Core
public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath);
public string GetGameSavesPath() => MakeDirAndGetFullPath(SavesPath);
public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath);
private string MakeDirAndGetFullPath(string Dir)
{
@ -56,7 +56,9 @@ namespace Ryujinx.Core
public string GetBasePath()
{
return Path.Combine(Directory.GetCurrentDirectory(), BasePath);
string AppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
return Path.Combine(AppDataPath, BasePath);
}
public void Dispose()