This commit is contained in:
gdkchan 2018-02-04 20:08:20 -03:00
commit b7e1d9930d
230 changed files with 17548 additions and 0 deletions

View 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"));
}
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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.
}
}
}

View 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;
}
}
}