| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- using ChocolArm64.Memory;
- using ChocolArm64.State;
- using Ryujinx.Common.Logging;
- using Ryujinx.HLE.Exceptions;
- using Ryujinx.HLE.HOS.Ipc;
- using Ryujinx.HLE.HOS.Services;
- using System;
- using System.Threading;
- using static Ryujinx.HLE.HOS.ErrorCode;
- namespace Ryujinx.HLE.HOS.Kernel
- {
- partial class SvcHandler
- {
- private const int AllowedCpuIdBitmask = 0b1111;
- private const bool EnableProcessDebugging = false;
- private void SvcExitProcess(CpuThreadState ThreadState)
- {
- Device.System.ExitProcess(Process.ProcessId);
- }
- private void SignalEvent64(CpuThreadState ThreadState)
- {
- ThreadState.X0 = (ulong)SignalEvent((int)ThreadState.X0);
- }
- private KernelResult SignalEvent(int Handle)
- {
- KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
- KernelResult Result;
- if (WritableEvent != null)
- {
- WritableEvent.Signal();
- Result = KernelResult.Success;
- }
- else
- {
- Result = KernelResult.InvalidHandle;
- }
- if (Result != KernelResult.Success)
- {
- Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
- }
- return Result;
- }
- private void ClearEvent64(CpuThreadState ThreadState)
- {
- ThreadState.X0 = (ulong)ClearEvent((int)ThreadState.X0);
- }
- private KernelResult ClearEvent(int Handle)
- {
- KernelResult Result;
- KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
- if (WritableEvent == null)
- {
- KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
- Result = ReadableEvent?.Clear() ?? KernelResult.InvalidHandle;
- }
- else
- {
- Result = WritableEvent.Clear();
- }
- if (Result != KernelResult.Success)
- {
- Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
- }
- return Result;
- }
- private void SvcCloseHandle(CpuThreadState ThreadState)
- {
- int Handle = (int)ThreadState.X0;
- object Obj = Process.HandleTable.GetObject<object>(Handle);
- Process.HandleTable.CloseHandle(Handle);
- if (Obj == null)
- {
- Logger.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- return;
- }
- if (Obj is KSession Session)
- {
- Session.Dispose();
- }
- else if (Obj is KTransferMemory TransferMemory)
- {
- Process.MemoryManager.ResetTransferMemory(
- TransferMemory.Position,
- TransferMemory.Size);
- }
- ThreadState.X0 = 0;
- }
- private void ResetSignal64(CpuThreadState ThreadState)
- {
- ThreadState.X0 = (ulong)ResetSignal((int)ThreadState.X0);
- }
- private KernelResult ResetSignal(int Handle)
- {
- KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
- KernelResult Result;
- //TODO: KProcess support.
- if (ReadableEvent != null)
- {
- Result = ReadableEvent.ClearIfSignaled();
- }
- else
- {
- Result = KernelResult.InvalidHandle;
- }
- if (Result == KernelResult.InvalidState)
- {
- Logger.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
- }
- else if (Result != KernelResult.Success)
- {
- Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
- }
- return Result;
- }
- private void SvcGetSystemTick(CpuThreadState ThreadState)
- {
- ThreadState.X0 = ThreadState.CntpctEl0;
- }
- private void SvcConnectToNamedPort(CpuThreadState ThreadState)
- {
- long StackPtr = (long)ThreadState.X0;
- long NamePtr = (long)ThreadState.X1;
- string Name = MemoryHelper.ReadAsciiString(Memory, NamePtr, 8);
- //TODO: Validate that app has perms to access the service, and that the service
- //actually exists, return error codes otherwise.
- KSession Session = new KSession(ServiceFactory.MakeService(System, Name), Name);
- if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
- {
- throw new InvalidOperationException("Out of handles!");
- }
- ThreadState.X0 = 0;
- ThreadState.X1 = (uint)Handle;
- }
- private void SvcSendSyncRequest(CpuThreadState ThreadState)
- {
- SendSyncRequest(ThreadState, ThreadState.Tpidr, 0x100, (int)ThreadState.X0);
- }
- private void SvcSendSyncRequestWithUserBuffer(CpuThreadState ThreadState)
- {
- SendSyncRequest(
- ThreadState,
- (long)ThreadState.X0,
- (long)ThreadState.X1,
- (int)ThreadState.X2);
- }
- private void SendSyncRequest(CpuThreadState ThreadState, long MessagePtr, long Size, int Handle)
- {
- KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
- byte[] MessageData = Memory.ReadBytes(MessagePtr, Size);
- KSession Session = Process.HandleTable.GetObject<KSession>(Handle);
- if (Session != null)
- {
- //Process.Scheduler.Suspend(CurrThread);
- System.CriticalSectionLock.Lock();
- KThread CurrentThread = System.Scheduler.GetCurrentThread();
- CurrentThread.SignaledObj = null;
- CurrentThread.ObjSyncResult = 0;
- CurrentThread.Reschedule(ThreadSchedState.Paused);
- IpcMessage Message = new IpcMessage(MessageData, MessagePtr);
- ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
- CurrentThread,
- Session,
- Message,
- MessagePtr));
- System.CriticalSectionLock.Unlock();
- ThreadState.X0 = (ulong)CurrentThread.ObjSyncResult;
- }
- else
- {
- Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!");
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
- }
- }
- private void ProcessIpcRequest(object State)
- {
- HleIpcMessage IpcMessage = (HleIpcMessage)State;
- IpcMessage.Thread.ObjSyncResult = (int)IpcHandler.IpcCall(
- Device,
- Process,
- Memory,
- IpcMessage.Session,
- IpcMessage.Message,
- IpcMessage.MessagePtr);
- IpcMessage.Thread.Reschedule(ThreadSchedState.Running);
- }
- private void SvcBreak(CpuThreadState ThreadState)
- {
- long Reason = (long)ThreadState.X0;
- long Unknown = (long)ThreadState.X1;
- long Info = (long)ThreadState.X2;
- if ((Reason & (1 << 31)) == 0)
- {
- Process.PrintStackTrace(ThreadState);
- throw new GuestBrokeExecutionException();
- }
- else
- {
- Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered");
- Process.PrintStackTrace(ThreadState);
- }
- }
- private void SvcOutputDebugString(CpuThreadState ThreadState)
- {
- long Position = (long)ThreadState.X0;
- long Size = (long)ThreadState.X1;
- string Str = MemoryHelper.ReadAsciiString(Memory, Position, Size);
- Logger.PrintWarning(LogClass.KernelSvc, Str);
- ThreadState.X0 = 0;
- }
- private void SvcGetInfo(CpuThreadState 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 ||
- InfoType == 20 ||
- InfoType == 21 ||
- InfoType == 22)
- {
- ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
- return;
- }
- switch (InfoType)
- {
- case 0:
- ThreadState.X1 = AllowedCpuIdBitmask;
- break;
- case 2:
- ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionStart;
- break;
- case 3:
- ThreadState.X1 = (ulong)Process.MemoryManager.MapRegionEnd -
- (ulong)Process.MemoryManager.MapRegionStart;
- break;
- case 4:
- ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionStart;
- break;
- case 5:
- ThreadState.X1 = (ulong)Process.MemoryManager.HeapRegionEnd -
- (ulong)Process.MemoryManager.HeapRegionStart;
- break;
- case 6:
- ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalAvailableSize;
- break;
- case 7:
- ThreadState.X1 = (ulong)Process.Device.Memory.Allocator.TotalUsedSize;
- break;
- case 8:
- ThreadState.X1 = EnableProcessDebugging ? 1 : 0;
- break;
- case 11:
- ThreadState.X1 = (ulong)Rng.Next() + ((ulong)Rng.Next() << 32);
- break;
- case 12:
- ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceStart;
- break;
- case 13:
- ThreadState.X1 = (ulong)Process.MemoryManager.AddrSpaceEnd -
- (ulong)Process.MemoryManager.AddrSpaceStart;
- break;
- case 14:
- ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionStart;
- break;
- case 15:
- ThreadState.X1 = (ulong)Process.MemoryManager.NewMapRegionEnd -
- (ulong)Process.MemoryManager.NewMapRegionStart;
- break;
- case 16:
- ThreadState.X1 = (ulong)(Process.MetaData?.SystemResourceSize ?? 0);
- break;
- case 17:
- ThreadState.X1 = (ulong)Process.MemoryManager.PersonalMmHeapUsage;
- break;
- default:
- Process.PrintStackTrace(ThreadState);
- throw new NotImplementedException($"SvcGetInfo: {InfoType} 0x{Handle:x8} {InfoId}");
- }
- ThreadState.X0 = 0;
- }
- private void CreateEvent64(CpuThreadState State)
- {
- KernelResult Result = CreateEvent(out int WEventHandle, out int REventHandle);
- State.X0 = (ulong)Result;
- State.X1 = (ulong)WEventHandle;
- State.X2 = (ulong)REventHandle;
- }
- private KernelResult CreateEvent(out int WEventHandle, out int REventHandle)
- {
- KEvent Event = new KEvent(System);
- KernelResult Result = Process.HandleTable.GenerateHandle(Event.WritableEvent, out WEventHandle);
- if (Result == KernelResult.Success)
- {
- Result = Process.HandleTable.GenerateHandle(Event.ReadableEvent, out REventHandle);
- if (Result != KernelResult.Success)
- {
- Process.HandleTable.CloseHandle(WEventHandle);
- }
- }
- else
- {
- REventHandle = 0;
- }
- return Result;
- }
- }
- }
|