diff options
| author | emmauss <emmausssss@gmail.com> | 2018-02-20 22:09:23 +0200 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-02-20 17:09:23 -0300 |
| commit | 62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch) | |
| tree | 0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/OsHle/Svc | |
| parent | cb665bb715834526d73c9469d16114b287faaecd (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.cs | 80 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Svc/SvcMemory.cs | 121 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Svc/SvcResult.cs | 11 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Svc/SvcSystem.cs | 227 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Svc/SvcThread.cs | 85 | ||||
| -rw-r--r-- | Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs | 78 |
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 |
