mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2025-11-07 05:58:59 -06:00
aloha
This commit is contained in:
86
Ryujinx/OsHle/CondVar.cs
Normal file
86
Ryujinx/OsHle/CondVar.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using ChocolArm64.Memory;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class CondVar
|
||||
{
|
||||
private AMemory Memory;
|
||||
|
||||
private long CondVarAddress;
|
||||
private long Timeout;
|
||||
|
||||
private class WaitingThread
|
||||
{
|
||||
public int Handle;
|
||||
|
||||
public ManualResetEvent Event;
|
||||
|
||||
public WaitingThread(int Handle, ManualResetEvent Event)
|
||||
{
|
||||
this.Handle = Handle;
|
||||
this.Event = Event;
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentQueue<WaitingThread> WaitingThreads;
|
||||
|
||||
public CondVar(AMemory Memory, long CondVarAddress, long Timeout)
|
||||
{
|
||||
this.Memory = Memory;
|
||||
this.CondVarAddress = CondVarAddress;
|
||||
this.Timeout = Timeout;
|
||||
|
||||
WaitingThreads = new ConcurrentQueue<WaitingThread>();
|
||||
}
|
||||
|
||||
public void WaitForSignal(int ThreadHandle)
|
||||
{
|
||||
int Count = Memory.ReadInt32(CondVarAddress);
|
||||
|
||||
if (Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Memory.WriteInt32(CondVarAddress, Count - 1);
|
||||
|
||||
ManualResetEvent Event = new ManualResetEvent(false);
|
||||
|
||||
WaitingThreads.Enqueue(new WaitingThread(ThreadHandle, Event));
|
||||
|
||||
if (Timeout != -1)
|
||||
{
|
||||
Event.WaitOne((int)(Timeout / 1000000));
|
||||
}
|
||||
else
|
||||
{
|
||||
Event.WaitOne();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSignal(int Count)
|
||||
{
|
||||
if (Count == -1)
|
||||
{
|
||||
while (WaitingThreads.TryDequeue(out WaitingThread Thread))
|
||||
{
|
||||
Thread.Event.Set();
|
||||
}
|
||||
|
||||
Memory.WriteInt32(CondVarAddress, WaitingThreads.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: Threads with the highest priority needs to be signaled first.
|
||||
if (WaitingThreads.TryDequeue(out WaitingThread Thread))
|
||||
{
|
||||
Thread.Event.Set();
|
||||
}
|
||||
|
||||
Memory.WriteInt32(CondVarAddress, Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Ryujinx/OsHle/Display.cs
Normal file
12
Ryujinx/OsHle/Display.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class Display
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Display(string Name)
|
||||
{
|
||||
this.Name = Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Ryujinx/OsHle/FileDesc.cs
Normal file
12
Ryujinx/OsHle/FileDesc.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class FileDesc
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public FileDesc(string Name)
|
||||
{
|
||||
this.Name = Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Ryujinx/OsHle/Handles/HDomain.cs
Normal file
58
Ryujinx/OsHle/Handles/HDomain.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Ryujinx.OsHle.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HDomain : HSession
|
||||
{
|
||||
private Dictionary<int, object> Objects;
|
||||
|
||||
private IdPool ObjIds;
|
||||
|
||||
public HDomain(HSession Session) : base(Session)
|
||||
{
|
||||
Objects = new Dictionary<int, object>();
|
||||
|
||||
ObjIds = new IdPool();
|
||||
}
|
||||
|
||||
public int GenertateObjectId(object Obj)
|
||||
{
|
||||
int Id = ObjIds.GenerateId();
|
||||
|
||||
if (Id == -1)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Objects.Add(Id, Obj);
|
||||
|
||||
return Id;
|
||||
}
|
||||
|
||||
public void DeleteObject(int Id)
|
||||
{
|
||||
if (Objects.TryGetValue(Id, out object Obj))
|
||||
{
|
||||
if (Obj is IDisposable DisposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
|
||||
ObjIds.DeleteId(Id);
|
||||
Objects.Remove(Id);
|
||||
}
|
||||
}
|
||||
|
||||
public object GetObject(int Id)
|
||||
{
|
||||
if (Objects.TryGetValue(Id, out object Obj))
|
||||
{
|
||||
return Obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Handles/HEvent.cs
Normal file
7
Ryujinx/OsHle/Handles/HEvent.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HEvent
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
18
Ryujinx/OsHle/Handles/HNvMap.cs
Normal file
18
Ryujinx/OsHle/Handles/HNvMap.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HNvMap
|
||||
{
|
||||
public int Id { get; private set; }
|
||||
public int Size { get; private set; }
|
||||
|
||||
public int Align { get; set; }
|
||||
public int Kind { get; set; }
|
||||
public long Address { get; set; }
|
||||
|
||||
public HNvMap(int Id, int Size)
|
||||
{
|
||||
this.Id = Id;
|
||||
this.Size = Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Ryujinx/OsHle/Handles/HSession.cs
Normal file
27
Ryujinx/OsHle/Handles/HSession.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HSession
|
||||
{
|
||||
public string ServiceName { get; private set; }
|
||||
|
||||
public bool IsInitialized { get; private set; }
|
||||
|
||||
public int State { get; set; }
|
||||
|
||||
public HSession(string ServiceName)
|
||||
{
|
||||
this.ServiceName = ServiceName;
|
||||
}
|
||||
|
||||
public HSession(HSession Session)
|
||||
{
|
||||
ServiceName = Session.ServiceName;
|
||||
IsInitialized = Session.IsInitialized;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
IsInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Ryujinx/OsHle/Handles/HSessionObj.cs
Normal file
12
Ryujinx/OsHle/Handles/HSessionObj.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HSessionObj : HSession
|
||||
{
|
||||
public object Obj { get; private set; }
|
||||
|
||||
public HSessionObj(HSession Session, object Obj) : base(Session)
|
||||
{
|
||||
this.Obj = Obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Ryujinx/OsHle/Handles/HSharedMem.cs
Normal file
12
Ryujinx/OsHle/Handles/HSharedMem.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HSharedMem
|
||||
{
|
||||
public long PhysPos { get; private set; }
|
||||
|
||||
public HSharedMem(long PhysPos)
|
||||
{
|
||||
this.PhysPos = PhysPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Ryujinx/OsHle/Handles/HThread.cs
Normal file
14
Ryujinx/OsHle/Handles/HThread.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using ChocolArm64;
|
||||
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HThread
|
||||
{
|
||||
public AThread Thread { get; private set; }
|
||||
|
||||
public HThread(AThread Thread)
|
||||
{
|
||||
this.Thread = Thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Ryujinx/OsHle/Handles/HTransferMem.cs
Normal file
23
Ryujinx/OsHle/Handles/HTransferMem.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ChocolArm64.Memory;
|
||||
|
||||
namespace Ryujinx.OsHle.Handles
|
||||
{
|
||||
class HTransferMem
|
||||
{
|
||||
public AMemory Memory { get; private set; }
|
||||
public AMemoryPerm Perm { get; private set; }
|
||||
|
||||
public long Position { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
public long PhysPos { get; private set; }
|
||||
|
||||
public HTransferMem(AMemory Memory, AMemoryPerm Perm, long Position, long Size, long PhysPos)
|
||||
{
|
||||
this.Memory = Memory;
|
||||
this.Perm = Perm;
|
||||
this.Position = Position;
|
||||
this.Size = Size;
|
||||
this.PhysPos = PhysPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
163
Ryujinx/OsHle/Horizon.cs
Normal file
163
Ryujinx/OsHle/Horizon.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Loaders.Executables;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Utilities;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class Horizon
|
||||
{
|
||||
internal const int HidSize = 0x40000;
|
||||
internal const int FontSize = 0x50;
|
||||
|
||||
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; }
|
||||
|
||||
internal IdPoolWithObj Handles { get; private set; }
|
||||
internal IdPoolWithObj Fds { get; private set; }
|
||||
internal IdPoolWithObj Displays { get; private set; }
|
||||
|
||||
public ConcurrentDictionary<long, Mutex> Mutexes { get; private set; }
|
||||
public ConcurrentDictionary<long, CondVar> CondVars { get; private set; }
|
||||
|
||||
private ConcurrentDictionary<int, Process> Processes;
|
||||
|
||||
private AMemoryAlloc Allocator;
|
||||
|
||||
private Switch Ns;
|
||||
|
||||
public Horizon(Switch Ns)
|
||||
{
|
||||
this.Ns = Ns;
|
||||
|
||||
IdGen = new IdPool();
|
||||
NvMapIds = new IdPool();
|
||||
|
||||
Handles = new IdPoolWithObj();
|
||||
Fds = new IdPoolWithObj();
|
||||
Displays = new IdPoolWithObj();
|
||||
|
||||
Mutexes = new ConcurrentDictionary<long, Mutex>();
|
||||
CondVars = new ConcurrentDictionary<long, CondVar>();
|
||||
|
||||
Processes = new ConcurrentDictionary<int, Process>();
|
||||
|
||||
Allocator = new AMemoryAlloc();
|
||||
|
||||
HidOffset = Allocator.Alloc(HidSize);
|
||||
FontOffset = Allocator.Alloc(FontSize);
|
||||
|
||||
HidHandle = Handles.GenerateId(new HSharedMem(HidOffset));
|
||||
FontHandle = Handles.GenerateId(new HSharedMem(FontOffset));
|
||||
}
|
||||
|
||||
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
||||
{
|
||||
if (RomFsFile != null)
|
||||
{
|
||||
Ns.VFs.LoadRomFs(RomFsFile);
|
||||
}
|
||||
|
||||
int ProcessId = IdGen.GenerateId();
|
||||
|
||||
Process MainProcess = new Process(Ns, Allocator, ProcessId);
|
||||
|
||||
void LoadNso(string FileName)
|
||||
{
|
||||
foreach (string File in Directory.GetFiles(ExeFsDir, FileName))
|
||||
{
|
||||
if (Path.GetExtension(File) != string.Empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using (FileStream Input = new FileStream(File, FileMode.Open))
|
||||
{
|
||||
Nso Program = new Nso(Input);
|
||||
|
||||
MainProcess.LoadProgram(Program);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoadNso("rtld");
|
||||
|
||||
MainProcess.SetEmptyArgs();
|
||||
|
||||
LoadNso("main");
|
||||
LoadNso("subsdk*");
|
||||
LoadNso("sdk");
|
||||
|
||||
MainProcess.InitializeHeap();
|
||||
MainProcess.Run();
|
||||
|
||||
Processes.TryAdd(ProcessId, MainProcess);
|
||||
}
|
||||
|
||||
public void LoadProgram(string FileName)
|
||||
{
|
||||
int ProcessId = IdGen.GenerateId();
|
||||
|
||||
Process MainProcess = new Process(Ns, Allocator, ProcessId);
|
||||
|
||||
using (FileStream Input = new FileStream(FileName, FileMode.Open))
|
||||
{
|
||||
if (Path.GetExtension(FileName).ToLower() == ".nro")
|
||||
{
|
||||
MainProcess.LoadProgram(new Nro(Input));
|
||||
}
|
||||
else
|
||||
{
|
||||
MainProcess.LoadProgram(new Nso(Input));
|
||||
}
|
||||
}
|
||||
|
||||
MainProcess.SetEmptyArgs();
|
||||
MainProcess.InitializeHeap();
|
||||
MainProcess.Run();
|
||||
|
||||
Processes.TryAdd(ProcessId, MainProcess);
|
||||
}
|
||||
|
||||
public void StopAllProcesses()
|
||||
{
|
||||
foreach (Process Process in Processes.Values)
|
||||
{
|
||||
Process.StopAllThreads();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool TryGetProcess(int ProcessId, out Process Process)
|
||||
{
|
||||
if (!Processes.TryGetValue(ProcessId, out Process))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void CloseHandle(int Handle)
|
||||
{
|
||||
object HndData = Handles.GetData<object>(Handle);
|
||||
|
||||
if (HndData is HTransferMem TransferMem)
|
||||
{
|
||||
TransferMem.Memory.Manager.Reprotect(
|
||||
TransferMem.Position,
|
||||
TransferMem.Size,
|
||||
TransferMem.Perm);
|
||||
}
|
||||
|
||||
Handles.Delete(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Ryujinx/OsHle/Ipc/IpcBuffDesc.cs
Normal file
27
Ryujinx/OsHle/Ipc/IpcBuffDesc.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
struct IpcBuffDesc
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
public int Flags { get; private set; }
|
||||
|
||||
public IpcBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
long Word0 = Reader.ReadUInt32();
|
||||
long Word1 = Reader.ReadUInt32();
|
||||
long Word2 = Reader.ReadUInt32();
|
||||
|
||||
Position = Word1;
|
||||
Position |= (Word2 << 4) & 0x0f00000000;
|
||||
Position |= (Word2 << 34) & 0x7000000000;
|
||||
|
||||
Size = Word0;
|
||||
Size |= (Word2 << 8) & 0xf00000000;
|
||||
|
||||
Flags = (int)Word2 & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Ryujinx/OsHle/Ipc/IpcDomCmd.cs
Normal file
8
Ryujinx/OsHle/Ipc/IpcDomCmd.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
enum IpcDomCmd
|
||||
{
|
||||
SendMsg = 1,
|
||||
DeleteObj = 2
|
||||
}
|
||||
}
|
||||
90
Ryujinx/OsHle/Ipc/IpcHandleDesc.cs
Normal file
90
Ryujinx/OsHle/Ipc/IpcHandleDesc.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
class IpcHandleDesc
|
||||
{
|
||||
public bool HasPId { get; private set; }
|
||||
|
||||
public long PId { get; private set; }
|
||||
|
||||
public int[] ToCopy { get; private set; }
|
||||
public int[] ToMove { get; private set; }
|
||||
|
||||
public IpcHandleDesc(BinaryReader Reader)
|
||||
{
|
||||
int Word = Reader.ReadInt32();
|
||||
|
||||
HasPId = (Word & 1) != 0;
|
||||
|
||||
ToCopy = new int[(Word >> 1) & 0xf];
|
||||
ToMove = new int[(Word >> 5) & 0xf];
|
||||
|
||||
PId = HasPId ? Reader.ReadInt64() : 0;
|
||||
|
||||
for (int Index = 0; Index < ToCopy.Length; Index++)
|
||||
{
|
||||
ToCopy[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < ToMove.Length; Index++)
|
||||
{
|
||||
ToMove[Index] = Reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public IpcHandleDesc(int[] Copy, int[] Move)
|
||||
{
|
||||
ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy));
|
||||
ToMove = Move ?? throw new ArgumentNullException(nameof(Move));
|
||||
}
|
||||
|
||||
public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move)
|
||||
{
|
||||
this.PId = PId;
|
||||
|
||||
HasPId = true;
|
||||
}
|
||||
|
||||
public static IpcHandleDesc MakeCopy(int Handle) => new IpcHandleDesc(
|
||||
new int[] { Handle },
|
||||
new int[0]);
|
||||
|
||||
public static IpcHandleDesc MakeMove(int Handle) => new IpcHandleDesc(
|
||||
new int[0],
|
||||
new int[] { Handle });
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
int Word = HasPId ? 1 : 0;
|
||||
|
||||
Word |= (ToCopy.Length & 0xf) << 1;
|
||||
Word |= (ToMove.Length & 0xf) << 5;
|
||||
|
||||
Writer.Write(Word);
|
||||
|
||||
if (HasPId)
|
||||
{
|
||||
Writer.Write((long)PId);
|
||||
}
|
||||
|
||||
foreach (int Handle in ToCopy)
|
||||
{
|
||||
Writer.Write(Handle);
|
||||
}
|
||||
|
||||
foreach (int Handle in ToMove)
|
||||
{
|
||||
Writer.Write(Handle);
|
||||
}
|
||||
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
358
Ryujinx/OsHle/Ipc/IpcHandler.cs
Normal file
358
Ryujinx/OsHle/Ipc/IpcHandler.cs
Normal file
@@ -0,0 +1,358 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Objects;
|
||||
using Ryujinx.OsHle.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
static class IpcHandler
|
||||
{
|
||||
private delegate long ServiceProcessRequest(ServiceCtx Context);
|
||||
|
||||
private static Dictionary<(string, int), ServiceProcessRequest> ServiceCmds =
|
||||
new Dictionary<(string, int), ServiceProcessRequest>()
|
||||
{
|
||||
{ ( "acc:u0", 3), Service.AccU0ListOpenUsers },
|
||||
{ ( "acc:u0", 5), Service.AccU0GetProfile },
|
||||
{ ( "acc:u0", 100), Service.AccU0InitializeApplicationInfo },
|
||||
{ ( "acc:u0", 101), Service.AccU0GetBaasAccountManagerForApplication },
|
||||
{ ( "apm", 0), Service.ApmOpenSession },
|
||||
{ ( "appletOE", 0), Service.AppletOpenApplicationProxy },
|
||||
{ ( "audout:u", 0), Service.AudOutListAudioOuts },
|
||||
{ ( "audout:u", 1), Service.AudOutOpenAudioOut },
|
||||
{ ( "audren:u", 0), Service.AudRenOpenAudioRenderer },
|
||||
{ ( "audren:u", 1), Service.AudRenGetAudioRendererWorkBufferSize },
|
||||
{ ( "friend:a", 0), Service.FriendCreateFriendService },
|
||||
{ ( "fsp-srv", 1), Service.FspSrvInitialize },
|
||||
{ ( "fsp-srv", 51), Service.FspSrvMountSaveData },
|
||||
{ ( "fsp-srv", 200), Service.FspSrvOpenDataStorageByCurrentProcess },
|
||||
{ ( "fsp-srv", 203), Service.FspSrvOpenRomStorage },
|
||||
{ ( "fsp-srv", 1005), Service.FspSrvGetGlobalAccessLogMode },
|
||||
{ ( "hid", 0), Service.HidCreateAppletResource },
|
||||
{ ( "hid", 11), Service.HidActivateTouchScreen },
|
||||
{ ( "hid", 100), Service.HidSetSupportedNpadStyleSet },
|
||||
{ ( "hid", 102), Service.HidSetSupportedNpadIdType },
|
||||
{ ( "hid", 103), Service.HidActivateNpad },
|
||||
{ ( "hid", 120), Service.HidSetNpadJoyHoldType },
|
||||
{ ( "lm", 0), Service.LmInitialize },
|
||||
{ ( "nvdrv", 0), Service.NvDrvOpen },
|
||||
{ ( "nvdrv", 1), Service.NvDrvIoctl },
|
||||
{ ( "nvdrv", 2), Service.NvDrvClose },
|
||||
{ ( "nvdrv", 3), Service.NvDrvInitialize },
|
||||
{ ( "nvdrv", 4), Service.NvDrvQueryEvent },
|
||||
{ ( "nvdrv:a", 0), Service.NvDrvOpen },
|
||||
{ ( "nvdrv:a", 1), Service.NvDrvIoctl },
|
||||
{ ( "nvdrv:a", 2), Service.NvDrvClose },
|
||||
{ ( "nvdrv:a", 3), Service.NvDrvInitialize },
|
||||
{ ( "nvdrv:a", 4), Service.NvDrvQueryEvent },
|
||||
{ ( "pctl:a", 0), Service.PctlCreateService },
|
||||
{ ( "pl:u", 1), Service.PlGetLoadState },
|
||||
{ ( "pl:u", 2), Service.PlGetFontSize },
|
||||
{ ( "pl:u", 3), Service.PlGetSharedMemoryAddressOffset },
|
||||
{ ( "pl:u", 4), Service.PlGetSharedMemoryNativeHandle },
|
||||
{ ( "set", 1), Service.SetGetAvailableLanguageCodes },
|
||||
{ ( "sm:", 0), Service.SmInitialize },
|
||||
{ ( "sm:", 1), Service.SmGetService },
|
||||
{ ( "time:u", 0), Service.TimeGetStandardUserSystemClock },
|
||||
{ ( "time:u", 1), Service.TimeGetStandardNetworkSystemClock },
|
||||
{ ( "time:u", 2), Service.TimeGetStandardSteadyClock },
|
||||
{ ( "time:u", 3), Service.TimeGetTimeZoneService },
|
||||
{ ( "time:s", 0), Service.TimeGetStandardUserSystemClock },
|
||||
{ ( "time:s", 1), Service.TimeGetStandardNetworkSystemClock },
|
||||
{ ( "time:s", 2), Service.TimeGetStandardSteadyClock },
|
||||
{ ( "time:s", 3), Service.TimeGetTimeZoneService },
|
||||
{ ( "vi:m", 2), Service.ViGetDisplayService },
|
||||
};
|
||||
|
||||
private static Dictionary<(Type, int), ServiceProcessRequest> ObjectCmds =
|
||||
new Dictionary<(Type, int), ServiceProcessRequest>()
|
||||
{
|
||||
//IManagerForApplication
|
||||
{ (typeof(AccIManagerForApplication), 0), AccIManagerForApplication.CheckAvailability },
|
||||
{ (typeof(AccIManagerForApplication), 1), AccIManagerForApplication.GetAccountId },
|
||||
|
||||
//IProfile
|
||||
{ (typeof(AccIProfile), 1), AccIProfile.GetBase },
|
||||
|
||||
//IApplicationFunctions
|
||||
{ (typeof(AmIApplicationFunctions), 1), AmIApplicationFunctions.PopLaunchParameter },
|
||||
{ (typeof(AmIApplicationFunctions), 20), AmIApplicationFunctions.EnsureSaveData },
|
||||
{ (typeof(AmIApplicationFunctions), 21), AmIApplicationFunctions.GetDesiredLanguage },
|
||||
|
||||
//IApplicationProxy
|
||||
{ (typeof(AmIApplicationProxy), 0), AmIApplicationProxy.GetCommonStateGetter },
|
||||
{ (typeof(AmIApplicationProxy), 1), AmIApplicationProxy.GetSelfController },
|
||||
{ (typeof(AmIApplicationProxy), 2), AmIApplicationProxy.GetWindowController },
|
||||
{ (typeof(AmIApplicationProxy), 3), AmIApplicationProxy.GetAudioController },
|
||||
{ (typeof(AmIApplicationProxy), 4), AmIApplicationProxy.GetDisplayController },
|
||||
{ (typeof(AmIApplicationProxy), 11), AmIApplicationProxy.GetLibraryAppletCreator },
|
||||
{ (typeof(AmIApplicationProxy), 20), AmIApplicationProxy.GetApplicationFunctions },
|
||||
{ (typeof(AmIApplicationProxy), 1000), AmIApplicationProxy.GetDebugFunctions },
|
||||
|
||||
//ICommonStateGetter
|
||||
{ (typeof(AmICommonStateGetter), 0), AmICommonStateGetter.GetEventHandle },
|
||||
{ (typeof(AmICommonStateGetter), 1), AmICommonStateGetter.ReceiveMessage },
|
||||
{ (typeof(AmICommonStateGetter), 5), AmICommonStateGetter.GetOperationMode },
|
||||
{ (typeof(AmICommonStateGetter), 6), AmICommonStateGetter.GetPerformanceMode },
|
||||
{ (typeof(AmICommonStateGetter), 9), AmICommonStateGetter.GetCurrentFocusState },
|
||||
|
||||
//ISelfController
|
||||
{ (typeof(AmISelfController), 11), AmISelfController.SetOperationModeChangedNotification },
|
||||
{ (typeof(AmISelfController), 12), AmISelfController.SetPerformanceModeChangedNotification },
|
||||
{ (typeof(AmISelfController), 13), AmISelfController.SetFocusHandlingMode },
|
||||
|
||||
//IStorage
|
||||
{ (typeof(AmIStorage), 0), AmIStorage.Open },
|
||||
|
||||
//IStorageAccessor
|
||||
{ (typeof(AmIStorageAccessor), 0), AmIStorageAccessor.GetSize },
|
||||
{ (typeof(AmIStorageAccessor), 11), AmIStorageAccessor.Read },
|
||||
|
||||
//IWindowController
|
||||
{ (typeof(AmIWindowController), 1), AmIWindowController.GetAppletResourceUserId },
|
||||
{ (typeof(AmIWindowController), 10), AmIWindowController.AcquireForegroundRights },
|
||||
|
||||
//ISession
|
||||
{ (typeof(ApmISession), 0), ApmISession.SetPerformanceConfiguration },
|
||||
|
||||
//IAudioRenderer
|
||||
{ (typeof(AudIAudioRenderer), 4), AudIAudioRenderer.RequestUpdateAudioRenderer },
|
||||
{ (typeof(AudIAudioRenderer), 5), AudIAudioRenderer.StartAudioRenderer },
|
||||
{ (typeof(AudIAudioRenderer), 7), AudIAudioRenderer.QuerySystemEvent },
|
||||
|
||||
//IFile
|
||||
{ (typeof(FspSrvIFile), 0), FspSrvIFile.Read },
|
||||
{ (typeof(FspSrvIFile), 1), FspSrvIFile.Write },
|
||||
|
||||
//IFileSystem
|
||||
{ (typeof(FspSrvIFileSystem), 7), FspSrvIFileSystem.GetEntryType },
|
||||
{ (typeof(FspSrvIFileSystem), 8), FspSrvIFileSystem.OpenFile },
|
||||
{ (typeof(FspSrvIFileSystem), 10), FspSrvIFileSystem.Commit },
|
||||
|
||||
//IStorage
|
||||
{ (typeof(FspSrvIStorage), 0), FspSrvIStorage.Read },
|
||||
|
||||
//IAppletResource
|
||||
{ (typeof(HidIAppletResource), 0), HidIAppletResource.GetSharedMemoryHandle },
|
||||
|
||||
//ISystemClock
|
||||
{ (typeof(TimeISystemClock), 0), TimeISystemClock.GetCurrentTime },
|
||||
|
||||
//IApplicationDisplayService
|
||||
{ (typeof(ViIApplicationDisplayService), 100), ViIApplicationDisplayService.GetRelayService },
|
||||
{ (typeof(ViIApplicationDisplayService), 101), ViIApplicationDisplayService.GetSystemDisplayService },
|
||||
{ (typeof(ViIApplicationDisplayService), 102), ViIApplicationDisplayService.GetManagerDisplayService },
|
||||
{ (typeof(ViIApplicationDisplayService), 1010), ViIApplicationDisplayService.OpenDisplay },
|
||||
{ (typeof(ViIApplicationDisplayService), 2020), ViIApplicationDisplayService.OpenLayer },
|
||||
{ (typeof(ViIApplicationDisplayService), 2030), ViIApplicationDisplayService.CreateStrayLayer },
|
||||
{ (typeof(ViIApplicationDisplayService), 2101), ViIApplicationDisplayService.SetLayerScalingMode },
|
||||
{ (typeof(ViIApplicationDisplayService), 5202), ViIApplicationDisplayService.GetDisplayVSyncEvent },
|
||||
|
||||
//IHOSBinderDriver
|
||||
{ (typeof(ViIHOSBinderDriver), 0), ViIHOSBinderDriver.TransactParcel },
|
||||
{ (typeof(ViIHOSBinderDriver), 1), ViIHOSBinderDriver.AdjustRefcount },
|
||||
{ (typeof(ViIHOSBinderDriver), 2), ViIHOSBinderDriver.GetNativeHandle },
|
||||
|
||||
//IManagerDisplayService
|
||||
{ (typeof(ViIManagerDisplayService), 2010), ViIManagerDisplayService.CreateManagedLayer },
|
||||
{ (typeof(ViIManagerDisplayService), 6000), ViIManagerDisplayService.AddToLayerStack },
|
||||
|
||||
//ISystemDisplayService
|
||||
{ (typeof(ViISystemDisplayService), 2205), ViISystemDisplayService.SetLayerZ },
|
||||
};
|
||||
|
||||
private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
|
||||
private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
|
||||
|
||||
public static void ProcessRequest(
|
||||
Switch Ns,
|
||||
AMemory Memory,
|
||||
HSession Session,
|
||||
IpcMessage Request,
|
||||
long CmdPtr,
|
||||
int HndId)
|
||||
{
|
||||
IpcMessage Response = new IpcMessage(Request.IsDomain);
|
||||
|
||||
using (MemoryStream Raw = new MemoryStream(Request.RawData))
|
||||
{
|
||||
BinaryReader ReqReader = new BinaryReader(Raw);
|
||||
|
||||
if (Request.Type == IpcMessageType.Request)
|
||||
{
|
||||
string ServiceName = Session.ServiceName;
|
||||
|
||||
ServiceProcessRequest ProcReq = null;
|
||||
|
||||
bool IgnoreNullPR = false;
|
||||
|
||||
if (Session is HDomain Dom)
|
||||
{
|
||||
if (Request.DomCmd == IpcDomCmd.SendMsg)
|
||||
{
|
||||
long Magic = ReqReader.ReadInt64();
|
||||
int CmdId = (int)ReqReader.ReadInt64();
|
||||
|
||||
object Obj = Dom.GetObject(Request.DomObjId);
|
||||
|
||||
if (Obj is HDomain)
|
||||
{
|
||||
ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq);
|
||||
}
|
||||
else if (Obj != null)
|
||||
{
|
||||
ObjectCmds.TryGetValue((Obj.GetType(), CmdId), out ProcReq);
|
||||
}
|
||||
}
|
||||
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
|
||||
{
|
||||
Dom.DeleteObject(Request.DomObjId);
|
||||
|
||||
Response = FillResponse(Response, 0);
|
||||
|
||||
IgnoreNullPR = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long Magic = ReqReader.ReadInt64();
|
||||
int CmdId = (int)ReqReader.ReadInt64();
|
||||
|
||||
if (Session is HSessionObj)
|
||||
{
|
||||
object Obj = ((HSessionObj)Session).Obj;
|
||||
|
||||
ObjectCmds.TryGetValue((Obj.GetType(), CmdId), out ProcReq);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq);
|
||||
}
|
||||
}
|
||||
|
||||
if (ProcReq != null)
|
||||
{
|
||||
using (MemoryStream ResMS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter ResWriter = new BinaryWriter(ResMS);
|
||||
|
||||
ServiceCtx Context = new ServiceCtx(
|
||||
Ns,
|
||||
Memory,
|
||||
Session,
|
||||
Request,
|
||||
Response,
|
||||
ReqReader,
|
||||
ResWriter);
|
||||
|
||||
long Result = ProcReq(Context);
|
||||
|
||||
Response = FillResponse(Response, Result, ResMS.ToArray());
|
||||
}
|
||||
}
|
||||
else if (!IgnoreNullPR)
|
||||
{
|
||||
throw new NotImplementedException(ServiceName);
|
||||
}
|
||||
}
|
||||
else if (Request.Type == IpcMessageType.Control)
|
||||
{
|
||||
long Magic = ReqReader.ReadInt64();
|
||||
long CmdId = ReqReader.ReadInt64();
|
||||
|
||||
switch (CmdId)
|
||||
{
|
||||
case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break;
|
||||
case 3: Request = IpcQueryBufferPointerSize(Response); break;
|
||||
case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break;
|
||||
|
||||
default: throw new NotImplementedException(CmdId.ToString());
|
||||
}
|
||||
}
|
||||
else if (Request.Type == IpcMessageType.Unknown2)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(Request.Type.ToString());
|
||||
}
|
||||
|
||||
AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr));
|
||||
}
|
||||
}
|
||||
|
||||
private static IpcMessage IpcConvertSessionToDomain(
|
||||
Switch Ns,
|
||||
HSession Session,
|
||||
IpcMessage Response,
|
||||
int HndId)
|
||||
{
|
||||
HDomain Dom = new HDomain(Session);
|
||||
|
||||
Ns.Os.Handles.ReplaceData(HndId, Dom);
|
||||
|
||||
return FillResponse(Response, 0, Dom.GenertateObjectId(Dom));
|
||||
}
|
||||
|
||||
private static IpcMessage IpcDuplicateSessionEx(
|
||||
Switch Ns,
|
||||
HSession Session,
|
||||
IpcMessage Response,
|
||||
BinaryReader ReqReader)
|
||||
{
|
||||
int Unknown = ReqReader.ReadInt32();
|
||||
|
||||
int Handle = Ns.Os.Handles.GenerateId(Session);
|
||||
|
||||
Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||
|
||||
return FillResponse(Response, 0);
|
||||
}
|
||||
|
||||
private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response)
|
||||
{
|
||||
return FillResponse(Response, 0, 0x500);
|
||||
}
|
||||
|
||||
private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
|
||||
{
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
foreach (int Value in Values)
|
||||
{
|
||||
Writer.Write(Value);
|
||||
}
|
||||
|
||||
return FillResponse(Response, Result, MS.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null)
|
||||
{
|
||||
Response.Type = IpcMessageType.Response;
|
||||
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
Writer.Write(SfcoMagic);
|
||||
Writer.Write(Result);
|
||||
|
||||
if (Data != null)
|
||||
{
|
||||
Writer.Write(Data);
|
||||
}
|
||||
|
||||
Response.RawData = MS.ToArray();
|
||||
}
|
||||
|
||||
return Response;
|
||||
}
|
||||
}
|
||||
}
|
||||
231
Ryujinx/OsHle/Ipc/IpcMessage.cs
Normal file
231
Ryujinx/OsHle/Ipc/IpcMessage.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
class IpcMessage
|
||||
{
|
||||
public IpcMessageType Type { get; set; }
|
||||
|
||||
public IpcHandleDesc HandleDesc { get; set; }
|
||||
|
||||
public List<IpcPtrBuffDesc> PtrBuff { get; private set; }
|
||||
public List<IpcBuffDesc> SendBuff { get; private set; }
|
||||
public List<IpcBuffDesc> ReceiveBuff { get; private set; }
|
||||
public List<IpcBuffDesc> ExchangeBuff { get; private set; }
|
||||
public List<IpcRecvListBuffDesc> RecvListBuff { get; private set; }
|
||||
|
||||
public List<int> ResponseObjIds { get; private set; }
|
||||
|
||||
public bool IsDomain { get; private set; }
|
||||
public IpcDomCmd DomCmd { get; private set; }
|
||||
public int DomObjId { get; private set; }
|
||||
|
||||
public byte[] RawData { get; set; }
|
||||
|
||||
public IpcMessage()
|
||||
{
|
||||
PtrBuff = new List<IpcPtrBuffDesc>();
|
||||
SendBuff = new List<IpcBuffDesc>();
|
||||
ReceiveBuff = new List<IpcBuffDesc>();
|
||||
ExchangeBuff = new List<IpcBuffDesc>();
|
||||
RecvListBuff = new List<IpcRecvListBuffDesc>();
|
||||
|
||||
ResponseObjIds = new List<int>();
|
||||
}
|
||||
|
||||
public IpcMessage(bool Domain) : this()
|
||||
{
|
||||
IsDomain = Domain;
|
||||
}
|
||||
|
||||
public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this()
|
||||
{
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
Initialize(Reader, CmdPtr, Domain);
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain)
|
||||
{
|
||||
IsDomain = Domain;
|
||||
|
||||
int Word0 = Reader.ReadInt32();
|
||||
int Word1 = Reader.ReadInt32();
|
||||
|
||||
Type = (IpcMessageType)(Word0 & 0xffff);
|
||||
|
||||
int PtrBuffCount = (Word0 >> 16) & 0xf;
|
||||
int SendBuffCount = (Word0 >> 20) & 0xf;
|
||||
int RecvBuffCount = (Word0 >> 24) & 0xf;
|
||||
int XchgBuffCount = (Word0 >> 28) & 0xf;
|
||||
|
||||
int RawDataSize = (Word1 >> 0) & 0x3ff;
|
||||
int RecvListFlags = (Word1 >> 10) & 0xf;
|
||||
bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0;
|
||||
|
||||
if (HndDescEnable)
|
||||
{
|
||||
HandleDesc = new IpcHandleDesc(Reader);
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < PtrBuffCount; Index++)
|
||||
{
|
||||
PtrBuff.Add(new IpcPtrBuffDesc(Reader));
|
||||
}
|
||||
|
||||
void ReadBuff(List<IpcBuffDesc> Buff, int Count)
|
||||
{
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
Buff.Add(new IpcBuffDesc(Reader));
|
||||
}
|
||||
}
|
||||
|
||||
ReadBuff(SendBuff, SendBuffCount);
|
||||
ReadBuff(ReceiveBuff, RecvBuffCount);
|
||||
ReadBuff(ExchangeBuff, XchgBuffCount);
|
||||
|
||||
RawDataSize *= 4;
|
||||
|
||||
long RecvListPos = Reader.BaseStream.Position + RawDataSize;
|
||||
|
||||
long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr);
|
||||
|
||||
Reader.BaseStream.Seek(Pad0, SeekOrigin.Current);
|
||||
|
||||
int RecvListCount = RecvListFlags - 2;
|
||||
|
||||
if (RecvListCount == 0)
|
||||
{
|
||||
RecvListCount = 1;
|
||||
}
|
||||
else if (RecvListCount < 0)
|
||||
{
|
||||
RecvListCount = 0;
|
||||
}
|
||||
|
||||
if (Domain)
|
||||
{
|
||||
int DomWord0 = Reader.ReadInt32();
|
||||
|
||||
DomCmd = (IpcDomCmd)(DomWord0 & 0xff);
|
||||
|
||||
RawDataSize = (DomWord0 >> 16) & 0xffff;
|
||||
|
||||
DomObjId = Reader.ReadInt32();
|
||||
|
||||
Reader.ReadInt64(); //Padding
|
||||
}
|
||||
|
||||
RawData = Reader.ReadBytes(RawDataSize);
|
||||
|
||||
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
|
||||
|
||||
for (int Index = 0; Index < RecvListCount; Index++)
|
||||
{
|
||||
RecvListBuff.Add(new IpcRecvListBuffDesc(Reader));
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetBytes(long CmdPtr)
|
||||
{
|
||||
//todo
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
int Word0;
|
||||
int Word1;
|
||||
|
||||
Word0 = (int)Type;
|
||||
Word0 |= (PtrBuff.Count & 0xf) << 16;
|
||||
Word0 |= (SendBuff.Count & 0xf) << 20;
|
||||
Word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
||||
Word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
||||
|
||||
byte[] HandleData = new byte[0];
|
||||
|
||||
if (HandleDesc != null)
|
||||
{
|
||||
HandleData = HandleDesc.GetBytes();
|
||||
}
|
||||
|
||||
int DataLength = RawData?.Length ?? 0;
|
||||
|
||||
int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length);
|
||||
|
||||
//Apparently, padding after Raw Data is 16 bytes, however when there is
|
||||
//padding before Raw Data too, we need to subtract the size of this padding.
|
||||
//This is the weirdest padding I've seen so far...
|
||||
int Pad1 = 0x10 - Pad0;
|
||||
|
||||
DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4;
|
||||
|
||||
DataLength += ResponseObjIds.Count;
|
||||
|
||||
Word1 = DataLength & 0x3ff;
|
||||
|
||||
if (HandleDesc != null)
|
||||
{
|
||||
Word1 |= 1 << 31;
|
||||
}
|
||||
|
||||
Writer.Write(Word0);
|
||||
Writer.Write(Word1);
|
||||
Writer.Write(HandleData);
|
||||
|
||||
MS.Seek(Pad0, SeekOrigin.Current);
|
||||
|
||||
if (IsDomain)
|
||||
{
|
||||
Writer.Write(ResponseObjIds.Count);
|
||||
Writer.Write(0);
|
||||
Writer.Write(0L);
|
||||
}
|
||||
|
||||
if (RawData != null)
|
||||
{
|
||||
Writer.Write(RawData);
|
||||
}
|
||||
|
||||
foreach (int Id in ResponseObjIds)
|
||||
{
|
||||
Writer.Write(Id);
|
||||
}
|
||||
|
||||
Writer.Write(new byte[Pad1]);
|
||||
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private long GetPadSize16(long Position)
|
||||
{
|
||||
if ((Position & 0xf) != 0)
|
||||
{
|
||||
return 0x10 - (Position & 0xf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSendBuffPtr()
|
||||
{
|
||||
if (SendBuff.Count > 0 && SendBuff[0].Position != 0)
|
||||
{
|
||||
return SendBuff[0].Position;
|
||||
}
|
||||
|
||||
if (PtrBuff.Count > 0 && PtrBuff[0].Position != 0)
|
||||
{
|
||||
return PtrBuff[0].Position;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Ryujinx/OsHle/Ipc/IpcMessageType.cs
Normal file
10
Ryujinx/OsHle/Ipc/IpcMessageType.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
enum IpcMessageType
|
||||
{
|
||||
Response = 0,
|
||||
Unknown2 = 2,
|
||||
Request = 4,
|
||||
Control = 5
|
||||
}
|
||||
}
|
||||
26
Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs
Normal file
26
Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
struct IpcPtrBuffDesc
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
public int Index { get; private set; }
|
||||
public short Size { get; private set; }
|
||||
|
||||
public IpcPtrBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
long Word0 = Reader.ReadUInt32();
|
||||
long Word1 = Reader.ReadUInt32();
|
||||
|
||||
Position = Word1;
|
||||
Position |= (Word0 << 20) & 0x0f00000000;
|
||||
Position |= (Word0 << 30) & 0x7000000000;
|
||||
|
||||
Index = ((int)Word0 >> 0) & 0x03f;
|
||||
Index |= ((int)Word0 >> 3) & 0x1c0;
|
||||
|
||||
Size = (short)(Word0 >> 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs
Normal file
19
Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Ipc
|
||||
{
|
||||
struct IpcRecvListBuffDesc
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
public short Size { get; private set; }
|
||||
|
||||
public IpcRecvListBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
long Value = Reader.ReadInt64();
|
||||
|
||||
Position = Value & 0xffffffffffff;
|
||||
|
||||
Size = (short)(Value >> 48);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Ryujinx/OsHle/MemoryInfo.cs
Normal file
28
Ryujinx/OsHle/MemoryInfo.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using ChocolArm64.Memory;
|
||||
|
||||
namespace Ryujinx.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 = 0;
|
||||
MemPerm = (int)MapInfo.Perm;
|
||||
IpcRefCount = 0;
|
||||
DeviceRefCount = 0;
|
||||
Padding = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Ryujinx/OsHle/MemoryType.cs
Normal file
25
Ryujinx/OsHle/MemoryType.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
enum MemoryType
|
||||
{
|
||||
Unmapped = 0,
|
||||
Io = 1,
|
||||
Normal = 2,
|
||||
CodeStatic = 3,
|
||||
CodeMutable = 4,
|
||||
Heap = 5,
|
||||
SharedMemory = 6,
|
||||
ModCodeStatic = 8,
|
||||
ModCodeMutable = 9,
|
||||
IpcBuffer0 = 10,
|
||||
MappedMemory = 11,
|
||||
ThreadLocal = 12,
|
||||
TransferMemoryIsolated = 13,
|
||||
TransferMemory = 14,
|
||||
ProcessMemory = 15,
|
||||
Reserved = 16,
|
||||
IpcBuffer1 = 17,
|
||||
IpcBuffer3 = 18,
|
||||
KernelStack = 19
|
||||
}
|
||||
}
|
||||
89
Ryujinx/OsHle/Mutex.cs
Normal file
89
Ryujinx/OsHle/Mutex.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using ChocolArm64;
|
||||
using ChocolArm64.Memory;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class Mutex
|
||||
{
|
||||
private const int MutexHasListenersMask = 0x40000000;
|
||||
|
||||
private AMemory Memory;
|
||||
|
||||
private long MutexAddress;
|
||||
|
||||
private int CurrRequestingThreadHandle;
|
||||
|
||||
private int HighestPriority;
|
||||
|
||||
private ManualResetEvent ThreadEvent;
|
||||
|
||||
private object EnterWaitLock;
|
||||
|
||||
public Mutex(AMemory Memory, long MutexAddress)
|
||||
{
|
||||
this.Memory = Memory;
|
||||
this.MutexAddress = MutexAddress;
|
||||
|
||||
ThreadEvent = new ManualResetEvent(false);
|
||||
|
||||
EnterWaitLock = new object();
|
||||
}
|
||||
|
||||
public void WaitForLock(AThread RequestingThread, int RequestingThreadHandle)
|
||||
{
|
||||
lock (EnterWaitLock)
|
||||
{
|
||||
int CurrentThreadHandle = Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask;
|
||||
|
||||
if (CurrentThreadHandle == RequestingThreadHandle ||
|
||||
CurrentThreadHandle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrRequestingThreadHandle == 0 || RequestingThread.Priority < HighestPriority)
|
||||
{
|
||||
CurrRequestingThreadHandle = RequestingThreadHandle;
|
||||
|
||||
HighestPriority = RequestingThread.Priority;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadEvent.Reset();
|
||||
ThreadEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void GiveUpLock(int ThreadHandle)
|
||||
{
|
||||
lock (EnterWaitLock)
|
||||
{
|
||||
int CurrentThread = Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask;
|
||||
|
||||
if (CurrentThread == ThreadHandle)
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
lock (EnterWaitLock)
|
||||
{
|
||||
if (CurrRequestingThreadHandle != 0)
|
||||
{
|
||||
Memory.WriteInt32(MutexAddress, CurrRequestingThreadHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory.WriteInt32(MutexAddress, 0);
|
||||
}
|
||||
|
||||
CurrRequestingThreadHandle = 0;
|
||||
|
||||
ThreadEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Ryujinx/OsHle/Objects/AccIManagerForApplication.cs
Normal file
17
Ryujinx/OsHle/Objects/AccIManagerForApplication.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AccIManagerForApplication
|
||||
{
|
||||
public static long CheckAvailability(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAccountId(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0xcafeL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Ryujinx/OsHle/Objects/AccIProfile.cs
Normal file
18
Ryujinx/OsHle/Objects/AccIProfile.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AccIProfile
|
||||
{
|
||||
public static long GetBase(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs
Normal file
56
Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.IO;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIApplicationFunctions
|
||||
{
|
||||
private const uint LaunchParamsMagic = 0xc79497ca;
|
||||
|
||||
public static long PopLaunchParameter(ServiceCtx Context)
|
||||
{
|
||||
//Only the first 0x18 bytes of the Data seems to be actually used.
|
||||
MakeObject(Context, new AmIStorage(MakeLaunchParams()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long EnsureSaveData(ServiceCtx Context)
|
||||
{
|
||||
long UIdLow = Context.RequestData.ReadInt64();
|
||||
long UIdHigh = Context.RequestData.ReadInt64();
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetDesiredLanguage(ServiceCtx Context)
|
||||
{
|
||||
//This is an enumerator where each number is a differnet language.
|
||||
//0 is Japanese and 1 is English, need to figure out the other codes.
|
||||
Context.ResponseData.Write(1L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static byte[] MakeLaunchParams()
|
||||
{
|
||||
//Size needs to be at least 0x88 bytes otherwise application errors.
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
MS.SetLength(0x88);
|
||||
|
||||
Writer.Write(LaunchParamsMagic);
|
||||
Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used.
|
||||
Writer.Write(1L); //User Id Low (note: User Id needs to be != 0)
|
||||
Writer.Write(0L); //User Id High
|
||||
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Ryujinx/OsHle/Objects/AmIApplicationProxy.cs
Normal file
63
Ryujinx/OsHle/Objects/AmIApplicationProxy.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIApplicationProxy
|
||||
{
|
||||
public static long GetCommonStateGetter(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmICommonStateGetter());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetSelfController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmISelfController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetWindowController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIWindowController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAudioController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIAudioController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetDisplayController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIDisplayController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetLibraryAppletCreator(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmILibraryAppletCreator());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetApplicationFunctions(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIApplicationFunctions());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetDebugFunctions(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIDebugFunctions());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/AmIAudioController.cs
Normal file
7
Ryujinx/OsHle/Objects/AmIAudioController.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIAudioController
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
55
Ryujinx/OsHle/Objects/AmICommonStateGetter.cs
Normal file
55
Ryujinx/OsHle/Objects/AmICommonStateGetter.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmICommonStateGetter
|
||||
{
|
||||
private enum FocusState
|
||||
{
|
||||
InFocus = 1,
|
||||
OutOfFocus = 2
|
||||
}
|
||||
|
||||
private enum OperationMode
|
||||
{
|
||||
Handheld = 0,
|
||||
Docked = 1
|
||||
}
|
||||
|
||||
public static long GetEventHandle(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long ReceiveMessage(ServiceCtx Context)
|
||||
{
|
||||
//Program expects 0xF at 0x17ae70 on puyo sdk,
|
||||
//otherwise runs on a infinite loop until it reads said value.
|
||||
//What it means is still unknown.
|
||||
Context.ResponseData.Write(0xfL);
|
||||
|
||||
return 0; //0x680;
|
||||
}
|
||||
|
||||
public static long GetOperationMode(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((byte)OperationMode.Handheld);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetPerformanceMode(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((byte)0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetCurrentFocusState(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((byte)FocusState.InFocus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/AmIDebugFunctions.cs
Normal file
7
Ryujinx/OsHle/Objects/AmIDebugFunctions.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIDebugFunctions
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/AmIDisplayController.cs
Normal file
7
Ryujinx/OsHle/Objects/AmIDisplayController.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIDisplayController
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/AmILibraryAppletCreator.cs
Normal file
7
Ryujinx/OsHle/Objects/AmILibraryAppletCreator.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmILibraryAppletCreator
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/AmIParentalControlService.cs
Normal file
7
Ryujinx/OsHle/Objects/AmIParentalControlService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIParentalControlService
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
28
Ryujinx/OsHle/Objects/AmISelfController.cs
Normal file
28
Ryujinx/OsHle/Objects/AmISelfController.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmISelfController
|
||||
{
|
||||
public static long SetOperationModeChangedNotification(ServiceCtx Context)
|
||||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long SetPerformanceModeChangedNotification(ServiceCtx Context)
|
||||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long SetFocusHandlingMode(ServiceCtx Context)
|
||||
{
|
||||
bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Ryujinx/OsHle/Objects/AmIStorage.cs
Normal file
23
Ryujinx/OsHle/Objects/AmIStorage.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIStorage
|
||||
{
|
||||
public byte[] Data { get; private set; }
|
||||
|
||||
public AmIStorage(byte[] Data)
|
||||
{
|
||||
this.Data = Data;
|
||||
}
|
||||
|
||||
public static long Open(ServiceCtx Context)
|
||||
{
|
||||
AmIStorage Storage = Context.GetObject<AmIStorage>();
|
||||
|
||||
MakeObject(Context, new AmIStorageAccessor(Storage));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Ryujinx/OsHle/Objects/AmIStorageAccessor.cs
Normal file
56
Ryujinx/OsHle/Objects/AmIStorageAccessor.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using ChocolArm64.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIStorageAccessor
|
||||
{
|
||||
public AmIStorage Storage { get; private set; }
|
||||
|
||||
public AmIStorageAccessor(AmIStorage Storage)
|
||||
{
|
||||
this.Storage = Storage;
|
||||
}
|
||||
|
||||
public static long GetSize(ServiceCtx Context)
|
||||
{
|
||||
AmIStorageAccessor Accessor = Context.GetObject<AmIStorageAccessor>();
|
||||
|
||||
Context.ResponseData.Write((long)Accessor.Storage.Data.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long Read(ServiceCtx Context)
|
||||
{
|
||||
AmIStorageAccessor Accessor = Context.GetObject<AmIStorageAccessor>();
|
||||
|
||||
AmIStorage Storage = Accessor.Storage;
|
||||
|
||||
long ReadPosition = Context.RequestData.ReadInt64();
|
||||
|
||||
if (Context.Request.RecvListBuff.Count > 0)
|
||||
{
|
||||
long Position = Context.Request.RecvListBuff[0].Position;
|
||||
short Size = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
byte[] Data;
|
||||
|
||||
if (Storage.Data.Length > Size)
|
||||
{
|
||||
Data = new byte[Size];
|
||||
|
||||
Buffer.BlockCopy(Storage.Data, 0, Data, 0, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Data = Storage.Data;
|
||||
}
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Ryujinx/OsHle/Objects/AmIWindowController.cs
Normal file
17
Ryujinx/OsHle/Objects/AmIWindowController.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AmIWindowController
|
||||
{
|
||||
public static long GetAppletResourceUserId(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AcquireForegroundRights(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Ryujinx/OsHle/Objects/ApmISession.cs
Normal file
13
Ryujinx/OsHle/Objects/ApmISession.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class ApmISession
|
||||
{
|
||||
public static long SetPerformanceConfiguration(ServiceCtx Context)
|
||||
{
|
||||
int PerfMode = Context.RequestData.ReadInt32();
|
||||
int PerfConfig = Context.RequestData.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
Normal file
36
Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class AudIAudioRenderer
|
||||
{
|
||||
public static long RequestUpdateAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
//0x40 bytes header
|
||||
Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section)
|
||||
Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size?
|
||||
Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size?
|
||||
Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size?
|
||||
Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size?
|
||||
Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size?
|
||||
Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header)
|
||||
|
||||
for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10)
|
||||
{
|
||||
Context.Memory.WriteInt32(Position + Offset, 5);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long StartAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long QuerySystemEvent(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/FriendIFriendService.cs
Normal file
7
Ryujinx/OsHle/Objects/FriendIFriendService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class FriendIFriendService
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
72
Ryujinx/OsHle/Objects/FspSrvIFile.cs
Normal file
72
Ryujinx/OsHle/Objects/FspSrvIFile.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using ChocolArm64.Memory;
|
||||
using System;
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class FspSrvIFile : IDisposable
|
||||
{
|
||||
public Stream BaseStream { get; private set; }
|
||||
|
||||
public FspSrvIFile(Stream BaseStream)
|
||||
{
|
||||
this.BaseStream = BaseStream;
|
||||
}
|
||||
|
||||
public static long Read(ServiceCtx Context)
|
||||
{
|
||||
FspSrvIFile File = Context.GetObject<FspSrvIFile>();
|
||||
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
long Zero = Context.RequestData.ReadInt64();
|
||||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
byte[] Data = new byte[Size];
|
||||
|
||||
int ReadSize = File.BaseStream.Read(Data, 0, (int)Size);
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
|
||||
|
||||
//TODO: Use ReadSize, we need to return the size that was REALLY read from the file.
|
||||
//This is a workaround because we are doing something wrong and the game expects to read
|
||||
//data from a file that doesn't yet exists -- and breaks if it can't read anything.
|
||||
Context.ResponseData.Write((long)Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long Write(ServiceCtx Context)
|
||||
{
|
||||
FspSrvIFile File = Context.GetObject<FspSrvIFile>();
|
||||
|
||||
long Position = Context.Request.SendBuff[0].Position;
|
||||
|
||||
long Zero = Context.RequestData.ReadInt64();
|
||||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)Size);
|
||||
|
||||
File.BaseStream.Seek(Offset, SeekOrigin.Begin);
|
||||
File.BaseStream.Write(Data, 0, (int)Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && BaseStream != null)
|
||||
{
|
||||
BaseStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Ryujinx/OsHle/Objects/FspSrvIFileSystem.cs
Normal file
70
Ryujinx/OsHle/Objects/FspSrvIFileSystem.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using ChocolArm64.Memory;
|
||||
using System.IO;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class FspSrvIFileSystem
|
||||
{
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
public FspSrvIFileSystem(string Path)
|
||||
{
|
||||
this.FilePath = Path;
|
||||
}
|
||||
|
||||
public static long GetEntryType(ServiceCtx Context)
|
||||
{
|
||||
FspSrvIFileSystem FileSystem = Context.GetObject<FspSrvIFileSystem>();
|
||||
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
||||
|
||||
string FileName = Context.Ns.VFs.GetFullPath(FileSystem.FilePath, Name);
|
||||
|
||||
if (FileName == null)
|
||||
{
|
||||
//TODO: Correct error code.
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IsFile = File.Exists(FileName);
|
||||
|
||||
Context.ResponseData.Write(IsFile ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long OpenFile(ServiceCtx Context)
|
||||
{
|
||||
FspSrvIFileSystem FileSystem = Context.GetObject<FspSrvIFileSystem>();
|
||||
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
int FilterFlags = Context.RequestData.ReadInt32();
|
||||
|
||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
|
||||
|
||||
string FileName = Context.Ns.VFs.GetFullPath(FileSystem.FilePath, Name);
|
||||
|
||||
if (FileName == null)
|
||||
{
|
||||
//TODO: Correct error code.
|
||||
return -1;
|
||||
}
|
||||
|
||||
FileStream Stream = new FileStream(FileName, FileMode.OpenOrCreate);
|
||||
|
||||
MakeObject(Context, new FspSrvIFile(Stream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long Commit(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Ryujinx/OsHle/Objects/FspSrvIStorage.cs
Normal file
44
Ryujinx/OsHle/Objects/FspSrvIStorage.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class FspSrvIStorage
|
||||
{
|
||||
public Stream BaseStream { get; private set; }
|
||||
|
||||
public FspSrvIStorage(Stream BaseStream)
|
||||
{
|
||||
this.BaseStream = BaseStream;
|
||||
}
|
||||
|
||||
public static long Read(ServiceCtx Context)
|
||||
{
|
||||
FspSrvIStorage Storage = Context.GetObject<FspSrvIStorage>();
|
||||
|
||||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
if (Context.Request.ReceiveBuff.Count > 0)
|
||||
{
|
||||
IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0];
|
||||
|
||||
//Use smaller length to avoid overflows.
|
||||
if (Size > BuffDesc.Size)
|
||||
{
|
||||
Size = BuffDesc.Size;
|
||||
}
|
||||
|
||||
byte[] Data = new byte[Size];
|
||||
|
||||
Storage.BaseStream.Seek(Offset, SeekOrigin.Begin);
|
||||
Storage.BaseStream.Read(Data, 0, Data.Length);
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, BuffDesc.Position, Data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Ryujinx/OsHle/Objects/HidIAppletResource.cs
Normal file
22
Ryujinx/OsHle/Objects/HidIAppletResource.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class HidIAppletResource
|
||||
{
|
||||
public HSharedMem Handle;
|
||||
|
||||
public HidIAppletResource(HSharedMem Handle)
|
||||
{
|
||||
this.Handle = Handle;
|
||||
}
|
||||
|
||||
public static long GetSharedMemoryHandle(ServiceCtx Context)
|
||||
{
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Ryujinx/OsHle/Objects/ObjHelper.cs
Normal file
24
Ryujinx/OsHle/Objects/ObjHelper.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
static class ObjHelper
|
||||
{
|
||||
public static void MakeObject(ServiceCtx Context, object Obj)
|
||||
{
|
||||
if (Context.Session is HDomain Dom)
|
||||
{
|
||||
Context.Response.ResponseObjIds.Add(Dom.GenertateObjectId(Obj));
|
||||
}
|
||||
else
|
||||
{
|
||||
HSessionObj HndData = new HSessionObj(Context.Session, Obj);
|
||||
|
||||
int VHandle = Context.Ns.Os.Handles.GenerateId(HndData);
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Ryujinx/OsHle/Objects/Parcel.cs
Normal file
58
Ryujinx/OsHle/Objects/Parcel.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects.Android
|
||||
{
|
||||
static class Parcel
|
||||
{
|
||||
public static byte[] GetParcelData(byte[] Parcel)
|
||||
{
|
||||
if (Parcel == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Parcel));
|
||||
}
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(Parcel))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
int DataSize = Reader.ReadInt32();
|
||||
int DataOffset = Reader.ReadInt32();
|
||||
int ObjsSize = Reader.ReadInt32();
|
||||
int ObjsOffset = Reader.ReadInt32();
|
||||
|
||||
MS.Seek(DataOffset - 0x10, SeekOrigin.Current);
|
||||
|
||||
return Reader.ReadBytes(DataSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] MakeParcel(byte[] Data, byte[] Objs)
|
||||
{
|
||||
if (Data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Data));
|
||||
}
|
||||
|
||||
if (Objs == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Objs));
|
||||
}
|
||||
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
Writer.Write(Data.Length);
|
||||
Writer.Write(0x10);
|
||||
Writer.Write(Objs.Length);
|
||||
Writer.Write(Data.Length + 0x10);
|
||||
|
||||
Writer.Write(Data);
|
||||
Writer.Write(Objs);
|
||||
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/TimeISteadyClock.cs
Normal file
7
Ryujinx/OsHle/Objects/TimeISteadyClock.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class TimeISteadyClock
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
16
Ryujinx/OsHle/Objects/TimeISystemClock.cs
Normal file
16
Ryujinx/OsHle/Objects/TimeISystemClock.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class TimeISystemClock
|
||||
{
|
||||
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
public static long GetCurrentTime(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Ryujinx/OsHle/Objects/TimeITimeZoneService.cs
Normal file
7
Ryujinx/OsHle/Objects/TimeITimeZoneService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class TimeITimeZoneService
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
148
Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs
Normal file
148
Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
using System.IO;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.Android.Parcel;
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class ViIApplicationDisplayService
|
||||
{
|
||||
public static long GetRelayService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new ViIHOSBinderDriver());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetSystemDisplayService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new ViISystemDisplayService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetManagerDisplayService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new ViIManagerDisplayService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long OpenDisplay(ServiceCtx Context)
|
||||
{
|
||||
string Name = GetDisplayName(Context);
|
||||
|
||||
long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name));
|
||||
|
||||
Context.ResponseData.Write(DisplayId);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long OpenLayer(ServiceCtx Context)
|
||||
{
|
||||
long LayerId = Context.RequestData.ReadInt64();
|
||||
long UserId = Context.RequestData.ReadInt64();
|
||||
|
||||
long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel);
|
||||
|
||||
Context.ResponseData.Write((long)Parcel.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long CreateStrayLayer(ServiceCtx Context)
|
||||
{
|
||||
long LayerFlags = Context.RequestData.ReadInt64();
|
||||
long DisplayId = Context.RequestData.ReadInt64();
|
||||
|
||||
long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
Display Disp = Context.Ns.Os.Displays.GetData<Display>((int)DisplayId);
|
||||
|
||||
byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel);
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write((long)Parcel.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long SetLayerScalingMode(ServiceCtx Context)
|
||||
{
|
||||
int ScalingMode = Context.RequestData.ReadInt32();
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetDisplayVSyncEvent(ServiceCtx Context)
|
||||
{
|
||||
string Name = GetDisplayName(Context);
|
||||
|
||||
int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static byte[] MakeIGraphicsBufferProducer(long BasePtr)
|
||||
{
|
||||
long Id = 0x20;
|
||||
long CookiePtr = 0L;
|
||||
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
//flat_binder_object (size is 0x28)
|
||||
Writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER)
|
||||
Writer.Write(0); //Flags
|
||||
Writer.Write((int)(Id >> 0));
|
||||
Writer.Write((int)(Id >> 32));
|
||||
Writer.Write((int)(CookiePtr >> 0));
|
||||
Writer.Write((int)(CookiePtr >> 32));
|
||||
Writer.Write((byte)'d');
|
||||
Writer.Write((byte)'i');
|
||||
Writer.Write((byte)'s');
|
||||
Writer.Write((byte)'p');
|
||||
Writer.Write((byte)'d');
|
||||
Writer.Write((byte)'r');
|
||||
Writer.Write((byte)'v');
|
||||
Writer.Write((byte)'\0');
|
||||
Writer.Write(0L); //Pad
|
||||
|
||||
return MakeParcel(MS.ToArray(), new byte[] { 0, 0, 0, 0 });
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDisplayName(ServiceCtx Context)
|
||||
{
|
||||
string Name = string.Empty;
|
||||
|
||||
for (int Index = 0; Index < 8 &&
|
||||
Context.RequestData.BaseStream.Position <
|
||||
Context.RequestData.BaseStream.Length; Index++)
|
||||
{
|
||||
byte Chr = Context.RequestData.ReadByte();
|
||||
|
||||
if (Chr >= 0x20 && Chr < 0x7f)
|
||||
{
|
||||
Name += (char)Chr;
|
||||
}
|
||||
}
|
||||
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
211
Ryujinx/OsHle/Objects/ViIHOSBinderDriver.cs
Normal file
211
Ryujinx/OsHle/Objects/ViIHOSBinderDriver.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
using Ryujinx.OsHle.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.Android.Parcel;
|
||||
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class ViIHOSBinderDriver
|
||||
{
|
||||
private delegate long ServiceProcessRequest(ServiceCtx Context, byte[] ParcelData);
|
||||
|
||||
private static Dictionary<(string, int), ServiceProcessRequest> InterfaceMthd =
|
||||
new Dictionary<(string, int), ServiceProcessRequest>()
|
||||
{
|
||||
{ ("android.gui.IGraphicBufferProducer", 0x1), GraphicBufferProducerRequestBuffer },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0x3), GraphicBufferProducerDequeueBuffer },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0x7), GraphicBufferProducerQueueBuffer },
|
||||
//{ ("android.gui.IGraphicBufferProducer", 0x8), GraphicBufferProducerCancelBuffer },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0x9), GraphicBufferProducerQuery },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0xa), GraphicBufferProducerConnect },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0xe), GraphicBufferPreallocateBuffer },
|
||||
};
|
||||
|
||||
private class BufferObj
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IdPoolWithObj BufferSlots { get; private set; }
|
||||
|
||||
public byte[] Gbfr;
|
||||
|
||||
public ViIHOSBinderDriver()
|
||||
{
|
||||
BufferSlots = new IdPoolWithObj();
|
||||
}
|
||||
|
||||
public static long TransactParcel(ServiceCtx Context)
|
||||
{
|
||||
int Id = Context.RequestData.ReadInt32();
|
||||
int Code = Context.RequestData.ReadInt32();
|
||||
|
||||
long DataPos = Context.Request.SendBuff[0].Position;
|
||||
long DataSize = Context.Request.SendBuff[0].Size;
|
||||
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)DataSize);
|
||||
|
||||
Data = GetParcelData(Data);
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
MS.Seek(4, SeekOrigin.Current);
|
||||
|
||||
int StrSize = Reader.ReadInt32();
|
||||
|
||||
string InterfaceName = Encoding.Unicode.GetString(Data, 8, StrSize * 2);
|
||||
|
||||
if (InterfaceMthd.TryGetValue((InterfaceName, Code), out ServiceProcessRequest ProcReq))
|
||||
{
|
||||
return ProcReq(Context, Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"{InterfaceName} {Code}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long GraphicBufferProducerRequestBuffer(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
|
||||
|
||||
int GbfrSize = BinderDriver.Gbfr?.Length ?? 0;
|
||||
|
||||
byte[] Data = new byte[GbfrSize + 4];
|
||||
|
||||
if (BinderDriver.Gbfr != null)
|
||||
{
|
||||
Buffer.BlockCopy(BinderDriver.Gbfr, 0, Data, 0, GbfrSize);
|
||||
}
|
||||
|
||||
return MakeReplyParcel(Context, Data);
|
||||
}
|
||||
|
||||
private static long GraphicBufferProducerDequeueBuffer(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
|
||||
|
||||
//Note: It seems that the maximum number of slots is 64, because if we return
|
||||
//a Slot number > 63, it seems to cause a buffer overrun and it reads garbage.
|
||||
//Note 2: The size of each object associated with the slot is 0x30.
|
||||
int Slot = BinderDriver.BufferSlots.GenerateId(new BufferObj());
|
||||
|
||||
return MakeReplyParcel(Context, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private static long GraphicBufferProducerQueueBuffer(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
|
||||
}
|
||||
|
||||
private static long GraphicBufferProducerCancelBuffer(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(ParcelData))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
MS.Seek(0x50, SeekOrigin.Begin);
|
||||
|
||||
int Slot = Reader.ReadInt32();
|
||||
|
||||
BinderDriver.BufferSlots.Delete(Slot);
|
||||
|
||||
return MakeReplyParcel(Context, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static long GraphicBufferProducerQuery(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
return MakeReplyParcel(Context, 0, 0);
|
||||
}
|
||||
|
||||
private static long GraphicBufferProducerConnect(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
|
||||
}
|
||||
|
||||
private static long GraphicBufferPreallocateBuffer(ServiceCtx Context, byte[] ParcelData)
|
||||
{
|
||||
ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
|
||||
|
||||
int GbfrSize = ParcelData.Length - 0x54;
|
||||
|
||||
BinderDriver.Gbfr = new byte[GbfrSize];
|
||||
|
||||
Buffer.BlockCopy(ParcelData, 0x54, BinderDriver.Gbfr, 0, GbfrSize);
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(ParcelData))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
MS.Seek(0xd4, SeekOrigin.Begin);
|
||||
|
||||
int Handle = Reader.ReadInt32();
|
||||
|
||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
||||
|
||||
Context.Ns.Gpu.Renderer.FrameBufferPtr =
|
||||
Context.Memory.Manager.GetPhys(NvMap.Address, AMemoryPerm.Read);
|
||||
}
|
||||
|
||||
return MakeReplyParcel(Context, 0);
|
||||
}
|
||||
|
||||
private static long MakeReplyParcel(ServiceCtx Context, params int[] Ints)
|
||||
{
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
foreach (int Int in Ints)
|
||||
{
|
||||
Writer.Write(Int);
|
||||
}
|
||||
|
||||
return MakeReplyParcel(Context, MS.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private static long MakeReplyParcel(ServiceCtx Context, byte[] Data)
|
||||
{
|
||||
long ReplyPos = Context.Request.ReceiveBuff[0].Position;
|
||||
long ReplySize = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
byte[] Reply = MakeParcel(Data, new byte[0]);
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AdjustRefcount(ServiceCtx Context)
|
||||
{
|
||||
int Id = Context.RequestData.ReadInt32();
|
||||
int AddVal = Context.RequestData.ReadInt32();
|
||||
int Type = Context.RequestData.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetNativeHandle(ServiceCtx Context)
|
||||
{
|
||||
int Id = Context.RequestData.ReadInt32();
|
||||
uint Unk = Context.RequestData.ReadUInt32();
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Ryujinx/OsHle/Objects/ViIManagerDisplayService.cs
Normal file
17
Ryujinx/OsHle/Objects/ViIManagerDisplayService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class ViIManagerDisplayService
|
||||
{
|
||||
public static long CreateManagedLayer(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0L); //LayerId
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AddToLayerStack(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Ryujinx/OsHle/Objects/ViISystemDisplayService.cs
Normal file
10
Ryujinx/OsHle/Objects/ViISystemDisplayService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Ryujinx.OsHle.Objects
|
||||
{
|
||||
class ViISystemDisplayService
|
||||
{
|
||||
public static long SetLayerZ(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
179
Ryujinx/OsHle/Process.cs
Normal file
179
Ryujinx/OsHle/Process.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using ChocolArm64;
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Loaders;
|
||||
using Ryujinx.Loaders.Executables;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Svc;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class Process
|
||||
{
|
||||
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;
|
||||
|
||||
public int ProcessId { get; private set; }
|
||||
|
||||
public AMemory Memory { get; private set; }
|
||||
|
||||
private SvcHandler SvcHandler;
|
||||
|
||||
private AThread MainThread;
|
||||
|
||||
private ConcurrentDictionary<int, AThread> TlsSlots;
|
||||
|
||||
private List<Executable> Executables;
|
||||
|
||||
private long ImageBase;
|
||||
|
||||
public Process(Switch Ns, AMemoryAlloc Allocator, int ProcessId)
|
||||
{
|
||||
this.Ns = Ns;
|
||||
this.ProcessId = ProcessId;
|
||||
|
||||
Memory = new AMemory(Ns.Ram, Allocator);
|
||||
SvcHandler = new SvcHandler(Ns, Memory);
|
||||
TlsSlots = new ConcurrentDictionary<int, AThread>();
|
||||
Executables = new List<Executable>();
|
||||
|
||||
ImageBase = 0x8000000;
|
||||
|
||||
Memory.Manager.MapPhys(
|
||||
TlsPageAddr,
|
||||
TlsTotalSize,
|
||||
(int)MemoryType.ThreadLocal,
|
||||
AMemoryPerm.RW);
|
||||
}
|
||||
|
||||
public void LoadProgram(IElf Program)
|
||||
{
|
||||
Executable Executable = new Executable(Program, Memory, ImageBase);
|
||||
|
||||
Executables.Add(Executable);
|
||||
|
||||
ImageBase = AMemoryHelper.PageRoundUp(Executable.ImageEnd);
|
||||
}
|
||||
|
||||
public void SetEmptyArgs()
|
||||
{
|
||||
ImageBase += AMemoryMgr.PageSize;
|
||||
}
|
||||
|
||||
public void InitializeHeap()
|
||||
{
|
||||
Memory.Manager.SetHeapAddr((ImageBase + 0x3fffffff) & ~0x3fffffff);
|
||||
}
|
||||
|
||||
public bool Run()
|
||||
{
|
||||
if (Executables.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long StackBot = TlsPageAddr - MaxStackSize;
|
||||
|
||||
Memory.Manager.MapPhys(StackBot, MaxStackSize, (int)MemoryType.Normal, AMemoryPerm.RW);
|
||||
|
||||
int Handle = MakeThread(Executables[0].ImageBase, TlsPageAddr, 0, 48, 0);
|
||||
|
||||
if (Handle == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MainThread = Ns.Os.Handles.GetData<HThread>(Handle).Thread;
|
||||
|
||||
MainThread.Execute();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void StopAllThreads()
|
||||
{
|
||||
if (MainThread != null)
|
||||
{
|
||||
while (MainThread.IsAlive)
|
||||
{
|
||||
MainThread.StopExecution();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (AThread Thread in TlsSlots.Values)
|
||||
{
|
||||
while (Thread.IsAlive)
|
||||
{
|
||||
Thread.StopExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int MakeThread(
|
||||
long EntryPoint,
|
||||
long StackTop,
|
||||
long ArgsPtr,
|
||||
int Priority,
|
||||
int ProcessorId)
|
||||
{
|
||||
AThread Thread = new AThread(Memory, EntryPoint, Priority);
|
||||
|
||||
int TlsSlot = GetFreeTlsSlot(Thread);
|
||||
|
||||
int Handle = Ns.Os.Handles.GenerateId(new HThread(Thread));
|
||||
|
||||
if (TlsSlot == -1 || Handle == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Thread.Registers.SvcCall += SvcHandler.SvcCall;
|
||||
Thread.Registers.ProcessId = ProcessId;
|
||||
Thread.Registers.ThreadId = Ns.Os.IdGen.GenerateId();
|
||||
Thread.Registers.TlsAddr = TlsPageAddr + TlsSlot * TlsSize;
|
||||
Thread.Registers.X0 = (ulong)ArgsPtr;
|
||||
Thread.Registers.X1 = (ulong)Handle;
|
||||
Thread.Registers.X31 = (ulong)StackTop;
|
||||
|
||||
Thread.WorkFinished += ThreadFinished;
|
||||
|
||||
return Handle;
|
||||
}
|
||||
|
||||
private int GetFreeTlsSlot(AThread Thread)
|
||||
{
|
||||
for (int Index = 1; Index < TotalTlsSlots; Index++)
|
||||
{
|
||||
if (TlsSlots.TryAdd(Index, Thread))
|
||||
{
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void ThreadFinished(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is AThread Thread)
|
||||
{
|
||||
TlsSlots.TryRemove(GetTlsSlot(Thread.Registers.TlsAddr), out _);
|
||||
|
||||
Ns.Os.IdGen.DeleteId(Thread.ThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetTlsSlot(long Position)
|
||||
{
|
||||
return (int)((Position - TlsPageAddr) / TlsSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Ryujinx/OsHle/ServiceCtx.cs
Normal file
52
Ryujinx/OsHle/ServiceCtx.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.OsHle
|
||||
{
|
||||
class ServiceCtx
|
||||
{
|
||||
public Switch Ns { get; private set; }
|
||||
public AMemory Memory { get; private set; }
|
||||
public HSession Session { get; private set; }
|
||||
public IpcMessage Request { get; private set; }
|
||||
public IpcMessage Response { get; private set; }
|
||||
public BinaryReader RequestData { get; private set; }
|
||||
public BinaryWriter ResponseData { get; private set; }
|
||||
|
||||
public ServiceCtx(
|
||||
Switch Ns,
|
||||
AMemory Memory,
|
||||
HSession Session,
|
||||
IpcMessage Request,
|
||||
IpcMessage Response,
|
||||
BinaryReader RequestData,
|
||||
BinaryWriter ResponseData)
|
||||
{
|
||||
this.Ns = Ns;
|
||||
this.Memory = Memory;
|
||||
this.Session = Session;
|
||||
this.Request = Request;
|
||||
this.Response = Response;
|
||||
this.RequestData = RequestData;
|
||||
this.ResponseData = ResponseData;
|
||||
}
|
||||
|
||||
public T GetObject<T>()
|
||||
{
|
||||
object Obj = null;
|
||||
|
||||
if (Session is HSessionObj SessionObj)
|
||||
{
|
||||
Obj = SessionObj.Obj;
|
||||
}
|
||||
if (Session is HDomain Dom)
|
||||
{
|
||||
Obj = Dom.GetObject(Request.DomObjId);
|
||||
}
|
||||
|
||||
return Obj is T ? (T)Obj : default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Ryujinx/OsHle/Services/ServiceAcc.cs
Normal file
33
Ryujinx/OsHle/Services/ServiceAcc.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long AccU0ListOpenUsers(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AccU0GetProfile(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AccIProfile());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AccU0InitializeApplicationInfo(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AccU0GetBaasAccountManagerForApplication(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AccIManagerForApplication());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Ryujinx/OsHle/Services/ServiceApm.cs
Normal file
16
Ryujinx/OsHle/Services/ServiceApm.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long ApmOpenSession(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new ApmISession());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Ryujinx/OsHle/Services/ServiceAppletOE.cs
Normal file
16
Ryujinx/OsHle/Services/ServiceAppletOE.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long AppletOpenApplicationProxy(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIApplicationProxy());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Ryujinx/OsHle/Services/ServiceAud.cs
Normal file
60
Ryujinx/OsHle/Services/ServiceAud.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.OsHle.Objects;
|
||||
using System.Text;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long AudOutListAudioOuts(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Position, Encoding.ASCII.GetBytes("iface"));
|
||||
|
||||
Context.ResponseData.Write(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AudOutOpenAudioOut(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(48000);
|
||||
Context.ResponseData.Write(2);
|
||||
Context.ResponseData.Write(2);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AudRenOpenAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AudIAudioRenderer());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long AudRenGetAudioRendererWorkBufferSize(ServiceCtx Context)
|
||||
{
|
||||
int SampleRate = Context.RequestData.ReadInt32();
|
||||
int Unknown4 = Context.RequestData.ReadInt32();
|
||||
int Unknown8 = Context.RequestData.ReadInt32();
|
||||
int UnknownC = Context.RequestData.ReadInt32();
|
||||
int Unknown10 = Context.RequestData.ReadInt32();
|
||||
int Unknown14 = Context.RequestData.ReadInt32();
|
||||
int Unknown18 = Context.RequestData.ReadInt32();
|
||||
int Unknown1c = Context.RequestData.ReadInt32();
|
||||
int Unknown20 = Context.RequestData.ReadInt32();
|
||||
int Unknown24 = Context.RequestData.ReadInt32();
|
||||
int Unknown28 = Context.RequestData.ReadInt32();
|
||||
int Unknown2c = Context.RequestData.ReadInt32();
|
||||
int Rev1Magic = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.ResponseData.Write(0x400L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Ryujinx/OsHle/Services/ServiceFriend.cs
Normal file
16
Ryujinx/OsHle/Services/ServiceFriend.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long FriendCreateFriendService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new FriendIFriendService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Ryujinx/OsHle/Services/ServiceFspSrv.cs
Normal file
42
Ryujinx/OsHle/Services/ServiceFspSrv.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long FspSrvInitialize(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long FspSrvMountSaveData(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new FspSrvIFileSystem(Context.Ns.VFs.GetGameSavesPath()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long FspSrvOpenDataStorageByCurrentProcess(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new FspSrvIStorage(Context.Ns.VFs.RomFs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long FspSrvOpenRomStorage(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new FspSrvIStorage(Context.Ns.VFs.RomFs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long FspSrvGetGlobalAccessLogMode(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Ryujinx/OsHle/Services/ServiceHid.cs
Normal file
56
Ryujinx/OsHle/Services/ServiceHid.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long HidCreateAppletResource(ServiceCtx Context)
|
||||
{
|
||||
HSharedMem HidHndData = Context.Ns.Os.Handles.GetData<HSharedMem>(Context.Ns.Os.HidHandle);
|
||||
|
||||
MakeObject(Context, new HidIAppletResource(HidHndData));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long HidActivateTouchScreen(ServiceCtx Context)
|
||||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long HidSetSupportedNpadStyleSet(ServiceCtx Context)
|
||||
{
|
||||
long Unknown0 = Context.RequestData.ReadInt64();
|
||||
long Unknown8 = Context.RequestData.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long HidSetSupportedNpadIdType(ServiceCtx Context)
|
||||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long HidActivateNpad(ServiceCtx Context)
|
||||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long HidSetNpadJoyHoldType(ServiceCtx Context)
|
||||
{
|
||||
long Unknown0 = Context.RequestData.ReadInt64();
|
||||
long Unknown8 = Context.RequestData.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Ryujinx/OsHle/Services/ServiceLm.cs
Normal file
12
Ryujinx/OsHle/Services/ServiceLm.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long LmInitialize(ServiceCtx Context)
|
||||
{
|
||||
Context.Session.Initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
601
Ryujinx/OsHle/Services/ServiceNvDrv.cs
Normal file
601
Ryujinx/OsHle/Services/ServiceNvDrv.cs
Normal file
@@ -0,0 +1,601 @@
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Gpu;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
using Ryujinx.OsHle.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
private delegate long ServiceProcessRequest(ServiceCtx Context);
|
||||
|
||||
private static Dictionary<(string, int), ServiceProcessRequest> IoctlCmds =
|
||||
new Dictionary<(string, int), ServiceProcessRequest>()
|
||||
{
|
||||
{ ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx },
|
||||
{ ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig },
|
||||
{ ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask },
|
||||
{ ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData },
|
||||
{ ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap },
|
||||
{ ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo },
|
||||
{ ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx },
|
||||
{ ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind },
|
||||
{ ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier },
|
||||
{ ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority },
|
||||
{ ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 },
|
||||
{ ("/dev/nvmap", 0x0101), NvMapIocCreate },
|
||||
{ ("/dev/nvmap", 0x0103), NvMapIocFromId },
|
||||
{ ("/dev/nvmap", 0x0104), NvMapIocAlloc },
|
||||
{ ("/dev/nvmap", 0x0109), NvMapIocParam },
|
||||
{ ("/dev/nvmap", 0x010e), NvMapIocGetId },
|
||||
};
|
||||
|
||||
public static long NvDrvOpen(ServiceCtx Context)
|
||||
{
|
||||
long NamePtr = Context.Request.SendBuff[0].Position;
|
||||
|
||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
|
||||
|
||||
int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name));
|
||||
|
||||
Context.ResponseData.Write(Fd);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long NvDrvIoctl(ServiceCtx Context)
|
||||
{
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
int Cmd = Context.RequestData.ReadInt32() & 0xffff;
|
||||
|
||||
FileDesc FdData = Context.Ns.Os.Fds.GetData<FileDesc>(Fd);
|
||||
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessRequest ProcReq))
|
||||
{
|
||||
return ProcReq(Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"{FdData.Name} {Cmd:x4}");
|
||||
}
|
||||
}
|
||||
|
||||
public static long NvDrvClose(ServiceCtx Context)
|
||||
{
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.Ns.Os.Fds.Delete(Fd);
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long NvDrvInitialize(ServiceCtx Context)
|
||||
{
|
||||
long TransferMemSize = Context.RequestData.ReadInt64();
|
||||
int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long NvDrvQueryEvent(ServiceCtx Context)
|
||||
{
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
int EventId = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe);
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuAsIoctlBindChannel(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
int Fd = Context.Memory.ReadInt32(Position);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int Pages = Reader.ReadInt32();
|
||||
int PageSize = Reader.ReadInt32();
|
||||
int Flags = Reader.ReadInt32();
|
||||
int Padding = Reader.ReadInt32();
|
||||
long Align = Reader.ReadInt64();
|
||||
|
||||
if ((Flags & 1) != 0)
|
||||
{
|
||||
Align = Context.Ns.Gpu.MemoryMgr.Reserve(Align, (long)Pages * PageSize, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Align = Context.Ns.Gpu.MemoryMgr.Reserve((long)Pages * PageSize, Align);
|
||||
}
|
||||
|
||||
Context.Memory.WriteInt64(Position + 0x10, Align);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int Flags = Reader.ReadInt32();
|
||||
int Kind = Reader.ReadInt32();
|
||||
int Handle = Reader.ReadInt32();
|
||||
int PageSize = Reader.ReadInt32();
|
||||
long BuffAddr = Reader.ReadInt64();
|
||||
long MapSize = Reader.ReadInt64();
|
||||
long Offset = Reader.ReadInt64();
|
||||
|
||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
||||
|
||||
if (NvMap != null)
|
||||
{
|
||||
if ((Flags & 1) != 0)
|
||||
{
|
||||
Offset = Context.Ns.Gpu.MemoryMgr.Map(NvMap.Address, Offset, NvMap.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Offset = Context.Ns.Gpu.MemoryMgr.Map(NvMap.Address, NvMap.Size);
|
||||
}
|
||||
}
|
||||
|
||||
Context.Memory.WriteInt64(Position + 0x20, Offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
MemWriter Writer = new MemWriter(Context.Memory, Position);
|
||||
|
||||
long Unused = Reader.ReadInt64();
|
||||
int BuffSize = Reader.ReadInt32();
|
||||
int Padding = Reader.ReadInt32();
|
||||
|
||||
BuffSize = 0x30;
|
||||
|
||||
Writer.WriteInt64(Unused);
|
||||
Writer.WriteInt32(BuffSize);
|
||||
Writer.WriteInt32(Padding);
|
||||
|
||||
Writer.WriteInt64(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt64(0);
|
||||
|
||||
Writer.WriteInt64(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt64(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int BigPageSize = Reader.ReadInt32();
|
||||
int AsFd = Reader.ReadInt32();
|
||||
int Flags = Reader.ReadInt32();
|
||||
int Reserved = Reader.ReadInt32();
|
||||
long Unknown10 = Reader.ReadInt64();
|
||||
long Unknown18 = Reader.ReadInt64();
|
||||
long Unknown20 = Reader.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82);
|
||||
|
||||
for (int Index = 0; Index < 0x101; Index++)
|
||||
{
|
||||
Writer.WriteByte(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvHostIoctlCtrlEventWait(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int SyncPtId = Reader.ReadInt32();
|
||||
int Threshold = Reader.ReadInt32();
|
||||
int Timeout = Reader.ReadInt32();
|
||||
int Value = Reader.ReadInt32();
|
||||
|
||||
Context.Memory.WriteInt32(Position + 0xc, 0xcafe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
Context.Memory.WriteInt32(Position, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemWriter Writer = new MemWriter(Context.Memory, Position);
|
||||
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
MemWriter Writer = new MemWriter(Context.Memory, Position);
|
||||
|
||||
//Note: We should just ignore the BuffAddr, because official code
|
||||
//does __memcpy_device from Position + 0x10 to BuffAddr.
|
||||
long BuffSize = Reader.ReadInt64();
|
||||
long BuffAddr = Reader.ReadInt64();
|
||||
|
||||
BuffSize = 0xa0;
|
||||
|
||||
Writer.WriteInt64(BuffSize);
|
||||
Writer.WriteInt64(BuffAddr);
|
||||
Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200
|
||||
Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B
|
||||
Writer.WriteInt32(0xa1);
|
||||
Writer.WriteInt32(1);
|
||||
Writer.WriteInt64(0x40000);
|
||||
Writer.WriteInt64(0);
|
||||
Writer.WriteInt32(2);
|
||||
Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI
|
||||
Writer.WriteInt32(0x20000);
|
||||
Writer.WriteInt32(0x20000);
|
||||
Writer.WriteInt32(0x1b);
|
||||
Writer.WriteInt32(0x30000);
|
||||
Writer.WriteInt32(1);
|
||||
Writer.WriteInt32(0x503);
|
||||
Writer.WriteInt32(0x503);
|
||||
Writer.WriteInt32(0x80);
|
||||
Writer.WriteInt32(0x28);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt64(0x55);
|
||||
Writer.WriteInt32(0x902d); //FERMI_TWOD_A
|
||||
Writer.WriteInt32(0xb197); //MAXWELL_B
|
||||
Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B
|
||||
Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A
|
||||
Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B
|
||||
Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A
|
||||
Writer.WriteInt32(1);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(2);
|
||||
Writer.WriteInt32(1);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(1);
|
||||
Writer.WriteInt32(0x21d70);
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteByte((byte)'g');
|
||||
Writer.WriteByte((byte)'m');
|
||||
Writer.WriteByte((byte)'2');
|
||||
Writer.WriteByte((byte)'0');
|
||||
Writer.WriteByte((byte)'b');
|
||||
Writer.WriteByte((byte)'\0');
|
||||
Writer.WriteByte((byte)'\0');
|
||||
Writer.WriteByte((byte)'\0');
|
||||
Writer.WriteInt64(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int MaskBuffSize = Reader.ReadInt32();
|
||||
int Reserved = Reader.ReadInt32();
|
||||
long MaskBuffAddr = Reader.ReadInt64();
|
||||
long Unknown = Reader.ReadInt64();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
Context.Memory.WriteInt32(Position + 0, 7);
|
||||
Context.Memory.WriteInt32(Position + 4, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelSetUserData(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
int Fd = Context.Memory.ReadInt32(Position);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10);
|
||||
|
||||
long GpFifo = Reader.ReadInt64();
|
||||
int Count = Reader.ReadInt32();
|
||||
int Flags = Reader.ReadInt32();
|
||||
int FenceId = Reader.ReadInt32();
|
||||
int FenceVal = Reader.ReadInt32();
|
||||
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
long GpFifoHdr = Reader.ReadInt64();
|
||||
|
||||
long GpuAddr = GpFifoHdr & 0xffffffffff;
|
||||
|
||||
int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc;
|
||||
|
||||
long CpuAddr = Context.Ns.Gpu.MemoryMgr.GetCpuAddr(GpuAddr);
|
||||
|
||||
if (CpuAddr != -1)
|
||||
{
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size);
|
||||
|
||||
NsGpuPBEntry[] PushBuffer = NsGpuPBEntry.DecodePushBuffer(Data);
|
||||
|
||||
Context.Ns.Gpu.PGraph.ProcessPushBuffer(PushBuffer, Context.Memory);
|
||||
}
|
||||
}
|
||||
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
int ClassNum = Context.Memory.ReadInt32(Position + 0);
|
||||
int Flags = Context.Memory.ReadInt32(Position + 4);
|
||||
|
||||
Context.Memory.WriteInt32(Position + 8, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelZcullBind(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
long GpuVa = Reader.ReadInt64();
|
||||
int Mode = Reader.ReadInt32();
|
||||
int Padding = Reader.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
long Offset = Reader.ReadInt64();
|
||||
long Size = Reader.ReadInt64();
|
||||
int Mem = Reader.ReadInt32();
|
||||
int Padding = Reader.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelSetPriority(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
int Priority = Context.Memory.ReadInt32(Position);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc);
|
||||
|
||||
int Count = Reader.ReadInt32();
|
||||
int Flags = Reader.ReadInt32();
|
||||
int Unknown8 = Reader.ReadInt32();
|
||||
long Fence = Reader.ReadInt64();
|
||||
int Unknown14 = Reader.ReadInt32();
|
||||
int Unknown18 = Reader.ReadInt32();
|
||||
|
||||
Writer.WriteInt32(0);
|
||||
Writer.WriteInt32(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIocCreate(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
int Size = Context.Memory.ReadInt32(Position);
|
||||
|
||||
int Id = Context.Ns.Os.NvMapIds.GenerateId();
|
||||
|
||||
int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size));
|
||||
|
||||
Context.Memory.WriteInt32(Position + 4, Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIocFromId(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
int Id = Context.Memory.ReadInt32(Position);
|
||||
|
||||
int Handle = -1;
|
||||
|
||||
foreach (KeyValuePair<int, object> KV in Context.Ns.Os.Handles)
|
||||
{
|
||||
if (KV.Value is HNvMap NvMap && NvMap.Id == Id)
|
||||
{
|
||||
Handle = KV.Key;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Context.Memory.WriteInt32(Position + 4, Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIocAlloc(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int Handle = Reader.ReadInt32();
|
||||
int HeapMask = Reader.ReadInt32();
|
||||
int Flags = Reader.ReadInt32();
|
||||
int Align = Reader.ReadInt32();
|
||||
byte Kind = (byte)Reader.ReadInt64();
|
||||
long Addr = Reader.ReadInt64();
|
||||
|
||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
||||
|
||||
if (NvMap != null)
|
||||
{
|
||||
NvMap.Address = Addr;
|
||||
NvMap.Align = Align;
|
||||
NvMap.Kind = Kind;
|
||||
}
|
||||
|
||||
Console.WriteLine($"NvMapIocAlloc at {NvMap.Address:x16}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIocParam(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int Handle = Reader.ReadInt32();
|
||||
int Param = Reader.ReadInt32();
|
||||
|
||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
||||
|
||||
int Response = 0;
|
||||
|
||||
switch (Param)
|
||||
{
|
||||
case 1: Response = NvMap.Size; break;
|
||||
case 2: Response = NvMap.Align; break;
|
||||
case 4: Response = 0x40000000; break;
|
||||
case 5: Response = NvMap.Kind; break;
|
||||
}
|
||||
|
||||
Context.Memory.WriteInt32(Position + 8, Response);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static long NvMapIocGetId(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
int Handle = Context.Memory.ReadInt32(Position + 4);
|
||||
|
||||
HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
|
||||
|
||||
Context.Memory.WriteInt32(Position, NvMap.Id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Ryujinx/OsHle/Services/ServicePctl.cs
Normal file
16
Ryujinx/OsHle/Services/ServicePctl.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long PctlCreateService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new AmIParentalControlService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Ryujinx/OsHle/Services/ServicePl.cs
Normal file
35
Ryujinx/OsHle/Services/ServicePl.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long PlGetLoadState(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(1); //Loaded
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long PlGetFontSize(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(Horizon.FontSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long PlGetSharedMemoryAddressOffset(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long PlGetSharedMemoryNativeHandle(ServiceCtx Context)
|
||||
{
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Ryujinx/OsHle/Services/ServiceSet.cs
Normal file
32
Ryujinx/OsHle/Services/ServiceSet.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using ChocolArm64.Memory;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
private const int LangCodesCount = 13;
|
||||
|
||||
public static long SetGetAvailableLanguageCodes(ServiceCtx Context)
|
||||
{
|
||||
int PtrBuffSize = Context.RequestData.ReadInt32();
|
||||
|
||||
if (Context.Request.RecvListBuff.Count > 0)
|
||||
{
|
||||
long Position = Context.Request.RecvListBuff[0].Position;
|
||||
short Size = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
//This should return an array of ints with values matching the LanguageCode enum.
|
||||
byte[] Data = new byte[Size];
|
||||
|
||||
Data[0] = 0;
|
||||
Data[1] = 1;
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
|
||||
}
|
||||
|
||||
Context.ResponseData.Write(LangCodesCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Ryujinx/OsHle/Services/ServiceSm.cs
Normal file
48
Ryujinx/OsHle/Services/ServiceSm.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
private const int SmNotInitialized = 0x415;
|
||||
|
||||
public static long SmInitialize(ServiceCtx Context)
|
||||
{
|
||||
Context.Session.Initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long SmGetService(ServiceCtx Context)
|
||||
{
|
||||
//Only for kernel version > 3.0.0.
|
||||
if (!Context.Session.IsInitialized)
|
||||
{
|
||||
//return SmNotInitialized;
|
||||
}
|
||||
|
||||
string Name = string.Empty;
|
||||
|
||||
for (int Index = 0; Index < 8 &&
|
||||
Context.RequestData.BaseStream.Position <
|
||||
Context.RequestData.BaseStream.Length; Index++)
|
||||
{
|
||||
byte Chr = Context.RequestData.ReadByte();
|
||||
|
||||
if (Chr >= 0x20 && Chr < 0x7f)
|
||||
{
|
||||
Name += (char)Chr;
|
||||
}
|
||||
}
|
||||
|
||||
HSession Session = new HSession(Name);
|
||||
|
||||
int Handle = Context.Ns.Os.Handles.GenerateId(Session);
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Ryujinx/OsHle/Services/ServiceTime.cs
Normal file
37
Ryujinx/OsHle/Services/ServiceTime.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long TimeGetStandardUserSystemClock(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new TimeISystemClock());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long TimeGetStandardNetworkSystemClock(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new TimeISystemClock());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long TimeGetStandardSteadyClock(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new TimeISteadyClock());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long TimeGetTimeZoneService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new TimeITimeZoneService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Ryujinx/OsHle/Services/ServiceVi.cs
Normal file
18
Ryujinx/OsHle/Services/ServiceVi.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Ryujinx.OsHle.Objects;
|
||||
|
||||
using static Ryujinx.OsHle.Objects.ObjHelper;
|
||||
|
||||
namespace Ryujinx.OsHle.Services
|
||||
{
|
||||
static partial class Service
|
||||
{
|
||||
public static long ViGetDisplayService(ServiceCtx Context)
|
||||
{
|
||||
int Unknown = Context.RequestData.ReadInt32();
|
||||
|
||||
MakeObject(Context, new ViIApplicationDisplayService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Ryujinx/OsHle/Svc/SvcHandler.cs
Normal file
79
Ryujinx/OsHle/Svc/SvcHandler.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.OsHle.Svc
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private delegate void SvcFunc(Switch Ns, ARegisters Registers, AMemory Memory);
|
||||
|
||||
private Dictionary<int, SvcFunc> SvcFuncs = new Dictionary<int, SvcFunc>()
|
||||
{
|
||||
{ 0x01, SvcSetHeapSize },
|
||||
{ 0x03, SvcSetMemoryAttribute },
|
||||
{ 0x04, SvcMapMemory },
|
||||
{ 0x06, SvcQueryMemory },
|
||||
{ 0x08, SvcCreateThread },
|
||||
{ 0x09, SvcStartThread },
|
||||
{ 0x0b, SvcSleepThread },
|
||||
{ 0x0c, SvcGetThreadPriority },
|
||||
{ 0x13, SvcMapSharedMemory },
|
||||
{ 0x14, SvcUnmapSharedMemory },
|
||||
{ 0x15, SvcCreateTransferMemory },
|
||||
{ 0x16, SvcCloseHandle },
|
||||
{ 0x17, SvcResetSignal },
|
||||
{ 0x18, SvcWaitSynchronization },
|
||||
{ 0x1a, SvcArbitrateLock },
|
||||
{ 0x1b, SvcArbitrateUnlock },
|
||||
{ 0x1c, SvcWaitProcessWideKeyAtomic },
|
||||
{ 0x1d, SvcSignalProcessWideKey },
|
||||
{ 0x1e, SvcGetSystemTick },
|
||||
{ 0x1f, SvcConnectToNamedPort },
|
||||
{ 0x21, SvcSendSyncRequest },
|
||||
{ 0x22, SvcSendSyncRequestWithUserBuffer },
|
||||
{ 0x26, SvcBreak },
|
||||
{ 0x27, SvcOutputDebugString },
|
||||
{ 0x29, SvcGetInfo }
|
||||
};
|
||||
|
||||
enum SvcResult
|
||||
{
|
||||
Success = 0,
|
||||
ErrBadHandle = 0xe401,
|
||||
ErrTimeout = 0xea01,
|
||||
ErrBadIpcReq = 0xf601,
|
||||
}
|
||||
|
||||
private Switch Ns;
|
||||
private AMemory Memory;
|
||||
|
||||
private static Random Rng;
|
||||
|
||||
public SvcHandler(Switch Ns, AMemory Memory)
|
||||
{
|
||||
this.Ns = Ns;
|
||||
this.Memory = Memory;
|
||||
}
|
||||
|
||||
static SvcHandler()
|
||||
{
|
||||
Rng = new Random();
|
||||
}
|
||||
|
||||
public void SvcCall(object sender, SvcEventArgs e)
|
||||
{
|
||||
ARegisters Registers = (ARegisters)sender;
|
||||
|
||||
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
||||
{
|
||||
Func(Ns, Registers, Memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(e.Id.ToString("x3"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Ryujinx/OsHle/Svc/SvcMemory.cs
Normal file
126
Ryujinx/OsHle/Svc/SvcMemory.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
|
||||
namespace Ryujinx.OsHle.Svc
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private static void SvcSetHeapSize(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Size = (int)Registers.X1;
|
||||
|
||||
Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
Registers.X1 = (ulong)Memory.Manager.HeapAddr;
|
||||
}
|
||||
|
||||
private static void SvcSetMemoryAttribute(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long Position = (long)Registers.X0;
|
||||
long Size = (long)Registers.X1;
|
||||
int State0 = (int)Registers.X2;
|
||||
int State1 = (int)Registers.X3;
|
||||
|
||||
//TODO
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcMapMemory(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long Src = (long)Registers.X0;
|
||||
long Dst = (long)Registers.X1;
|
||||
long Size = (long)Registers.X2;
|
||||
|
||||
Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcQueryMemory(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long InfoPtr = (long)Registers.X0;
|
||||
long Position = (long)Registers.X2;
|
||||
|
||||
AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position);
|
||||
|
||||
MemoryInfo Info = new MemoryInfo(MapInfo);
|
||||
|
||||
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);
|
||||
|
||||
//TODO: X1.
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
Registers.X1 = 0;
|
||||
}
|
||||
|
||||
private static void SvcMapSharedMemory(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Handle = (int)Registers.X0;
|
||||
long Position = (long)Registers.X1;
|
||||
long Size = (long)Registers.X2;
|
||||
int Perm = (int)Registers.X3;
|
||||
|
||||
HSharedMem HndData = Ns.Os.Handles.GetData<HSharedMem>(Handle);
|
||||
|
||||
if (HndData != null)
|
||||
{
|
||||
long Src = Position;
|
||||
long Dst = HndData.PhysPos;
|
||||
|
||||
if (Memory.Manager.MapPhys(Src, Dst, Size,
|
||||
(int)MemoryType.SharedMemory, (AMemoryPerm)Perm))
|
||||
{
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private static void SvcUnmapSharedMemory(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Handle = (int)Registers.X0;
|
||||
long Position = (long)Registers.X1;
|
||||
long Size = (long)Registers.X2;
|
||||
|
||||
HSharedMem HndData = Ns.Os.Handles.GetData<HSharedMem>(Handle);
|
||||
|
||||
if (HndData != null)
|
||||
{
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private static void SvcCreateTransferMemory(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long Position = (long)Registers.X1;
|
||||
long Size = (long)Registers.X2;
|
||||
int Perm = (int)Registers.X3;
|
||||
|
||||
AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position);
|
||||
|
||||
Memory.Manager.Reprotect(Position, Size, (AMemoryPerm)Perm);
|
||||
|
||||
long PhysPos = Memory.Manager.GetPhys(Position, AMemoryPerm.None);
|
||||
|
||||
HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Position, Size, PhysPos);
|
||||
|
||||
int Handle = Ns.Os.Handles.GenerateId(HndData);
|
||||
|
||||
Registers.X1 = (ulong)Handle;
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
163
Ryujinx/OsHle/Svc/SvcSystem.cs
Normal file
163
Ryujinx/OsHle/Svc/SvcSystem.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using Ryujinx.OsHle.Ipc;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.OsHle.Svc
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private static void SvcCloseHandle(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Handle = (int)Registers.X0;
|
||||
|
||||
Ns.Os.CloseHandle(Handle);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcResetSignal(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Handle = (int)Registers.X0;
|
||||
|
||||
//TODO: Implement events.
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcWaitSynchronization(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long HandlesPtr = (long)Registers.X0;
|
||||
int HandlesCount = (int)Registers.X2;
|
||||
long Timeout = (long)Registers.X3;
|
||||
|
||||
//TODO: Implement events.
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcGetSystemTick(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
Registers.X0 = (ulong)Registers.GetSystemReg(3, 3, 14, 0, 1);
|
||||
}
|
||||
|
||||
private static void SvcConnectToNamedPort(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long StackPtr = (long)Registers.X0;
|
||||
long NamePtr = (long)Registers.X1;
|
||||
|
||||
string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8);
|
||||
|
||||
//TODO: Validate that app has perms to access the service, and that the service
|
||||
//actually exists, return error codes otherwise.
|
||||
|
||||
HSession Session = new HSession(Name);
|
||||
|
||||
Registers.X1 = (ulong)Ns.Os.Handles.GenerateId(Session);
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcSendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
SendSyncRequest(Ns, Registers, Memory, false);
|
||||
}
|
||||
|
||||
private static void SvcSendSyncRequestWithUserBuffer(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
SendSyncRequest(Ns, Registers, Memory, true);
|
||||
}
|
||||
|
||||
private static void SendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory, bool IsUser)
|
||||
{
|
||||
long CmdPtr = Registers.TlsAddr;
|
||||
long Size = 0x100;
|
||||
int Handle = 0;
|
||||
|
||||
if (IsUser)
|
||||
{
|
||||
CmdPtr = (long)Registers.X0;
|
||||
Size = (long)Registers.X1;
|
||||
Handle = (int)Registers.X2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle = (int)Registers.X0;
|
||||
}
|
||||
|
||||
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
|
||||
|
||||
HSession Session = Ns.Os.Handles.GetData<HSession>(Handle);
|
||||
|
||||
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
|
||||
|
||||
if (Session != null)
|
||||
{
|
||||
IpcHandler.ProcessRequest(Ns, Memory, Session, Cmd, CmdPtr, Handle);
|
||||
|
||||
byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Registers.X0 = (int)SvcResult.ErrBadIpcReq;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SvcBreak(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long Reason = (long)Registers.X0;
|
||||
long Unknown = (long)Registers.X1;
|
||||
long Info = (long)Registers.X2;
|
||||
|
||||
throw new Exception($"SvcBreak: {Reason} {Unknown} {Info}");
|
||||
}
|
||||
|
||||
private static void SvcOutputDebugString(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long Position = (long)Registers.X0;
|
||||
long Size = (long)Registers.X1;
|
||||
|
||||
string Str = AMemoryHelper.ReadAsciiString(Memory, Position, (int)Size);
|
||||
|
||||
Console.WriteLine($"SvcOutputDebugString: {Str}");
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcGetInfo(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long StackPtr = (long)Registers.X0;
|
||||
int InfoType = (int)Registers.X1;
|
||||
long Handle = (long)Registers.X2;
|
||||
int InfoId = (int)Registers.X3;
|
||||
|
||||
switch (InfoType)
|
||||
{
|
||||
case 6: Registers.X1 = GetTotalMem(Memory); break;
|
||||
case 7: Registers.X1 = GetUsedMem(Memory); break;
|
||||
case 11: Registers.X1 = GetRnd64(); break;
|
||||
|
||||
default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}");
|
||||
}
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static ulong GetTotalMem(AMemory Memory)
|
||||
{
|
||||
return (ulong)Memory.Manager.GetTotalMemorySize();
|
||||
}
|
||||
|
||||
private static ulong GetUsedMem(AMemory Memory)
|
||||
{
|
||||
return (ulong)Memory.Manager.GetUsedMemorySize();
|
||||
}
|
||||
|
||||
private static ulong GetRnd64()
|
||||
{
|
||||
return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Ryujinx/OsHle/Svc/SvcThread.cs
Normal file
79
Ryujinx/OsHle/Svc/SvcThread.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.OsHle.Svc
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private static void SvcCreateThread(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long EntryPoint = (long)Registers.X1;
|
||||
long ArgsPtr = (long)Registers.X2;
|
||||
long StackTop = (long)Registers.X3;
|
||||
int Priority = (int)Registers.X4;
|
||||
int ProcessorId = (int)Registers.X5;
|
||||
|
||||
if (Ns.Os.TryGetProcess(Registers.ProcessId, out Process Process))
|
||||
{
|
||||
int Handle = Process.MakeThread(
|
||||
EntryPoint,
|
||||
StackTop,
|
||||
ArgsPtr,
|
||||
Priority,
|
||||
ProcessorId);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
Registers.X1 = (ulong)Handle;
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private static void SvcStartThread(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Handle = (int)Registers.X0;
|
||||
|
||||
HThread HndData = Ns.Os.Handles.GetData<HThread>(Handle);
|
||||
|
||||
if (HndData != null)
|
||||
{
|
||||
HndData.Thread.Execute();
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private static void SvcSleepThread(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
ulong NanoSecs = Registers.X0;
|
||||
|
||||
if (NanoSecs == 0)
|
||||
{
|
||||
Thread.Yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep((int)(NanoSecs / 1000000));
|
||||
}
|
||||
}
|
||||
|
||||
private static void SvcGetThreadPriority(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int Handle = (int)Registers.X1;
|
||||
|
||||
HThread HndData = Ns.Os.Handles.GetData<HThread>(Handle);
|
||||
|
||||
if (HndData != null)
|
||||
{
|
||||
Registers.X1 = (ulong)HndData.Thread.Priority;
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
}
|
||||
}
|
||||
87
Ryujinx/OsHle/Svc/SvcThreadSync.cs
Normal file
87
Ryujinx/OsHle/Svc/SvcThreadSync.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using ChocolArm64;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.OsHle.Handles;
|
||||
|
||||
namespace Ryujinx.OsHle.Svc
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private static void SvcArbitrateLock(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
int OwnerThreadHandle = (int)Registers.X0;
|
||||
long MutexAddress = (long)Registers.X1;
|
||||
int RequestingThreadHandle = (int)Registers.X2;
|
||||
|
||||
AThread RequestingThread = Ns.Os.Handles.GetData<HThread>(RequestingThreadHandle).Thread;
|
||||
|
||||
Mutex M = new Mutex(Memory, MutexAddress);
|
||||
|
||||
M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M);
|
||||
|
||||
//FIXME
|
||||
//M.WaitForLock(RequestingThread, RequestingThreadHandle);
|
||||
|
||||
Memory.WriteInt32(MutexAddress, 0);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcArbitrateUnlock(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long MutexAddress = (long)Registers.X0;
|
||||
|
||||
if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M))
|
||||
{
|
||||
M.Unlock();
|
||||
}
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcWaitProcessWideKeyAtomic(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long MutexAddress = (long)Registers.X0;
|
||||
long CondVarAddress = (long)Registers.X1;
|
||||
int ThreadHandle = (int)Registers.X2;
|
||||
long Timeout = (long)Registers.X3;
|
||||
|
||||
AThread Thread = Ns.Os.Handles.GetData<HThread>(ThreadHandle).Thread;
|
||||
|
||||
if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M))
|
||||
{
|
||||
M.GiveUpLock(ThreadHandle);
|
||||
}
|
||||
|
||||
CondVar Signal = new CondVar(Memory, CondVarAddress, Timeout);
|
||||
|
||||
Signal = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Signal);
|
||||
|
||||
Signal.WaitForSignal(ThreadHandle);
|
||||
|
||||
M = new Mutex(Memory, MutexAddress);
|
||||
|
||||
M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M);
|
||||
|
||||
//FIXME
|
||||
//M.WaitForLock(Thread, ThreadHandle);
|
||||
|
||||
Memory.WriteInt32(MutexAddress, 0);
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
private static void SvcSignalProcessWideKey(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||
{
|
||||
long CondVarAddress = (long)Registers.X0;
|
||||
int Count = (int)Registers.X1;
|
||||
|
||||
if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv))
|
||||
{
|
||||
Cv.SetSignal(Count);
|
||||
}
|
||||
|
||||
Registers.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Ryujinx/OsHle/Utilities/IdPool.cs
Normal file
53
Ryujinx/OsHle/Utilities/IdPool.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.OsHle.Utilities
|
||||
{
|
||||
class IdPool
|
||||
{
|
||||
private HashSet<int> Ids;
|
||||
|
||||
private int CurrId;
|
||||
private int MinId;
|
||||
private int MaxId;
|
||||
|
||||
public IdPool(int Min, int Max)
|
||||
{
|
||||
Ids = new HashSet<int>();
|
||||
|
||||
CurrId = Min;
|
||||
MinId = Min;
|
||||
MaxId = Max;
|
||||
}
|
||||
|
||||
public IdPool() : this(1, int.MaxValue) { }
|
||||
|
||||
public int GenerateId()
|
||||
{
|
||||
lock (Ids)
|
||||
{
|
||||
for (int Cnt = MinId; Cnt < MaxId; Cnt++)
|
||||
{
|
||||
if (Ids.Add(CurrId))
|
||||
{
|
||||
return CurrId;
|
||||
}
|
||||
|
||||
if (CurrId++ == MaxId)
|
||||
{
|
||||
CurrId = MinId;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DeleteId(int Id)
|
||||
{
|
||||
lock (Ids)
|
||||
{
|
||||
return Ids.Remove(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Ryujinx/OsHle/Utilities/IdPoolWithObj.cs
Normal file
78
Ryujinx/OsHle/Utilities/IdPoolWithObj.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.OsHle.Utilities
|
||||
{
|
||||
class IdPoolWithObj : IEnumerable<KeyValuePair<int, object>>
|
||||
{
|
||||
private IdPool Ids;
|
||||
|
||||
private ConcurrentDictionary<int, object> Objs;
|
||||
|
||||
public IdPoolWithObj()
|
||||
{
|
||||
Ids = new IdPool();
|
||||
|
||||
Objs = new ConcurrentDictionary<int, object>();
|
||||
}
|
||||
|
||||
public int GenerateId(object Data)
|
||||
{
|
||||
int Id = Ids.GenerateId();
|
||||
|
||||
if (Id == -1 || !Objs.TryAdd(Id, Data))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return Id;
|
||||
}
|
||||
|
||||
public bool ReplaceData(int Id, object Data)
|
||||
{
|
||||
if (Objs.ContainsKey(Id))
|
||||
{
|
||||
Objs[Id] = Data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T GetData<T>(int Id)
|
||||
{
|
||||
if (Objs.TryGetValue(Id, out object Data) && Data is T)
|
||||
{
|
||||
return (T)Data;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public void Delete(int Id)
|
||||
{
|
||||
if (Objs.TryRemove(Id, out object Obj))
|
||||
{
|
||||
if (Obj is IDisposable DisposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
|
||||
Ids.DeleteId(Id);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<int, object>> IEnumerable<KeyValuePair<int, object>>.GetEnumerator()
|
||||
{
|
||||
return Objs.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return Objs.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Ryujinx/OsHle/Utilities/MemReader.cs
Normal file
44
Ryujinx/OsHle/Utilities/MemReader.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using ChocolArm64.Memory;
|
||||
|
||||
namespace Ryujinx.OsHle.Utilities
|
||||
{
|
||||
class MemReader
|
||||
{
|
||||
private AMemory Memory;
|
||||
|
||||
public long Position { get; private set; }
|
||||
|
||||
public MemReader(AMemory Memory, long Position)
|
||||
{
|
||||
this.Memory = Memory;
|
||||
this.Position = Position;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
byte Value = Memory.ReadByte(Position);
|
||||
|
||||
Position++;
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
int Value = Memory.ReadInt32(Position);
|
||||
|
||||
Position += 4;
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
public long ReadInt64()
|
||||
{
|
||||
long Value = Memory.ReadInt64(Position);
|
||||
|
||||
Position += 8;
|
||||
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Ryujinx/OsHle/Utilities/MemWriter.cs
Normal file
38
Ryujinx/OsHle/Utilities/MemWriter.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using ChocolArm64.Memory;
|
||||
|
||||
namespace Ryujinx.OsHle.Utilities
|
||||
{
|
||||
class MemWriter
|
||||
{
|
||||
private AMemory Memory;
|
||||
|
||||
public long Position { get; private set; }
|
||||
|
||||
public MemWriter(AMemory Memory, long Position)
|
||||
{
|
||||
this.Memory = Memory;
|
||||
this.Position = Position;
|
||||
}
|
||||
|
||||
public void WriteByte(byte Value)
|
||||
{
|
||||
Memory.WriteByte(Position, Value);
|
||||
|
||||
Position++;
|
||||
}
|
||||
|
||||
public void WriteInt32(int Value)
|
||||
{
|
||||
Memory.WriteInt32(Position, Value);
|
||||
|
||||
Position += 4;
|
||||
}
|
||||
|
||||
public void WriteInt64(long Value)
|
||||
{
|
||||
Memory.WriteInt64(Position, Value);
|
||||
|
||||
Position += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user