aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/OsHle/Svc
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/Svc
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'Ryujinx.Core/OsHle/Svc')
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcHandler.cs80
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcMemory.cs121
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcResult.cs11
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcSystem.cs227
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcThread.cs85
-rw-r--r--Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs78
6 files changed, 602 insertions, 0 deletions
diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
new file mode 100644
index 00000000..60af1e11
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
@@ -0,0 +1,80 @@
+using ChocolArm64.Memory;
+using ChocolArm64.State;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle.Svc
+{
+ partial class SvcHandler
+ {
+ private delegate void SvcFunc(AThreadState ThreadState);
+
+ private Dictionary<int, SvcFunc> SvcFuncs;
+
+ private Switch Ns;
+ private Process Process;
+ private AMemory Memory;
+
+ private static Random Rng;
+
+ public SvcHandler(Switch Ns, Process Process)
+ {
+ SvcFuncs = new Dictionary<int, SvcFunc>()
+ {
+ { 0x01, SvcSetHeapSize },
+ { 0x03, SvcSetMemoryAttribute },
+ { 0x04, SvcMapMemory },
+ { 0x06, SvcQueryMemory },
+ { 0x07, SvcExitProcess },
+ { 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 }
+ };
+
+ this.Ns = Ns;
+ this.Process = Process;
+ this.Memory = Process.Memory;
+ }
+
+ static SvcHandler()
+ {
+ Rng = new Random();
+ }
+
+ public void SvcCall(object sender, AInstExceptEventArgs e)
+ {
+ AThreadState ThreadState = (AThreadState)sender;
+
+ if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
+ {
+ Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} called.");
+
+ Func(ThreadState);
+
+ Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} ended.");
+ }
+ else
+ {
+ throw new NotImplementedException(e.Id.ToString("x4"));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
new file mode 100644
index 00000000..7528f4e0
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
@@ -0,0 +1,121 @@
+using ChocolArm64.Memory;
+using ChocolArm64.State;
+using Ryujinx.Core.OsHle.Handles;
+
+namespace Ryujinx.Core.OsHle.Svc
+{
+ partial class SvcHandler
+ {
+ private void SvcSetHeapSize(AThreadState ThreadState)
+ {
+ uint Size = (uint)ThreadState.X1;
+
+ Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ ThreadState.X1 = (ulong)Memory.Manager.HeapAddr;
+ }
+
+ private void SvcSetMemoryAttribute(AThreadState ThreadState)
+ {
+ long Position = (long)ThreadState.X0;
+ long Size = (long)ThreadState.X1;
+ int State0 = (int)ThreadState.X2;
+ int State1 = (int)ThreadState.X3;
+
+ //TODO
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcMapMemory(AThreadState ThreadState)
+ {
+ long Dst = (long)ThreadState.X0;
+ long Src = (long)ThreadState.X1;
+ long Size = (long)ThreadState.X2;
+
+ Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcQueryMemory(AThreadState ThreadState)
+ {
+ long InfoPtr = (long)ThreadState.X0;
+ long Position = (long)ThreadState.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.
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ ThreadState.X1 = 0;
+ }
+
+ private void SvcMapSharedMemory(AThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X0;
+ long Src = (long)ThreadState.X1;
+ long Size = (long)ThreadState.X2;
+ int Perm = (int)ThreadState.X3;
+
+ HSharedMem SharedMem = Ns.Os.Handles.GetData<HSharedMem>(Handle);
+
+ if (SharedMem != null)
+ {
+ SharedMem.AddVirtualPosition(Src);
+
+ Memory.Manager.MapPhys(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ //TODO: Error codes.
+ }
+
+ private void SvcUnmapSharedMemory(AThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X0;
+ long Position = (long)ThreadState.X1;
+ long Size = (long)ThreadState.X2;
+
+ HSharedMem HndData = Ns.Os.Handles.GetData<HSharedMem>(Handle);
+
+ if (HndData != null)
+ {
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ //TODO: Error codes.
+ }
+
+ private void SvcCreateTransferMemory(AThreadState ThreadState)
+ {
+ long Position = (long)ThreadState.X1;
+ long Size = (long)ThreadState.X2;
+ int Perm = (int)ThreadState.X3;
+
+ AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position);
+
+ Memory.Manager.Reprotect(Position, Size, (AMemoryPerm)Perm);
+
+ HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Position, Size);
+
+ int Handle = Ns.Os.Handles.GenerateId(HndData);
+
+ ThreadState.X1 = (ulong)Handle;
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcResult.cs b/Ryujinx.Core/OsHle/Svc/SvcResult.cs
new file mode 100644
index 00000000..a5be9a94
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Svc/SvcResult.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Core.OsHle.Svc
+{
+ enum SvcResult
+ {
+ Success = 0,
+ ErrBadHandle = 0xe401,
+ ErrTimeout = 0xea01,
+ ErrBadInfo = 0xf001,
+ ErrBadIpcReq = 0xf601
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
new file mode 100644
index 00000000..7f593c8f
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
@@ -0,0 +1,227 @@
+using ChocolArm64.Memory;
+using ChocolArm64.State;
+using Ryujinx.Core.OsHle.Exceptions;
+using Ryujinx.Core.OsHle.Handles;
+using Ryujinx.Core.OsHle.Ipc;
+using System;
+using System.Threading;
+
+namespace Ryujinx.Core.OsHle.Svc
+{
+ partial class SvcHandler
+ {
+ private void SvcExitProcess(AThreadState ThreadState) => Ns.Os.ExitProcess(ThreadState.ProcessId);
+
+ private void SvcCloseHandle(AThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X0;
+
+ Ns.Os.CloseHandle(Handle);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcResetSignal(AThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X0;
+
+ //TODO: Implement events.
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcWaitSynchronization(AThreadState ThreadState)
+ {
+ long HandlesPtr = (long)ThreadState.X0;
+ int HandlesCount = (int)ThreadState.X2;
+ long Timeout = (long)ThreadState.X3;
+
+ //TODO: Implement events.
+
+ HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
+ Process.Scheduler.Suspend(CurrThread.ProcessorId);
+ Process.Scheduler.Resume(CurrThread);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcGetSystemTick(AThreadState ThreadState)
+ {
+ ThreadState.X0 = (ulong)ThreadState.CntpctEl0;
+ }
+
+ private void SvcConnectToNamedPort(AThreadState ThreadState)
+ {
+ long StackPtr = (long)ThreadState.X0;
+ long NamePtr = (long)ThreadState.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);
+
+ ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session);
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcSendSyncRequest(AThreadState ThreadState)
+ {
+ SendSyncRequest(ThreadState, false);
+ }
+
+ private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState)
+ {
+ SendSyncRequest(ThreadState, true);
+ }
+
+ private void SendSyncRequest(AThreadState ThreadState, bool UserBuffer)
+ {
+ long CmdPtr = ThreadState.Tpidr;
+ long Size = 0x100;
+ int Handle = 0;
+
+ if (UserBuffer)
+ {
+ CmdPtr = (long)ThreadState.X0;
+ Size = (long)ThreadState.X1;
+ Handle = (int)ThreadState.X2;
+ }
+ else
+ {
+ Handle = (int)ThreadState.X0;
+ }
+
+ HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
+ Process.Scheduler.Suspend(CurrThread.ProcessorId);
+
+ 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.IpcCall(Ns, Memory, Session, Cmd, CmdPtr, Handle);
+
+ byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+ else
+ {
+ ThreadState.X0 = (int)SvcResult.ErrBadIpcReq;
+ }
+
+ Thread.Yield();
+
+ Process.Scheduler.Resume(CurrThread);
+ }
+
+ private void SvcBreak(AThreadState ThreadState)
+ {
+ long Reason = (long)ThreadState.X0;
+ long Unknown = (long)ThreadState.X1;
+ long Info = (long)ThreadState.X2;
+
+ throw new GuestBrokeExecutionException();
+ }
+
+ private void SvcOutputDebugString(AThreadState ThreadState)
+ {
+ long Position = (long)ThreadState.X0;
+ long Size = (long)ThreadState.X1;
+
+ string Str = AMemoryHelper.ReadAsciiString(Memory, Position, (int)Size);
+
+ Logging.Info($"SvcOutputDebugString: {Str}");
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcGetInfo(AThreadState ThreadState)
+ {
+ long StackPtr = (long)ThreadState.X0;
+ int InfoType = (int)ThreadState.X1;
+ long Handle = (long)ThreadState.X2;
+ int InfoId = (int)ThreadState.X3;
+
+ //Fail for info not available on older Kernel versions.
+ if (InfoType == 18 ||
+ InfoType == 19)
+ {
+ ThreadState.X0 = (int)SvcResult.ErrBadInfo;
+
+ return;
+ }
+
+ switch (InfoType)
+ {
+ case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break;
+ case 3: ThreadState.X1 = GetMapRegionSize(); break;
+ case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break;
+ case 5: ThreadState.X1 = GetHeapRegionSize(); break;
+ case 6: ThreadState.X1 = GetTotalMem(); break;
+ case 7: ThreadState.X1 = GetUsedMem(); break;
+ case 11: ThreadState.X1 = GetRnd64(); break;
+ case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break;
+ case 13: ThreadState.X1 = GetAddrSpaceSize(); break;
+ case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break;
+ case 15: ThreadState.X1 = GetMapRegionSize(); break;
+
+ default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}");
+ }
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private ulong GetTotalMem()
+ {
+ return (ulong)Memory.Manager.GetTotalMemorySize();
+ }
+
+ private ulong GetUsedMem()
+ {
+ return (ulong)Memory.Manager.GetUsedMemorySize();
+ }
+
+ private ulong GetRnd64()
+ {
+ return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
+ }
+
+ private ulong GetAddrSpaceBaseAddr()
+ {
+ return 0x08000000;
+ }
+
+ private ulong GetAddrSpaceSize()
+ {
+ return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr();
+ }
+
+ private ulong GetMapRegionBaseAddr()
+ {
+ return 0x80000000;
+ }
+
+ private ulong GetMapRegionSize()
+ {
+ return 0x40000000;
+ }
+
+ private ulong GetHeapRegionBaseAddr()
+ {
+ return GetMapRegionBaseAddr() + GetMapRegionSize();
+ }
+
+ private ulong GetHeapRegionSize()
+ {
+ return 0x40000000;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs
new file mode 100644
index 00000000..a635edb1
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs
@@ -0,0 +1,85 @@
+using ChocolArm64.State;
+using Ryujinx.Core.OsHle.Handles;
+
+namespace Ryujinx.Core.OsHle.Svc
+{
+ partial class SvcHandler
+ {
+ private void SvcCreateThread(AThreadState ThreadState)
+ {
+ long EntryPoint = (long)ThreadState.X1;
+ long ArgsPtr = (long)ThreadState.X2;
+ long StackTop = (long)ThreadState.X3;
+ int Priority = (int)ThreadState.X4;
+ int ProcessorId = (int)ThreadState.X5;
+
+ if (Ns.Os.TryGetProcess(ThreadState.ProcessId, out Process Process))
+ {
+ if (ProcessorId == -2)
+ {
+ //TODO: Get this value from the NPDM file.
+ ProcessorId = 0;
+ }
+
+ int Handle = Process.MakeThread(
+ EntryPoint,
+ StackTop,
+ ArgsPtr,
+ Priority,
+ ProcessorId);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ ThreadState.X1 = (ulong)Handle;
+ }
+
+ //TODO: Error codes.
+ }
+
+ private void SvcStartThread(AThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X0;
+
+ HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+
+ if (Thread != null)
+ {
+ Process.Scheduler.StartThread(Thread);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ //TODO: Error codes.
+ }
+
+ private void SvcSleepThread(AThreadState ThreadState)
+ {
+ ulong NanoSecs = ThreadState.X0;
+
+ HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
+ if (NanoSecs == 0)
+ {
+ Process.Scheduler.Yield(CurrThread);
+ }
+ else
+ {
+ Process.Scheduler.WaitForSignal(CurrThread, (int)(NanoSecs / 1000000));
+ }
+ }
+
+ private void SvcGetThreadPriority(AThreadState ThreadState)
+ {
+ int Handle = (int)ThreadState.X1;
+
+ HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+
+ if (Thread != null)
+ {
+ ThreadState.X1 = (ulong)Thread.Priority;
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ //TODO: Error codes.
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
new file mode 100644
index 00000000..dec13f75
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
@@ -0,0 +1,78 @@
+using ChocolArm64.State;
+using Ryujinx.Core.OsHle.Handles;
+
+namespace Ryujinx.Core.OsHle.Svc
+{
+ partial class SvcHandler
+ {
+ private void SvcArbitrateLock(AThreadState ThreadState)
+ {
+ int OwnerThreadHandle = (int)ThreadState.X0;
+ long MutexAddress = (long)ThreadState.X1;
+ int RequestingThreadHandle = (int)ThreadState.X2;
+
+ HThread RequestingThread = Ns.Os.Handles.GetData<HThread>(RequestingThreadHandle);
+
+ Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
+
+ M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M);
+
+ M.WaitForLock(RequestingThread, RequestingThreadHandle);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcArbitrateUnlock(AThreadState ThreadState)
+ {
+ long MutexAddress = (long)ThreadState.X0;
+
+ if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M))
+ {
+ M.Unlock();
+ }
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState)
+ {
+ long MutexAddress = (long)ThreadState.X0;
+ long CondVarAddress = (long)ThreadState.X1;
+ int ThreadHandle = (int)ThreadState.X2;
+ long Timeout = (long)ThreadState.X3;
+
+ HThread Thread = Ns.Os.Handles.GetData<HThread>(ThreadHandle);
+
+ Mutex M = new Mutex(Process, MutexAddress, ThreadHandle);
+
+ M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M);
+
+ M.GiveUpLock(ThreadHandle);
+
+ CondVar Cv = new CondVar(Process, CondVarAddress, Timeout);
+
+ Cv = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Cv);
+
+ Cv.WaitForSignal(Thread);
+
+ M.WaitForLock(Thread, ThreadHandle);
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+
+ private void SvcSignalProcessWideKey(AThreadState ThreadState)
+ {
+ long CondVarAddress = (long)ThreadState.X0;
+ int Count = (int)ThreadState.X1;
+
+ HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+
+ if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv))
+ {
+ Cv.SetSignal(CurrThread, Count);
+ }
+
+ ThreadState.X0 = (int)SvcResult.Success;
+ }
+ }
+} \ No newline at end of file