/ src / Ryujinx.HLE / HOS / Kernel / SupervisorCall / Syscall.cs
Syscall.cs
   1  using Ryujinx.Common;
   2  using Ryujinx.Common.Logging;
   3  using Ryujinx.Cpu;
   4  using Ryujinx.HLE.Exceptions;
   5  using Ryujinx.HLE.HOS.Kernel.Common;
   6  using Ryujinx.HLE.HOS.Kernel.Ipc;
   7  using Ryujinx.HLE.HOS.Kernel.Memory;
   8  using Ryujinx.HLE.HOS.Kernel.Process;
   9  using Ryujinx.HLE.HOS.Kernel.Threading;
  10  using Ryujinx.Horizon.Common;
  11  using Ryujinx.Memory;
  12  using System;
  13  using System.Buffers;
  14  using System.Threading;
  15  
  16  namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
  17  {
  18      [SvcImpl]
  19      class Syscall : ISyscallApi
  20      {
  21          private readonly KernelContext _context;
  22  
  23          public Syscall(KernelContext context)
  24          {
  25              _context = context;
  26          }
  27  
  28          // Process
  29  
  30          [Svc(0x24)]
  31          public Result GetProcessId(out ulong pid, int handle)
  32          {
  33              KProcess currentProcess = KernelStatic.GetCurrentProcess();
  34  
  35              KProcess process = currentProcess.HandleTable.GetKProcess(handle);
  36  
  37              if (process == null)
  38              {
  39                  KThread thread = currentProcess.HandleTable.GetKThread(handle);
  40  
  41                  if (thread != null)
  42                  {
  43                      process = thread.Owner;
  44                  }
  45  
  46                  // TODO: KDebugEvent.
  47              }
  48  
  49              pid = process?.Pid ?? 0;
  50  
  51              return process != null
  52                  ? Result.Success
  53                  : KernelResult.InvalidHandle;
  54          }
  55  
  56          public Result CreateProcess(
  57              out int handle,
  58              ProcessCreationInfo info,
  59              ReadOnlySpan<uint> capabilities,
  60              IProcessContextFactory contextFactory,
  61              ThreadStart customThreadStart = null)
  62          {
  63              handle = 0;
  64  
  65              if ((info.Flags & ~ProcessCreationFlags.All) != 0)
  66              {
  67                  return KernelResult.InvalidEnumValue;
  68              }
  69  
  70              // TODO: Address space check.
  71  
  72              if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
  73              {
  74                  return KernelResult.InvalidEnumValue;
  75              }
  76  
  77              if ((info.CodeAddress & 0x1fffff) != 0)
  78              {
  79                  return KernelResult.InvalidAddress;
  80              }
  81  
  82              if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
  83              {
  84                  return KernelResult.InvalidSize;
  85              }
  86  
  87              if (info.Flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize))
  88              {
  89                  if ((info.Flags & ProcessCreationFlags.AddressSpaceMask) != ProcessCreationFlags.AddressSpace64Bit ||
  90                      info.SystemResourcePagesCount <= 0)
  91                  {
  92                      return KernelResult.InvalidState;
  93                  }
  94  
  95                  // TODO: Check that we are in debug mode.
  96              }
  97  
  98              if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
  99                  !info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
 100              {
 101                  return KernelResult.InvalidThread;
 102              }
 103  
 104              KHandleTable handleTable = KernelStatic.GetCurrentProcess().HandleTable;
 105  
 106              KProcess process = new(_context);
 107  
 108              using var _ = new OnScopeExit(process.DecrementReferenceCount);
 109  
 110              KResourceLimit resourceLimit;
 111  
 112              if (info.ResourceLimitHandle != 0)
 113              {
 114                  resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
 115  
 116                  if (resourceLimit == null)
 117                  {
 118                      return KernelResult.InvalidHandle;
 119                  }
 120              }
 121              else
 122              {
 123                  resourceLimit = _context.ResourceLimit;
 124              }
 125  
 126              MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch
 127              {
 128                  ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application,
 129                  ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet,
 130                  ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service,
 131                  ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices,
 132                  _ => MemoryRegion.NvServices,
 133              };
 134  
 135              Result result = process.Initialize(
 136                  info,
 137                  capabilities,
 138                  resourceLimit,
 139                  memRegion,
 140                  contextFactory,
 141                  customThreadStart);
 142  
 143              if (result != Result.Success)
 144              {
 145                  return result;
 146              }
 147  
 148              _context.Processes.TryAdd(process.Pid, process);
 149  
 150              return handleTable.GenerateHandle(process, out handle);
 151          }
 152  
 153          public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
 154          {
 155              KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
 156  
 157              if (process == null)
 158              {
 159                  return KernelResult.InvalidHandle;
 160              }
 161  
 162              if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
 163              {
 164                  return KernelResult.InvalidCpuCore;
 165              }
 166  
 167              if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority))
 168              {
 169                  return KernelResult.InvalidPriority;
 170              }
 171  
 172              process.DefaultCpuCore = cpuCore;
 173  
 174              Result result = process.Start(priority, mainThreadStackSize);
 175  
 176              if (result != Result.Success)
 177              {
 178                  return result;
 179              }
 180  
 181              process.IncrementReferenceCount();
 182  
 183              return Result.Success;
 184          }
 185  
 186          [Svc(0x5f)]
 187          public Result FlushProcessDataCache(int processHandle, ulong address, ulong size)
 188          {
 189              // FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
 190              // As we don't support (and don't actually need) to flush the cache, this is stubbed.
 191              return Result.Success;
 192          }
 193  
 194          // IPC
 195  
 196          [Svc(0x1f)]
 197          public Result ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr)
 198          {
 199              handle = 0;
 200  
 201              if (!KernelTransfer.UserToKernelString(out string name, namePtr, 12))
 202              {
 203                  return KernelResult.UserCopyFailed;
 204              }
 205  
 206              return ConnectToNamedPort(out handle, name);
 207          }
 208  
 209          public Result ConnectToNamedPort(out int handle, string name)
 210          {
 211              handle = 0;
 212  
 213              if (name.Length > 11)
 214              {
 215                  return KernelResult.MaximumExceeded;
 216              }
 217  
 218              KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
 219  
 220              if (autoObj is not KClientPort clientPort)
 221              {
 222                  return KernelResult.NotFound;
 223              }
 224  
 225              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 226  
 227              Result result = currentProcess.HandleTable.ReserveHandle(out handle);
 228  
 229              if (result != Result.Success)
 230              {
 231                  return result;
 232              }
 233  
 234              result = clientPort.Connect(out KClientSession clientSession);
 235  
 236              if (result != Result.Success)
 237              {
 238                  currentProcess.HandleTable.CancelHandleReservation(handle);
 239  
 240                  return result;
 241              }
 242  
 243              currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
 244  
 245              clientSession.DecrementReferenceCount();
 246  
 247              return result;
 248          }
 249  
 250          [Svc(0x21)]
 251          public Result SendSyncRequest(int handle)
 252          {
 253              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 254  
 255              KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle);
 256  
 257              if (session == null)
 258              {
 259                  return KernelResult.InvalidHandle;
 260              }
 261  
 262              return session.SendSyncRequest();
 263          }
 264  
 265          [Svc(0x22)]
 266          public Result SendSyncRequestWithUserBuffer(
 267              [PointerSized] ulong messagePtr,
 268              [PointerSized] ulong messageSize,
 269              int handle)
 270          {
 271              if (!PageAligned(messagePtr))
 272              {
 273                  return KernelResult.InvalidAddress;
 274              }
 275  
 276              if (!PageAligned(messageSize) || messageSize == 0)
 277              {
 278                  return KernelResult.InvalidSize;
 279              }
 280  
 281              if (messagePtr + messageSize <= messagePtr)
 282              {
 283                  return KernelResult.InvalidMemState;
 284              }
 285  
 286              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 287  
 288              Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
 289  
 290              if (result != Result.Success)
 291              {
 292                  return result;
 293              }
 294  
 295              KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle);
 296  
 297              if (session == null)
 298              {
 299                  result = KernelResult.InvalidHandle;
 300              }
 301              else
 302              {
 303                  result = session.SendSyncRequest(messagePtr, messageSize);
 304              }
 305  
 306              Result result2 = currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 307  
 308              if (result == Result.Success)
 309              {
 310                  result = result2;
 311              }
 312  
 313              return result;
 314          }
 315  
 316          [Svc(0x23)]
 317          public Result SendAsyncRequestWithUserBuffer(
 318              out int doneEventHandle,
 319              [PointerSized] ulong messagePtr,
 320              [PointerSized] ulong messageSize,
 321              int handle)
 322          {
 323              doneEventHandle = 0;
 324  
 325              if (!PageAligned(messagePtr))
 326              {
 327                  return KernelResult.InvalidAddress;
 328              }
 329  
 330              if (!PageAligned(messageSize) || messageSize == 0)
 331              {
 332                  return KernelResult.InvalidSize;
 333              }
 334  
 335              if (messagePtr + messageSize <= messagePtr)
 336              {
 337                  return KernelResult.InvalidMemState;
 338              }
 339  
 340              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 341  
 342              Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
 343  
 344              if (result != Result.Success)
 345              {
 346                  return result;
 347              }
 348  
 349              KResourceLimit resourceLimit = currentProcess.ResourceLimit;
 350  
 351              if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.Event, 1))
 352              {
 353                  currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 354  
 355                  return KernelResult.ResLimitExceeded;
 356              }
 357  
 358              KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle);
 359  
 360              if (session == null)
 361              {
 362                  result = KernelResult.InvalidHandle;
 363              }
 364              else
 365              {
 366                  KEvent doneEvent = new(_context);
 367  
 368                  result = currentProcess.HandleTable.GenerateHandle(doneEvent.ReadableEvent, out doneEventHandle);
 369  
 370                  if (result == Result.Success)
 371                  {
 372                      result = session.SendAsyncRequest(doneEvent.WritableEvent, messagePtr, messageSize);
 373  
 374                      if (result != Result.Success)
 375                      {
 376                          currentProcess.HandleTable.CloseHandle(doneEventHandle);
 377                      }
 378                  }
 379              }
 380  
 381              if (result != Result.Success)
 382              {
 383                  resourceLimit?.Release(LimitableResource.Event, 1);
 384  
 385                  currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 386              }
 387  
 388              return result;
 389          }
 390  
 391          [Svc(0x40)]
 392          public Result CreateSession(
 393              out int serverSessionHandle,
 394              out int clientSessionHandle,
 395              bool isLight,
 396              [PointerSized] ulong namePtr)
 397          {
 398              return CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, null);
 399          }
 400  
 401          public Result CreateSession(
 402              out int serverSessionHandle,
 403              out int clientSessionHandle,
 404              bool isLight,
 405              string name)
 406          {
 407              serverSessionHandle = 0;
 408              clientSessionHandle = 0;
 409  
 410              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 411  
 412              KResourceLimit resourceLimit = currentProcess.ResourceLimit;
 413  
 414              if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.Session, 1))
 415              {
 416                  return KernelResult.ResLimitExceeded;
 417              }
 418  
 419              Result result;
 420  
 421              if (isLight)
 422              {
 423                  KLightSession session = new(_context);
 424  
 425                  result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
 426  
 427                  if (result == Result.Success)
 428                  {
 429                      result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
 430  
 431                      if (result != Result.Success)
 432                      {
 433                          currentProcess.HandleTable.CloseHandle(serverSessionHandle);
 434  
 435                          serverSessionHandle = 0;
 436                      }
 437                  }
 438  
 439                  session.ServerSession.DecrementReferenceCount();
 440                  session.ClientSession.DecrementReferenceCount();
 441              }
 442              else
 443              {
 444                  KSession session = new(_context);
 445  
 446                  result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
 447  
 448                  if (result == Result.Success)
 449                  {
 450                      result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
 451  
 452                      if (result != Result.Success)
 453                      {
 454                          currentProcess.HandleTable.CloseHandle(serverSessionHandle);
 455  
 456                          serverSessionHandle = 0;
 457                      }
 458                  }
 459  
 460                  session.ServerSession.DecrementReferenceCount();
 461                  session.ClientSession.DecrementReferenceCount();
 462              }
 463  
 464              return result;
 465          }
 466  
 467          [Svc(0x41)]
 468          public Result AcceptSession(out int sessionHandle, int portHandle)
 469          {
 470              sessionHandle = 0;
 471  
 472              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 473  
 474              KServerPort serverPort = currentProcess.HandleTable.GetObject<KServerPort>(portHandle);
 475  
 476              if (serverPort == null)
 477              {
 478                  return KernelResult.InvalidHandle;
 479              }
 480  
 481              Result result = currentProcess.HandleTable.ReserveHandle(out int handle);
 482  
 483              if (result != Result.Success)
 484              {
 485                  return result;
 486              }
 487  
 488              KAutoObject session;
 489  
 490              if (serverPort.IsLight)
 491              {
 492                  session = serverPort.AcceptIncomingLightConnection();
 493              }
 494              else
 495              {
 496                  session = serverPort.AcceptIncomingConnection();
 497              }
 498  
 499              if (session != null)
 500              {
 501                  currentProcess.HandleTable.SetReservedHandleObj(handle, session);
 502  
 503                  session.DecrementReferenceCount();
 504  
 505                  sessionHandle = handle;
 506  
 507                  result = Result.Success;
 508              }
 509              else
 510              {
 511                  currentProcess.HandleTable.CancelHandleReservation(handle);
 512  
 513                  result = KernelResult.NotFound;
 514              }
 515  
 516              return result;
 517          }
 518  
 519          [Svc(0x43)]
 520          public Result ReplyAndReceive(
 521              out int handleIndex,
 522              [PointerSized] ulong handlesPtr,
 523              int handlesCount,
 524              int replyTargetHandle,
 525              long timeout)
 526          {
 527              handleIndex = 0;
 528  
 529              if ((uint)handlesCount > 0x40)
 530              {
 531                  return KernelResult.MaximumExceeded;
 532              }
 533  
 534              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 535  
 536              ulong copySize = (ulong)((long)handlesCount * 4);
 537  
 538              if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize))
 539              {
 540                  return KernelResult.UserCopyFailed;
 541              }
 542  
 543              if (handlesPtr + copySize < handlesPtr)
 544              {
 545                  return KernelResult.UserCopyFailed;
 546              }
 547  
 548              int[] handles = new int[handlesCount];
 549  
 550              if (!KernelTransfer.UserToKernelArray<int>(handlesPtr, handles))
 551              {
 552                  return KernelResult.UserCopyFailed;
 553              }
 554  
 555              if (timeout > 0)
 556              {
 557                  timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
 558              }
 559  
 560              return ReplyAndReceive(out handleIndex, handles, replyTargetHandle, timeout);
 561          }
 562  
 563          public Result ReplyAndReceive(out int handleIndex, ReadOnlySpan<int> handles, int replyTargetHandle, long timeout)
 564          {
 565              handleIndex = 0;
 566  
 567              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 568  
 569              KSynchronizationObject[] syncObjsArray = ArrayPool<KSynchronizationObject>.Shared.Rent(handles.Length);
 570  
 571              Span<KSynchronizationObject> syncObjs = syncObjsArray.AsSpan(0, handles.Length);
 572  
 573              for (int index = 0; index < handles.Length; index++)
 574              {
 575                  KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
 576  
 577                  if (obj == null)
 578                  {
 579                      return KernelResult.InvalidHandle;
 580                  }
 581  
 582                  syncObjs[index] = obj;
 583              }
 584  
 585              Result result = Result.Success;
 586  
 587              if (replyTargetHandle != 0)
 588              {
 589                  KServerSession replyTarget = currentProcess.HandleTable.GetObject<KServerSession>(replyTargetHandle);
 590  
 591                  if (replyTarget == null)
 592                  {
 593                      result = KernelResult.InvalidHandle;
 594                  }
 595                  else
 596                  {
 597                      result = replyTarget.Reply();
 598                  }
 599              }
 600  
 601              if (result == Result.Success)
 602              {
 603                  if (timeout > 0)
 604                  {
 605                      timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
 606                  }
 607  
 608                  while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == Result.Success)
 609                  {
 610                      KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
 611  
 612                      if (session == null)
 613                      {
 614                          break;
 615                      }
 616  
 617                      if ((result = session.Receive()) != KernelResult.NotFound)
 618                      {
 619                          break;
 620                      }
 621                  }
 622              }
 623  
 624              ArrayPool<KSynchronizationObject>.Shared.Return(syncObjsArray, true);
 625  
 626              return result;
 627          }
 628  
 629          [Svc(0x44)]
 630          public Result ReplyAndReceiveWithUserBuffer(
 631              out int handleIndex,
 632              [PointerSized] ulong messagePtr,
 633              [PointerSized] ulong messageSize,
 634              [PointerSized] ulong handlesPtr,
 635              int handlesCount,
 636              int replyTargetHandle,
 637              long timeout)
 638          {
 639              handleIndex = 0;
 640  
 641              if ((uint)handlesCount > 0x40)
 642              {
 643                  return KernelResult.MaximumExceeded;
 644              }
 645  
 646              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 647  
 648              ulong copySize = (ulong)((long)handlesCount * 4);
 649  
 650              if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize))
 651              {
 652                  return KernelResult.UserCopyFailed;
 653              }
 654  
 655              if (handlesPtr + copySize < handlesPtr)
 656              {
 657                  return KernelResult.UserCopyFailed;
 658              }
 659  
 660              Result result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize);
 661  
 662              if (result != Result.Success)
 663              {
 664                  return result;
 665              }
 666  
 667              int[] handles = new int[handlesCount];
 668  
 669              if (!KernelTransfer.UserToKernelArray<int>(handlesPtr, handles))
 670              {
 671                  currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 672  
 673                  return KernelResult.UserCopyFailed;
 674              }
 675  
 676              KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
 677  
 678              for (int index = 0; index < handlesCount; index++)
 679              {
 680                  KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
 681  
 682                  if (obj == null)
 683                  {
 684                      currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 685  
 686                      return KernelResult.InvalidHandle;
 687                  }
 688  
 689                  syncObjs[index] = obj;
 690              }
 691  
 692              if (replyTargetHandle != 0)
 693              {
 694                  KServerSession replyTarget = currentProcess.HandleTable.GetObject<KServerSession>(replyTargetHandle);
 695  
 696                  if (replyTarget == null)
 697                  {
 698                      result = KernelResult.InvalidHandle;
 699                  }
 700                  else
 701                  {
 702                      result = replyTarget.Reply(messagePtr, messageSize);
 703                  }
 704              }
 705  
 706              if (result == Result.Success)
 707              {
 708                  if (timeout > 0)
 709                  {
 710                      timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
 711                  }
 712  
 713                  while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == Result.Success)
 714                  {
 715                      KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
 716  
 717                      if (session == null)
 718                      {
 719                          break;
 720                      }
 721  
 722                      if ((result = session.Receive(messagePtr, messageSize)) != KernelResult.NotFound)
 723                      {
 724                          break;
 725                      }
 726                  }
 727              }
 728  
 729              currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize);
 730  
 731              return result;
 732          }
 733  
 734          [Svc(0x70)]
 735          public Result CreatePort(
 736              out int serverPortHandle,
 737              out int clientPortHandle,
 738              int maxSessions,
 739              bool isLight,
 740              [PointerSized] ulong namePtr)
 741          {
 742              // The kernel doesn't use the name pointer, so we can just pass null as the name.
 743              return CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, null);
 744          }
 745  
 746          public Result CreatePort(
 747              out int serverPortHandle,
 748              out int clientPortHandle,
 749              int maxSessions,
 750              bool isLight,
 751              string name)
 752          {
 753              serverPortHandle = clientPortHandle = 0;
 754  
 755              if (maxSessions < 1)
 756              {
 757                  return KernelResult.MaximumExceeded;
 758              }
 759  
 760              KPort port = new(_context, maxSessions, isLight, name);
 761  
 762              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 763  
 764              Result result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
 765  
 766              if (result != Result.Success)
 767              {
 768                  return result;
 769              }
 770  
 771              result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out serverPortHandle);
 772  
 773              if (result != Result.Success)
 774              {
 775                  currentProcess.HandleTable.CloseHandle(clientPortHandle);
 776              }
 777  
 778              return result;
 779          }
 780  
 781          [Svc(0x71)]
 782          public Result ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions)
 783          {
 784              handle = 0;
 785  
 786              if (!KernelTransfer.UserToKernelString(out string name, namePtr, 12))
 787              {
 788                  return KernelResult.UserCopyFailed;
 789              }
 790  
 791              if (name.Length > 11)
 792              {
 793                  return KernelResult.MaximumExceeded;
 794              }
 795  
 796              return ManageNamedPort(out handle, name, maxSessions);
 797          }
 798  
 799          public Result ManageNamedPort(out int handle, string name, int maxSessions)
 800          {
 801              handle = 0;
 802  
 803              if (maxSessions < 0)
 804              {
 805                  return KernelResult.MaximumExceeded;
 806              }
 807  
 808              if (maxSessions == 0)
 809              {
 810                  return KAutoObject.RemoveName(_context, name);
 811              }
 812  
 813              KPort port = new(_context, maxSessions, false, null);
 814  
 815              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 816  
 817              Result result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
 818  
 819              if (result != Result.Success)
 820              {
 821                  return result;
 822              }
 823  
 824              result = port.ClientPort.SetName(name);
 825  
 826              if (result != Result.Success)
 827              {
 828                  currentProcess.HandleTable.CloseHandle(handle);
 829              }
 830  
 831              return result;
 832          }
 833  
 834          [Svc(0x72)]
 835          public Result ConnectToPort(out int clientSessionHandle, int clientPortHandle)
 836          {
 837              clientSessionHandle = 0;
 838  
 839              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 840  
 841              KClientPort clientPort = currentProcess.HandleTable.GetObject<KClientPort>(clientPortHandle);
 842  
 843              if (clientPort == null)
 844              {
 845                  return KernelResult.InvalidHandle;
 846              }
 847  
 848              Result result = currentProcess.HandleTable.ReserveHandle(out int handle);
 849  
 850              if (result != Result.Success)
 851              {
 852                  return result;
 853              }
 854  
 855              KAutoObject session;
 856  
 857              if (clientPort.IsLight)
 858              {
 859                  result = clientPort.ConnectLight(out KLightClientSession clientSession);
 860  
 861                  session = clientSession;
 862              }
 863              else
 864              {
 865                  result = clientPort.Connect(out KClientSession clientSession);
 866  
 867                  session = clientSession;
 868              }
 869  
 870              if (result != Result.Success)
 871              {
 872                  currentProcess.HandleTable.CancelHandleReservation(handle);
 873  
 874                  return result;
 875              }
 876  
 877              currentProcess.HandleTable.SetReservedHandleObj(handle, session);
 878  
 879              session.DecrementReferenceCount();
 880  
 881              clientSessionHandle = handle;
 882  
 883              return result;
 884          }
 885  
 886          // Memory
 887  
 888          [Svc(1)]
 889          public Result SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size)
 890          {
 891              if ((size & 0xfffffffe001fffff) != 0)
 892              {
 893                  address = 0;
 894  
 895                  return KernelResult.InvalidSize;
 896              }
 897  
 898              KProcess process = KernelStatic.GetCurrentProcess();
 899  
 900              return process.MemoryManager.SetHeapSize(size, out address);
 901          }
 902  
 903          [Svc(2)]
 904          public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
 905          {
 906              if (!PageAligned(address))
 907              {
 908                  return KernelResult.InvalidAddress;
 909              }
 910  
 911              if (!PageAligned(size) || size == 0)
 912              {
 913                  return KernelResult.InvalidSize;
 914              }
 915  
 916              if (address + size <= address)
 917              {
 918                  return KernelResult.InvalidMemState;
 919              }
 920  
 921              if (permission != KMemoryPermission.None && (permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
 922              {
 923                  return KernelResult.InvalidPermission;
 924              }
 925  
 926              KProcess currentProcess = KernelStatic.GetCurrentProcess();
 927  
 928              if (!currentProcess.MemoryManager.InsideAddrSpace(address, size))
 929              {
 930                  return KernelResult.InvalidMemState;
 931              }
 932  
 933              return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission);
 934          }
 935  
 936          [Svc(3)]
 937          public Result SetMemoryAttribute(
 938              [PointerSized] ulong address,
 939              [PointerSized] ulong size,
 940              MemoryAttribute attributeMask,
 941              MemoryAttribute attributeValue)
 942          {
 943              if (!PageAligned(address))
 944              {
 945                  return KernelResult.InvalidAddress;
 946              }
 947  
 948              if (!PageAligned(size) || size == 0)
 949              {
 950                  return KernelResult.InvalidSize;
 951              }
 952  
 953              MemoryAttribute attributes = attributeMask | attributeValue;
 954  
 955              const MemoryAttribute SupportedAttributes = MemoryAttribute.Uncached | MemoryAttribute.PermissionLocked;
 956  
 957              if (attributes != attributeMask ||
 958                 (attributes | SupportedAttributes) != SupportedAttributes)
 959              {
 960                  return KernelResult.InvalidCombination;
 961              }
 962  
 963              // The permission locked attribute can't be unset.
 964              if ((attributeMask & MemoryAttribute.PermissionLocked) != (attributeValue & MemoryAttribute.PermissionLocked))
 965              {
 966                  return KernelResult.InvalidCombination;
 967              }
 968  
 969              KProcess process = KernelStatic.GetCurrentProcess();
 970  
 971              if (!process.MemoryManager.InsideAddrSpace(address, size))
 972              {
 973                  return KernelResult.InvalidMemState;
 974              }
 975  
 976              Result result = process.MemoryManager.SetMemoryAttribute(
 977                  address,
 978                  size,
 979                  attributeMask,
 980                  attributeValue);
 981  
 982              return result;
 983          }
 984  
 985          [Svc(4)]
 986          public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
 987          {
 988              if (!PageAligned(src | dst))
 989              {
 990                  return KernelResult.InvalidAddress;
 991              }
 992  
 993              if (!PageAligned(size) || size == 0)
 994              {
 995                  return KernelResult.InvalidSize;
 996              }
 997  
 998              if (src + size <= src || dst + size <= dst)
 999              {
1000                  return KernelResult.InvalidMemState;
1001              }
1002  
1003              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1004  
1005              if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
1006              {
1007                  return KernelResult.InvalidMemState;
1008              }
1009  
1010              if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
1011                  currentProcess.MemoryManager.InsideHeapRegion(dst, size) ||
1012                  currentProcess.MemoryManager.InsideAliasRegion(dst, size))
1013              {
1014                  return KernelResult.InvalidMemRange;
1015              }
1016  
1017              KProcess process = KernelStatic.GetCurrentProcess();
1018  
1019              return process.MemoryManager.Map(dst, src, size);
1020          }
1021  
1022          [Svc(5)]
1023          public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
1024          {
1025              if (!PageAligned(src | dst))
1026              {
1027                  return KernelResult.InvalidAddress;
1028              }
1029  
1030              if (!PageAligned(size) || size == 0)
1031              {
1032                  return KernelResult.InvalidSize;
1033              }
1034  
1035              if (src + size <= src || dst + size <= dst)
1036              {
1037                  return KernelResult.InvalidMemState;
1038              }
1039  
1040              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1041  
1042              if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
1043              {
1044                  return KernelResult.InvalidMemState;
1045              }
1046  
1047              if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
1048                  currentProcess.MemoryManager.InsideHeapRegion(dst, size) ||
1049                  currentProcess.MemoryManager.InsideAliasRegion(dst, size))
1050              {
1051                  return KernelResult.InvalidMemRange;
1052              }
1053  
1054              KProcess process = KernelStatic.GetCurrentProcess();
1055  
1056              return process.MemoryManager.Unmap(dst, src, size);
1057          }
1058  
1059          [Svc(6)]
1060          public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
1061          {
1062              Result result = QueryMemory(out MemoryInfo info, out pageInfo, address);
1063  
1064              if (result == Result.Success)
1065              {
1066                  return KernelTransfer.KernelToUser(infoPtr, info)
1067                      ? Result.Success
1068                      : KernelResult.InvalidMemState;
1069              }
1070  
1071              return result;
1072          }
1073  
1074          public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
1075          {
1076              KProcess process = KernelStatic.GetCurrentProcess();
1077  
1078              KMemoryInfo blockInfo = process.MemoryManager.QueryMemory(address);
1079  
1080              info = new MemoryInfo(
1081                  blockInfo.Address,
1082                  blockInfo.Size,
1083                  blockInfo.State & MemoryState.UserMask,
1084                  blockInfo.Attribute,
1085                  blockInfo.Permission & KMemoryPermission.UserMask,
1086                  blockInfo.IpcRefCount,
1087                  blockInfo.DeviceRefCount);
1088  
1089              pageInfo = 0;
1090  
1091              return Result.Success;
1092          }
1093  
1094          [Svc(0x13)]
1095          public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
1096          {
1097              if (!PageAligned(address))
1098              {
1099                  return KernelResult.InvalidAddress;
1100              }
1101  
1102              if (!PageAligned(size) || size == 0)
1103              {
1104                  return KernelResult.InvalidSize;
1105              }
1106  
1107              if (address + size <= address)
1108              {
1109                  return KernelResult.InvalidMemState;
1110              }
1111  
1112              if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
1113              {
1114                  return KernelResult.InvalidPermission;
1115              }
1116  
1117              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1118  
1119              KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
1120  
1121              if (sharedMemory == null)
1122              {
1123                  return KernelResult.InvalidHandle;
1124              }
1125  
1126              if (currentProcess.MemoryManager.IsInvalidRegion(address, size) ||
1127                  currentProcess.MemoryManager.InsideHeapRegion(address, size) ||
1128                  currentProcess.MemoryManager.InsideAliasRegion(address, size))
1129              {
1130                  return KernelResult.InvalidMemRange;
1131              }
1132  
1133              return sharedMemory.MapIntoProcess(
1134                  currentProcess.MemoryManager,
1135                  address,
1136                  size,
1137                  currentProcess,
1138                  permission);
1139          }
1140  
1141          [Svc(0x14)]
1142          public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
1143          {
1144              if (!PageAligned(address))
1145              {
1146                  return KernelResult.InvalidAddress;
1147              }
1148  
1149              if (!PageAligned(size) || size == 0)
1150              {
1151                  return KernelResult.InvalidSize;
1152              }
1153  
1154              if (address + size <= address)
1155              {
1156                  return KernelResult.InvalidMemState;
1157              }
1158  
1159              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1160  
1161              KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
1162  
1163              if (sharedMemory == null)
1164              {
1165                  return KernelResult.InvalidHandle;
1166              }
1167  
1168              if (currentProcess.MemoryManager.IsInvalidRegion(address, size) ||
1169                  currentProcess.MemoryManager.InsideHeapRegion(address, size) ||
1170                  currentProcess.MemoryManager.InsideAliasRegion(address, size))
1171              {
1172                  return KernelResult.InvalidMemRange;
1173              }
1174  
1175              return sharedMemory.UnmapFromProcess(
1176                  currentProcess.MemoryManager,
1177                  address,
1178                  size,
1179                  currentProcess);
1180          }
1181  
1182          [Svc(0x15)]
1183          public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
1184          {
1185              handle = 0;
1186  
1187              if (!PageAligned(address))
1188              {
1189                  return KernelResult.InvalidAddress;
1190              }
1191  
1192              if (!PageAligned(size) || size == 0)
1193              {
1194                  return KernelResult.InvalidSize;
1195              }
1196  
1197              if (address + size <= address)
1198              {
1199                  return KernelResult.InvalidMemState;
1200              }
1201  
1202              if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
1203              {
1204                  return KernelResult.InvalidPermission;
1205              }
1206  
1207              KProcess process = KernelStatic.GetCurrentProcess();
1208  
1209              KResourceLimit resourceLimit = process.ResourceLimit;
1210  
1211              if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.TransferMemory, 1))
1212              {
1213                  return KernelResult.ResLimitExceeded;
1214              }
1215  
1216              void CleanUpForError()
1217              {
1218                  resourceLimit?.Release(LimitableResource.TransferMemory, 1);
1219              }
1220  
1221              if (!process.MemoryManager.InsideAddrSpace(address, size))
1222              {
1223                  CleanUpForError();
1224  
1225                  return KernelResult.InvalidMemState;
1226              }
1227  
1228              KTransferMemory transferMemory = new(_context);
1229  
1230              Result result = transferMemory.Initialize(address, size, permission);
1231  
1232              if (result != Result.Success)
1233              {
1234                  CleanUpForError();
1235  
1236                  return result;
1237              }
1238  
1239              result = process.HandleTable.GenerateHandle(transferMemory, out handle);
1240  
1241              transferMemory.DecrementReferenceCount();
1242  
1243              return result;
1244          }
1245  
1246          [Svc(0x51)]
1247          public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
1248          {
1249              if (!PageAligned(address))
1250              {
1251                  return KernelResult.InvalidAddress;
1252              }
1253  
1254              if (!PageAligned(size) || size == 0)
1255              {
1256                  return KernelResult.InvalidSize;
1257              }
1258  
1259              if (address + size <= address)
1260              {
1261                  return KernelResult.InvalidMemState;
1262              }
1263  
1264              if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
1265              {
1266                  return KernelResult.InvalidPermission;
1267              }
1268  
1269              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1270  
1271              KTransferMemory transferMemory = currentProcess.HandleTable.GetObject<KTransferMemory>(handle);
1272  
1273              if (transferMemory == null)
1274              {
1275                  return KernelResult.InvalidHandle;
1276              }
1277  
1278              if (currentProcess.MemoryManager.IsInvalidRegion(address, size) ||
1279                  currentProcess.MemoryManager.InsideHeapRegion(address, size) ||
1280                  currentProcess.MemoryManager.InsideAliasRegion(address, size))
1281              {
1282                  return KernelResult.InvalidMemRange;
1283              }
1284  
1285              return transferMemory.MapIntoProcess(
1286                  currentProcess.MemoryManager,
1287                  address,
1288                  size,
1289                  currentProcess,
1290                  permission);
1291          }
1292  
1293          [Svc(0x52)]
1294          public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
1295          {
1296              if (!PageAligned(address))
1297              {
1298                  return KernelResult.InvalidAddress;
1299              }
1300  
1301              if (!PageAligned(size) || size == 0)
1302              {
1303                  return KernelResult.InvalidSize;
1304              }
1305  
1306              if (address + size <= address)
1307              {
1308                  return KernelResult.InvalidMemState;
1309              }
1310  
1311              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1312  
1313              KTransferMemory transferMemory = currentProcess.HandleTable.GetObject<KTransferMemory>(handle);
1314  
1315              if (transferMemory == null)
1316              {
1317                  return KernelResult.InvalidHandle;
1318              }
1319  
1320              if (currentProcess.MemoryManager.IsInvalidRegion(address, size) ||
1321                  currentProcess.MemoryManager.InsideHeapRegion(address, size) ||
1322                  currentProcess.MemoryManager.InsideAliasRegion(address, size))
1323              {
1324                  return KernelResult.InvalidMemRange;
1325              }
1326  
1327              return transferMemory.UnmapFromProcess(
1328                  currentProcess.MemoryManager,
1329                  address,
1330                  size,
1331                  currentProcess);
1332          }
1333  
1334          [Svc(0x2c)]
1335          public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
1336          {
1337              if (!PageAligned(address))
1338              {
1339                  return KernelResult.InvalidAddress;
1340              }
1341  
1342              if (!PageAligned(size) || size == 0)
1343              {
1344                  return KernelResult.InvalidSize;
1345              }
1346  
1347              if (address + size <= address)
1348              {
1349                  return KernelResult.InvalidMemRange;
1350              }
1351  
1352              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1353  
1354              if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
1355              {
1356                  return KernelResult.InvalidState;
1357              }
1358  
1359              if (!currentProcess.MemoryManager.InsideAddrSpace(address, size) ||
1360                   currentProcess.MemoryManager.OutsideAliasRegion(address, size))
1361              {
1362                  return KernelResult.InvalidMemRange;
1363              }
1364  
1365              KProcess process = KernelStatic.GetCurrentProcess();
1366  
1367              return process.MemoryManager.MapPhysicalMemory(address, size);
1368          }
1369  
1370          [Svc(0x2d)]
1371          public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
1372          {
1373              if (!PageAligned(address))
1374              {
1375                  return KernelResult.InvalidAddress;
1376              }
1377  
1378              if (!PageAligned(size) || size == 0)
1379              {
1380                  return KernelResult.InvalidSize;
1381              }
1382  
1383              if (address + size <= address)
1384              {
1385                  return KernelResult.InvalidMemRange;
1386              }
1387  
1388              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1389  
1390              if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
1391              {
1392                  return KernelResult.InvalidState;
1393              }
1394  
1395              if (!currentProcess.MemoryManager.InsideAddrSpace(address, size) ||
1396                   currentProcess.MemoryManager.OutsideAliasRegion(address, size))
1397              {
1398                  return KernelResult.InvalidMemRange;
1399              }
1400  
1401              KProcess process = KernelStatic.GetCurrentProcess();
1402  
1403              return process.MemoryManager.UnmapPhysicalMemory(address, size);
1404          }
1405  
1406          [Svc(0x4b)]
1407          public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
1408          {
1409              handle = 0;
1410  
1411              if (!PageAligned(address))
1412              {
1413                  return KernelResult.InvalidAddress;
1414              }
1415  
1416              if (!PageAligned(size) || size == 0)
1417              {
1418                  return KernelResult.InvalidSize;
1419              }
1420  
1421              if (size + address <= address)
1422              {
1423                  return KernelResult.InvalidMemState;
1424              }
1425  
1426              KCodeMemory codeMemory = new(_context);
1427  
1428              using var _ = new OnScopeExit(codeMemory.DecrementReferenceCount);
1429  
1430              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1431  
1432              if (!currentProcess.MemoryManager.InsideAddrSpace(address, size))
1433              {
1434                  return KernelResult.InvalidMemState;
1435              }
1436  
1437              Result result = codeMemory.Initialize(address, size);
1438  
1439              if (result != Result.Success)
1440              {
1441                  return result;
1442              }
1443  
1444              return currentProcess.HandleTable.GenerateHandle(codeMemory, out handle);
1445          }
1446  
1447          [Svc(0x4c)]
1448          public Result ControlCodeMemory(
1449              int handle,
1450              CodeMemoryOperation op,
1451              ulong address,
1452              ulong size,
1453              KMemoryPermission permission)
1454          {
1455              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1456  
1457              KCodeMemory codeMemory = currentProcess.HandleTable.GetObject<KCodeMemory>(handle);
1458  
1459              // Newer versions of the kernel also returns an error here if the owner and process
1460              // where the operation will happen are the same. We do not return an error here
1461              // for homebrew because some of them requires this to be patched out to work (for JIT).
1462              if (codeMemory == null || (!currentProcess.AllowCodeMemoryForJit && codeMemory.Owner == currentProcess))
1463              {
1464                  return KernelResult.InvalidHandle;
1465              }
1466  
1467              switch (op)
1468              {
1469                  case CodeMemoryOperation.Map:
1470                      if (!currentProcess.MemoryManager.CanContain(address, size, MemoryState.CodeWritable))
1471                      {
1472                          return KernelResult.InvalidMemRange;
1473                      }
1474  
1475                      if (permission != KMemoryPermission.ReadAndWrite)
1476                      {
1477                          return KernelResult.InvalidPermission;
1478                      }
1479  
1480                      return codeMemory.Map(address, size, permission);
1481  
1482                  case CodeMemoryOperation.MapToOwner:
1483                      if (!currentProcess.MemoryManager.CanContain(address, size, MemoryState.CodeReadOnly))
1484                      {
1485                          return KernelResult.InvalidMemRange;
1486                      }
1487  
1488                      if (permission != KMemoryPermission.Read && permission != KMemoryPermission.ReadAndExecute)
1489                      {
1490                          return KernelResult.InvalidPermission;
1491                      }
1492  
1493                      return codeMemory.MapToOwner(address, size, permission);
1494  
1495                  case CodeMemoryOperation.Unmap:
1496                      if (!currentProcess.MemoryManager.CanContain(address, size, MemoryState.CodeWritable))
1497                      {
1498                          return KernelResult.InvalidMemRange;
1499                      }
1500  
1501                      if (permission != KMemoryPermission.None)
1502                      {
1503                          return KernelResult.InvalidPermission;
1504                      }
1505  
1506                      return codeMemory.Unmap(address, size);
1507  
1508                  case CodeMemoryOperation.UnmapFromOwner:
1509                      if (!currentProcess.MemoryManager.CanContain(address, size, MemoryState.CodeReadOnly))
1510                      {
1511                          return KernelResult.InvalidMemRange;
1512                      }
1513  
1514                      if (permission != KMemoryPermission.None)
1515                      {
1516                          return KernelResult.InvalidPermission;
1517                      }
1518  
1519                      return codeMemory.UnmapFromOwner(address, size);
1520  
1521                  default:
1522                      return KernelResult.InvalidEnumValue;
1523              }
1524          }
1525  
1526          [Svc(0x73)]
1527          public Result SetProcessMemoryPermission(
1528              int handle,
1529              ulong src,
1530              ulong size,
1531              KMemoryPermission permission)
1532          {
1533              if (!PageAligned(src))
1534              {
1535                  return KernelResult.InvalidAddress;
1536              }
1537  
1538              if (!PageAligned(size) || size == 0)
1539              {
1540                  return KernelResult.InvalidSize;
1541              }
1542  
1543              if (permission != KMemoryPermission.None &&
1544                  permission != KMemoryPermission.Read &&
1545                  permission != KMemoryPermission.ReadAndWrite &&
1546                  permission != KMemoryPermission.ReadAndExecute)
1547              {
1548                  return KernelResult.InvalidPermission;
1549              }
1550  
1551              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1552  
1553              KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
1554  
1555              if (targetProcess == null)
1556              {
1557                  return KernelResult.InvalidHandle;
1558              }
1559  
1560              if (targetProcess.MemoryManager.OutsideAddrSpace(src, size))
1561              {
1562                  return KernelResult.InvalidMemState;
1563              }
1564  
1565              return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
1566          }
1567  
1568          [Svc(0x74)]
1569          public Result MapProcessMemory(
1570              [PointerSized] ulong dst,
1571              int handle,
1572              ulong src,
1573              [PointerSized] ulong size)
1574          {
1575              if (!PageAligned(src) || !PageAligned(dst))
1576              {
1577                  return KernelResult.InvalidAddress;
1578              }
1579  
1580              if (!PageAligned(size) || size == 0)
1581              {
1582                  return KernelResult.InvalidSize;
1583              }
1584  
1585              if (dst + size <= dst || src + size <= src)
1586              {
1587                  return KernelResult.InvalidMemRange;
1588              }
1589  
1590              KProcess dstProcess = KernelStatic.GetCurrentProcess();
1591              KProcess srcProcess = dstProcess.HandleTable.GetObject<KProcess>(handle);
1592  
1593              if (srcProcess == null)
1594              {
1595                  return KernelResult.InvalidHandle;
1596              }
1597  
1598              if (!srcProcess.MemoryManager.InsideAddrSpace(src, size) ||
1599                  !dstProcess.MemoryManager.CanContain(dst, size, MemoryState.ProcessMemory))
1600              {
1601                  return KernelResult.InvalidMemRange;
1602              }
1603  
1604              KPageList pageList = new();
1605  
1606              Result result = srcProcess.MemoryManager.GetPagesIfStateEquals(
1607                  src,
1608                  size,
1609                  MemoryState.MapProcessAllowed,
1610                  MemoryState.MapProcessAllowed,
1611                  KMemoryPermission.None,
1612                  KMemoryPermission.None,
1613                  MemoryAttribute.Mask,
1614                  MemoryAttribute.None,
1615                  pageList);
1616  
1617              if (result != Result.Success)
1618              {
1619                  return result;
1620              }
1621  
1622              return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite);
1623          }
1624  
1625          [Svc(0x75)]
1626          public Result UnmapProcessMemory(
1627              [PointerSized] ulong dst,
1628              int handle,
1629              ulong src,
1630              [PointerSized] ulong size)
1631          {
1632              if (!PageAligned(src) || !PageAligned(dst))
1633              {
1634                  return KernelResult.InvalidAddress;
1635              }
1636  
1637              if (!PageAligned(size) || size == 0)
1638              {
1639                  return KernelResult.InvalidSize;
1640              }
1641  
1642              if (dst + size <= dst || src + size <= src)
1643              {
1644                  return KernelResult.InvalidMemRange;
1645              }
1646  
1647              KProcess dstProcess = KernelStatic.GetCurrentProcess();
1648              KProcess srcProcess = dstProcess.HandleTable.GetObject<KProcess>(handle);
1649  
1650              if (srcProcess == null)
1651              {
1652                  return KernelResult.InvalidHandle;
1653              }
1654  
1655              if (!srcProcess.MemoryManager.InsideAddrSpace(src, size) ||
1656                  !dstProcess.MemoryManager.CanContain(dst, size, MemoryState.ProcessMemory))
1657              {
1658                  return KernelResult.InvalidMemRange;
1659              }
1660  
1661              Result result = dstProcess.MemoryManager.UnmapProcessMemory(dst, size, srcProcess.MemoryManager, src);
1662  
1663              if (result != Result.Success)
1664              {
1665                  return result;
1666              }
1667  
1668              return Result.Success;
1669          }
1670  
1671          [Svc(0x77)]
1672          public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
1673          {
1674              if (!PageAligned(dst) || !PageAligned(src))
1675              {
1676                  return KernelResult.InvalidAddress;
1677              }
1678  
1679              if (!PageAligned(size) || size == 0)
1680              {
1681                  return KernelResult.InvalidSize;
1682              }
1683  
1684              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1685  
1686              KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
1687  
1688              if (targetProcess == null)
1689              {
1690                  return KernelResult.InvalidHandle;
1691              }
1692  
1693              if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
1694                  targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
1695                  targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
1696                  targetProcess.MemoryManager.InsideHeapRegion(dst, size))
1697              {
1698                  return KernelResult.InvalidMemRange;
1699              }
1700  
1701              if (size + dst <= dst || size + src <= src)
1702              {
1703                  return KernelResult.InvalidMemState;
1704              }
1705  
1706              return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
1707          }
1708  
1709          [Svc(0x78)]
1710          public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
1711          {
1712              if (!PageAligned(dst) || !PageAligned(src))
1713              {
1714                  return KernelResult.InvalidAddress;
1715              }
1716  
1717              if (!PageAligned(size) || size == 0)
1718              {
1719                  return KernelResult.InvalidSize;
1720              }
1721  
1722              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1723  
1724              KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
1725  
1726              if (targetProcess == null)
1727              {
1728                  return KernelResult.InvalidHandle;
1729              }
1730  
1731              if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
1732                  targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
1733                  targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
1734                  targetProcess.MemoryManager.InsideHeapRegion(dst, size))
1735              {
1736                  return KernelResult.InvalidMemRange;
1737              }
1738  
1739              if (size + dst <= dst || size + src <= src)
1740              {
1741                  return KernelResult.InvalidMemState;
1742              }
1743  
1744              return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
1745          }
1746  
1747          private static bool PageAligned(ulong address)
1748          {
1749              return (address & (KPageTableBase.PageSize - 1)) == 0;
1750          }
1751  
1752          // System
1753  
1754          [Svc(0x7b)]
1755          public Result TerminateProcess(int handle)
1756          {
1757              KProcess process = KernelStatic.GetCurrentProcess();
1758  
1759              process = process.HandleTable.GetObject<KProcess>(handle);
1760  
1761              Result result;
1762  
1763              if (process != null)
1764              {
1765                  if (process == KernelStatic.GetCurrentProcess())
1766                  {
1767                      result = Result.Success;
1768                      process.DecrementToZeroWhileTerminatingCurrent();
1769                  }
1770                  else
1771                  {
1772                      result = process.Terminate();
1773                      process.DecrementReferenceCount();
1774                  }
1775              }
1776              else
1777              {
1778                  result = KernelResult.InvalidHandle;
1779              }
1780  
1781              return result;
1782          }
1783  
1784          [Svc(7)]
1785          public void ExitProcess()
1786          {
1787              KernelStatic.GetCurrentProcess().TerminateCurrentProcess();
1788          }
1789  
1790          [Svc(0x11)]
1791          public Result SignalEvent(int handle)
1792          {
1793              KProcess process = KernelStatic.GetCurrentProcess();
1794  
1795              KWritableEvent writableEvent = process.HandleTable.GetObject<KWritableEvent>(handle);
1796  
1797              Result result;
1798  
1799              if (writableEvent != null)
1800              {
1801                  writableEvent.Signal();
1802  
1803                  result = Result.Success;
1804              }
1805              else
1806              {
1807                  result = KernelResult.InvalidHandle;
1808              }
1809  
1810              return result;
1811          }
1812  
1813          [Svc(0x12)]
1814          public Result ClearEvent(int handle)
1815          {
1816              Result result;
1817  
1818              KProcess process = KernelStatic.GetCurrentProcess();
1819  
1820              KWritableEvent writableEvent = process.HandleTable.GetObject<KWritableEvent>(handle);
1821  
1822              if (writableEvent == null)
1823              {
1824                  KReadableEvent readableEvent = process.HandleTable.GetObject<KReadableEvent>(handle);
1825  
1826                  result = readableEvent?.Clear() ?? KernelResult.InvalidHandle;
1827              }
1828              else
1829              {
1830                  result = writableEvent.Clear();
1831              }
1832  
1833              return result;
1834          }
1835  
1836          [Svc(0x16)]
1837          public Result CloseHandle(int handle)
1838          {
1839              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1840  
1841              return currentProcess.HandleTable.CloseHandle(handle) ? Result.Success : KernelResult.InvalidHandle;
1842          }
1843  
1844          [Svc(0x17)]
1845          public Result ResetSignal(int handle)
1846          {
1847              KProcess currentProcess = KernelStatic.GetCurrentProcess();
1848  
1849              KReadableEvent readableEvent = currentProcess.HandleTable.GetObject<KReadableEvent>(handle);
1850  
1851              Result result;
1852  
1853              if (readableEvent != null)
1854              {
1855                  result = readableEvent.ClearIfSignaled();
1856              }
1857              else
1858              {
1859                  KProcess process = currentProcess.HandleTable.GetKProcess(handle);
1860  
1861                  if (process != null)
1862                  {
1863                      result = process.ClearIfNotExited();
1864                  }
1865                  else
1866                  {
1867                      result = KernelResult.InvalidHandle;
1868                  }
1869              }
1870  
1871              return result;
1872          }
1873  
1874          [Svc(0x1e)]
1875          public ulong GetSystemTick()
1876          {
1877              return _context.TickSource.Counter;
1878          }
1879  
1880          [Svc(0x26)]
1881          public void Break(ulong reason)
1882          {
1883              KThread currentThread = KernelStatic.GetCurrentThread();
1884  
1885              if ((reason & (1UL << 31)) == 0)
1886              {
1887                  currentThread.PrintGuestStackTrace();
1888                  currentThread.PrintGuestRegisterPrintout();
1889  
1890                  // As the process is exiting, this is probably caused by emulation termination.
1891                  if (currentThread.Owner.State == ProcessState.Exiting)
1892                  {
1893                      return;
1894                  }
1895  
1896                  // TODO: Debug events.
1897                  currentThread.Owner.TerminateCurrentProcess();
1898  
1899                  throw new GuestBrokeExecutionException();
1900              }
1901              else
1902              {
1903                  Logger.Debug?.Print(LogClass.KernelSvc, "Debugger triggered.");
1904              }
1905          }
1906  
1907          [Svc(0x27)]
1908          public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size)
1909          {
1910              KProcess process = KernelStatic.GetCurrentProcess();
1911  
1912              string str = MemoryHelper.ReadAsciiString(process.CpuMemory, strPtr, (long)size);
1913  
1914              Logger.Warning?.Print(LogClass.KernelSvc, str);
1915          }
1916  
1917          [Svc(0x29)]
1918          public Result GetInfo(out ulong value, InfoType id, int handle, long subId)
1919          {
1920              value = 0;
1921  
1922              switch (id)
1923              {
1924                  case InfoType.CoreMask:
1925                  case InfoType.PriorityMask:
1926                  case InfoType.AliasRegionAddress:
1927                  case InfoType.AliasRegionSize:
1928                  case InfoType.HeapRegionAddress:
1929                  case InfoType.HeapRegionSize:
1930                  case InfoType.TotalMemorySize:
1931                  case InfoType.UsedMemorySize:
1932                  case InfoType.AslrRegionAddress:
1933                  case InfoType.AslrRegionSize:
1934                  case InfoType.StackRegionAddress:
1935                  case InfoType.StackRegionSize:
1936                  case InfoType.SystemResourceSizeTotal:
1937                  case InfoType.SystemResourceSizeUsed:
1938                  case InfoType.ProgramId:
1939                  case InfoType.UserExceptionContextAddress:
1940                  case InfoType.TotalNonSystemMemorySize:
1941                  case InfoType.UsedNonSystemMemorySize:
1942                  case InfoType.IsApplication:
1943                  case InfoType.FreeThreadCount:
1944                  case InfoType.AliasRegionExtraSize:
1945                      {
1946                          if (subId != 0)
1947                          {
1948                              return KernelResult.InvalidCombination;
1949                          }
1950  
1951                          KProcess currentProcess = KernelStatic.GetCurrentProcess();
1952  
1953                          KProcess process = currentProcess.HandleTable.GetKProcess(handle);
1954  
1955                          if (process == null)
1956                          {
1957                              return KernelResult.InvalidHandle;
1958                          }
1959  
1960                          switch (id)
1961                          {
1962                              case InfoType.CoreMask:
1963                                  value = process.Capabilities.AllowedCpuCoresMask;
1964                                  break;
1965                              case InfoType.PriorityMask:
1966                                  value = process.Capabilities.AllowedThreadPriosMask;
1967                                  break;
1968  
1969                              case InfoType.AliasRegionAddress:
1970                                  value = process.MemoryManager.AliasRegionStart;
1971                                  break;
1972                              case InfoType.AliasRegionSize:
1973                                  value = process.MemoryManager.AliasRegionEnd - process.MemoryManager.AliasRegionStart;
1974                                  break;
1975  
1976                              case InfoType.HeapRegionAddress:
1977                                  value = process.MemoryManager.HeapRegionStart;
1978                                  break;
1979                              case InfoType.HeapRegionSize:
1980                                  value = process.MemoryManager.HeapRegionEnd - process.MemoryManager.HeapRegionStart;
1981                                  break;
1982  
1983                              case InfoType.TotalMemorySize:
1984                                  value = process.GetMemoryCapacity();
1985                                  break;
1986                              case InfoType.UsedMemorySize:
1987                                  value = process.GetMemoryUsage();
1988                                  break;
1989  
1990                              case InfoType.AslrRegionAddress:
1991                                  value = process.MemoryManager.GetAddrSpaceBaseAddr();
1992                                  break;
1993                              case InfoType.AslrRegionSize:
1994                                  value = process.MemoryManager.GetAddrSpaceSize();
1995                                  break;
1996  
1997                              case InfoType.StackRegionAddress:
1998                                  value = process.MemoryManager.StackRegionStart;
1999                                  break;
2000                              case InfoType.StackRegionSize:
2001                                  value = process.MemoryManager.StackRegionEnd - process.MemoryManager.StackRegionStart;
2002                                  break;
2003  
2004                              case InfoType.SystemResourceSizeTotal:
2005                                  value = process.PersonalMmHeapPagesCount * KPageTableBase.PageSize;
2006                                  break;
2007                              case InfoType.SystemResourceSizeUsed:
2008                                  if (process.PersonalMmHeapPagesCount != 0)
2009                                  {
2010                                      value = process.MemoryManager.GetMmUsedPages() * KPageTableBase.PageSize;
2011                                  }
2012                                  break;
2013  
2014                              case InfoType.ProgramId:
2015                                  value = process.TitleId;
2016                                  break;
2017  
2018                              case InfoType.UserExceptionContextAddress:
2019                                  value = process.UserExceptionContextAddress;
2020                                  break;
2021  
2022                              case InfoType.TotalNonSystemMemorySize:
2023                                  value = process.GetMemoryCapacityWithoutPersonalMmHeap();
2024                                  break;
2025                              case InfoType.UsedNonSystemMemorySize:
2026                                  value = process.GetMemoryUsageWithoutPersonalMmHeap();
2027                                  break;
2028  
2029                              case InfoType.IsApplication:
2030                                  value = process.IsApplication ? 1UL : 0UL;
2031                                  break;
2032  
2033                              case InfoType.FreeThreadCount:
2034                                  if (process.ResourceLimit != null)
2035                                  {
2036                                      value = (ulong)(process.ResourceLimit.GetLimitValue(LimitableResource.Thread) -
2037                                                      process.ResourceLimit.GetCurrentValue(LimitableResource.Thread));
2038                                  }
2039                                  else
2040                                  {
2041                                      value = 0;
2042                                  }
2043                                  break;
2044  
2045                              case InfoType.AliasRegionExtraSize:
2046                                  value = process.MemoryManager.AliasRegionExtraSize;
2047                                  break;
2048                          }
2049                          break;
2050                      }
2051  
2052                  case InfoType.DebuggerAttached:
2053                      {
2054                          if (handle != 0)
2055                          {
2056                              return KernelResult.InvalidHandle;
2057                          }
2058  
2059                          if (subId != 0)
2060                          {
2061                              return KernelResult.InvalidCombination;
2062                          }
2063  
2064                          value = KernelStatic.GetCurrentProcess().Debug ? 1UL : 0UL;
2065                          break;
2066                      }
2067  
2068                  case InfoType.ResourceLimit:
2069                      {
2070                          if (handle != 0)
2071                          {
2072                              return KernelResult.InvalidHandle;
2073                          }
2074  
2075                          if (subId != 0)
2076                          {
2077                              return KernelResult.InvalidCombination;
2078                          }
2079  
2080                          KProcess currentProcess = KernelStatic.GetCurrentProcess();
2081  
2082                          if (currentProcess.ResourceLimit != null)
2083                          {
2084                              KHandleTable handleTable = currentProcess.HandleTable;
2085                              KResourceLimit resourceLimit = currentProcess.ResourceLimit;
2086  
2087                              Result result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
2088  
2089                              if (result != Result.Success)
2090                              {
2091                                  return result;
2092                              }
2093  
2094                              value = (uint)resLimHandle;
2095                          }
2096                          break;
2097                      }
2098  
2099                  case InfoType.IdleTickCount:
2100                      {
2101                          if (handle != 0)
2102                          {
2103                              return KernelResult.InvalidHandle;
2104                          }
2105  
2106                          int currentCore = KernelStatic.GetCurrentThread().CurrentCore;
2107  
2108                          if (subId != -1 && subId != currentCore)
2109                          {
2110                              return KernelResult.InvalidCombination;
2111                          }
2112  
2113                          value = (ulong)KTimeManager.ConvertHostTicksToTicks(_context.Schedulers[currentCore].TotalIdleTimeTicks);
2114                          break;
2115                      }
2116  
2117                  case InfoType.RandomEntropy:
2118                      {
2119                          if (handle != 0)
2120                          {
2121                              return KernelResult.InvalidHandle;
2122                          }
2123  
2124                          if ((ulong)subId > 3)
2125                          {
2126                              return KernelResult.InvalidCombination;
2127                          }
2128  
2129                          KProcess currentProcess = KernelStatic.GetCurrentProcess();
2130  
2131                          value = currentProcess.RandomEntropy[subId];
2132                          break;
2133                      }
2134  
2135                  case InfoType.ThreadTickCount:
2136                      {
2137                          if (subId < -1 || subId > 3)
2138                          {
2139                              return KernelResult.InvalidCombination;
2140                          }
2141  
2142                          KThread thread = KernelStatic.GetCurrentProcess().HandleTable.GetKThread(handle);
2143  
2144                          if (thread == null)
2145                          {
2146                              return KernelResult.InvalidHandle;
2147                          }
2148  
2149                          KThread currentThread = KernelStatic.GetCurrentThread();
2150  
2151                          int currentCore = currentThread.CurrentCore;
2152  
2153                          if (subId != -1 && subId != currentCore)
2154                          {
2155                              return Result.Success;
2156                          }
2157  
2158                          KScheduler scheduler = _context.Schedulers[currentCore];
2159  
2160                          long timeDelta = PerformanceCounter.ElapsedTicks - scheduler.LastContextSwitchTime;
2161  
2162                          if (subId != -1)
2163                          {
2164                              value = (ulong)KTimeManager.ConvertHostTicksToTicks(timeDelta);
2165                          }
2166                          else
2167                          {
2168                              long totalTimeRunning = thread.TotalTimeRunning;
2169  
2170                              if (thread == currentThread)
2171                              {
2172                                  totalTimeRunning += timeDelta;
2173                              }
2174  
2175                              value = (ulong)KTimeManager.ConvertHostTicksToTicks(totalTimeRunning);
2176                          }
2177                          break;
2178                      }
2179  
2180                  case InfoType.IsSvcPermitted:
2181                      {
2182                          if (handle != 0)
2183                          {
2184                              return KernelResult.InvalidHandle;
2185                          }
2186  
2187                          if (subId != 0x36)
2188                          {
2189                              return KernelResult.InvalidCombination;
2190                          }
2191  
2192                          value = KernelStatic.GetCurrentProcess().IsSvcPermitted((int)subId) ? 1UL : 0UL;
2193                          break;
2194                      }
2195  
2196                  case InfoType.MesosphereCurrentProcess:
2197                      {
2198                          if (handle != 0)
2199                          {
2200                              return KernelResult.InvalidHandle;
2201                          }
2202  
2203                          if (subId != 0)
2204                          {
2205                              return KernelResult.InvalidCombination;
2206                          }
2207  
2208                          KProcess currentProcess = KernelStatic.GetCurrentProcess();
2209                          KHandleTable handleTable = currentProcess.HandleTable;
2210  
2211                          Result result = handleTable.GenerateHandle(currentProcess, out int outHandle);
2212  
2213                          if (result != Result.Success)
2214                          {
2215                              return result;
2216                          }
2217  
2218                          value = (uint)outHandle;
2219                          break;
2220                      }
2221  
2222                  default:
2223                      return KernelResult.InvalidEnumValue;
2224              }
2225  
2226              return Result.Success;
2227          }
2228  
2229          [Svc(0x45)]
2230          public Result CreateEvent(out int wEventHandle, out int rEventHandle)
2231          {
2232              KEvent Event = new(_context);
2233  
2234              KProcess process = KernelStatic.GetCurrentProcess();
2235  
2236              Result result = process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
2237  
2238              if (result == Result.Success)
2239              {
2240                  result = process.HandleTable.GenerateHandle(Event.ReadableEvent, out rEventHandle);
2241  
2242                  if (result != Result.Success)
2243                  {
2244                      process.HandleTable.CloseHandle(wEventHandle);
2245                  }
2246              }
2247              else
2248              {
2249                  rEventHandle = 0;
2250              }
2251  
2252              return result;
2253          }
2254  
2255          [Svc(0x65)]
2256          public Result GetProcessList(out int count, [PointerSized] ulong address, int maxCount)
2257          {
2258              count = 0;
2259  
2260              if ((maxCount >> 28) != 0)
2261              {
2262                  return KernelResult.MaximumExceeded;
2263              }
2264  
2265              if (maxCount != 0)
2266              {
2267                  KProcess currentProcess = KernelStatic.GetCurrentProcess();
2268  
2269                  ulong copySize = (ulong)maxCount * 8;
2270  
2271                  if (address + copySize <= address)
2272                  {
2273                      return KernelResult.InvalidMemState;
2274                  }
2275  
2276                  if (currentProcess.MemoryManager.OutsideAddrSpace(address, copySize))
2277                  {
2278                      return KernelResult.InvalidMemState;
2279                  }
2280              }
2281  
2282              int copyCount = 0;
2283  
2284              lock (_context.Processes)
2285              {
2286                  foreach (KProcess process in _context.Processes.Values)
2287                  {
2288                      if (copyCount < maxCount)
2289                      {
2290                          if (!KernelTransfer.KernelToUser(address + (ulong)copyCount * 8, process.Pid))
2291                          {
2292                              return KernelResult.UserCopyFailed;
2293                          }
2294                      }
2295  
2296                      copyCount++;
2297                  }
2298              }
2299  
2300              count = copyCount;
2301  
2302              return Result.Success;
2303          }
2304  
2305          [Svc(0x6f)]
2306          public Result GetSystemInfo(out long value, uint id, int handle, long subId)
2307          {
2308              value = 0;
2309  
2310              if (id > 2)
2311              {
2312                  return KernelResult.InvalidEnumValue;
2313              }
2314  
2315              if (handle != 0)
2316              {
2317                  return KernelResult.InvalidHandle;
2318              }
2319  
2320              if (id < 2)
2321              {
2322                  if ((ulong)subId > 3)
2323                  {
2324                      return KernelResult.InvalidCombination;
2325                  }
2326  
2327                  KMemoryRegionManager region = _context.MemoryManager.MemoryRegions[subId];
2328  
2329                  switch (id)
2330                  {
2331                      // Memory region capacity.
2332                      case 0:
2333                          value = (long)region.Size;
2334                          break;
2335  
2336                      // Memory region free space.
2337                      case 1:
2338                          {
2339                              ulong freePagesCount = region.GetFreePages();
2340  
2341                              value = (long)(freePagesCount * KPageTableBase.PageSize);
2342  
2343                              break;
2344                          }
2345                  }
2346              }
2347              else /* if (Id == 2) */
2348              {
2349                  if ((ulong)subId > 1)
2350                  {
2351                      return KernelResult.InvalidCombination;
2352                  }
2353  
2354                  switch (subId)
2355                  {
2356                      case 0:
2357                          value = _context.PrivilegedProcessLowestId;
2358                          break;
2359                      case 1:
2360                          value = _context.PrivilegedProcessHighestId;
2361                          break;
2362                  }
2363              }
2364  
2365              return Result.Success;
2366          }
2367  
2368          [Svc(0x30)]
2369          public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
2370          {
2371              limitValue = 0;
2372  
2373              if (resource >= LimitableResource.Count)
2374              {
2375                  return KernelResult.InvalidEnumValue;
2376              }
2377  
2378              KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KResourceLimit>(handle);
2379  
2380              if (resourceLimit == null)
2381              {
2382                  return KernelResult.InvalidHandle;
2383              }
2384  
2385              limitValue = resourceLimit.GetLimitValue(resource);
2386  
2387              return Result.Success;
2388          }
2389  
2390          [Svc(0x31)]
2391          public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
2392          {
2393              limitValue = 0;
2394  
2395              if (resource >= LimitableResource.Count)
2396              {
2397                  return KernelResult.InvalidEnumValue;
2398              }
2399  
2400              KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KResourceLimit>(handle);
2401  
2402              if (resourceLimit == null)
2403              {
2404                  return KernelResult.InvalidHandle;
2405              }
2406  
2407              limitValue = resourceLimit.GetCurrentValue(resource);
2408  
2409              return Result.Success;
2410          }
2411  
2412          [Svc(0x37)]
2413          public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
2414          {
2415              peak = 0;
2416  
2417              if (resource >= LimitableResource.Count)
2418              {
2419                  return KernelResult.InvalidEnumValue;
2420              }
2421  
2422              KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KResourceLimit>(handle);
2423  
2424              if (resourceLimit == null)
2425              {
2426                  return KernelResult.InvalidHandle;
2427              }
2428  
2429              peak = resourceLimit.GetPeakValue(resource);
2430  
2431              return Result.Success;
2432          }
2433  
2434          [Svc(0x7d)]
2435          public Result CreateResourceLimit(out int handle)
2436          {
2437              KResourceLimit limit = new(_context);
2438  
2439              KProcess process = KernelStatic.GetCurrentProcess();
2440  
2441              return process.HandleTable.GenerateHandle(limit, out handle);
2442          }
2443  
2444          [Svc(0x7e)]
2445          public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
2446          {
2447              if (resource >= LimitableResource.Count)
2448              {
2449                  return KernelResult.InvalidEnumValue;
2450              }
2451  
2452              KResourceLimit resourceLimit = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KResourceLimit>(handle);
2453  
2454              if (resourceLimit == null)
2455              {
2456                  return KernelResult.InvalidHandle;
2457              }
2458  
2459              return resourceLimit.SetLimitValue(resource, limitValue);
2460          }
2461  
2462          // Thread
2463  
2464          [Svc(8)]
2465          public Result CreateThread(
2466              out int handle,
2467              [PointerSized] ulong entrypoint,
2468              [PointerSized] ulong argsPtr,
2469              [PointerSized] ulong stackTop,
2470              int priority,
2471              int cpuCore)
2472          {
2473              return CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore, null);
2474          }
2475  
2476          public Result CreateThread(
2477              out int handle,
2478              ulong entrypoint,
2479              ulong argsPtr,
2480              ulong stackTop,
2481              int priority,
2482              int cpuCore,
2483              ThreadStart customThreadStart)
2484          {
2485              handle = 0;
2486  
2487              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2488  
2489              if (cpuCore == -2)
2490              {
2491                  cpuCore = currentProcess.DefaultCpuCore;
2492              }
2493  
2494              if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore))
2495              {
2496                  return KernelResult.InvalidCpuCore;
2497              }
2498  
2499              if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority))
2500              {
2501                  return KernelResult.InvalidPriority;
2502              }
2503  
2504              long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
2505  
2506              if (currentProcess.ResourceLimit != null &&
2507                 !currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout))
2508              {
2509                  return KernelResult.ResLimitExceeded;
2510              }
2511  
2512              KThread thread = new(_context);
2513  
2514              Result result = currentProcess.InitializeThread(
2515                  thread,
2516                  entrypoint,
2517                  argsPtr,
2518                  stackTop,
2519                  priority,
2520                  cpuCore,
2521                  customThreadStart);
2522  
2523              if (result == Result.Success)
2524              {
2525                  KProcess process = KernelStatic.GetCurrentProcess();
2526  
2527                  result = process.HandleTable.GenerateHandle(thread, out handle);
2528              }
2529              else
2530              {
2531                  currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
2532              }
2533  
2534              thread.DecrementReferenceCount();
2535  
2536              return result;
2537          }
2538  
2539          [Svc(9)]
2540          public Result StartThread(int handle)
2541          {
2542              KProcess process = KernelStatic.GetCurrentProcess();
2543  
2544              KThread thread = process.HandleTable.GetKThread(handle);
2545  
2546              if (thread != null)
2547              {
2548                  thread.IncrementReferenceCount();
2549  
2550                  Result result = thread.Start();
2551  
2552                  if (result == Result.Success)
2553                  {
2554                      thread.IncrementReferenceCount();
2555                  }
2556  
2557                  thread.DecrementReferenceCount();
2558  
2559                  return result;
2560              }
2561              else
2562              {
2563                  return KernelResult.InvalidHandle;
2564              }
2565          }
2566  
2567          [Svc(0xa)]
2568          public void ExitThread()
2569          {
2570              KThread currentThread = KernelStatic.GetCurrentThread();
2571  
2572              currentThread.Exit();
2573          }
2574  
2575          [Svc(0xb)]
2576          public void SleepThread(long timeout)
2577          {
2578              if (timeout < 1)
2579              {
2580                  switch (timeout)
2581                  {
2582                      case 0:
2583                          KScheduler.Yield(_context);
2584                          break;
2585                      case -1:
2586                          KScheduler.YieldWithLoadBalancing(_context);
2587                          break;
2588                      case -2:
2589                          KScheduler.YieldToAnyThread(_context);
2590                          break;
2591                  }
2592              }
2593              else
2594              {
2595                  KernelStatic.GetCurrentThread().Sleep(timeout + KTimeManager.DefaultTimeIncrementNanoseconds);
2596              }
2597          }
2598  
2599          [Svc(0xc)]
2600          public Result GetThreadPriority(out int priority, int handle)
2601          {
2602              KProcess process = KernelStatic.GetCurrentProcess();
2603  
2604              KThread thread = process.HandleTable.GetKThread(handle);
2605  
2606              if (thread != null)
2607              {
2608                  priority = thread.DynamicPriority;
2609  
2610                  return Result.Success;
2611              }
2612              else
2613              {
2614                  priority = 0;
2615  
2616                  return KernelResult.InvalidHandle;
2617              }
2618          }
2619  
2620          [Svc(0xd)]
2621          public Result SetThreadPriority(int handle, int priority)
2622          {
2623              // TODO: NPDM check.
2624  
2625              KProcess process = KernelStatic.GetCurrentProcess();
2626  
2627              KThread thread = process.HandleTable.GetKThread(handle);
2628  
2629              if (thread == null)
2630              {
2631                  return KernelResult.InvalidHandle;
2632              }
2633  
2634              thread.SetPriority(priority);
2635  
2636              return Result.Success;
2637          }
2638  
2639          [Svc(0xe)]
2640          public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
2641          {
2642              KProcess process = KernelStatic.GetCurrentProcess();
2643  
2644              KThread thread = process.HandleTable.GetKThread(handle);
2645  
2646              if (thread != null)
2647              {
2648                  preferredCore = thread.PreferredCore;
2649                  affinityMask = thread.AffinityMask;
2650  
2651                  return Result.Success;
2652              }
2653              else
2654              {
2655                  preferredCore = 0;
2656                  affinityMask = 0;
2657  
2658                  return KernelResult.InvalidHandle;
2659              }
2660          }
2661  
2662          [Svc(0xf)]
2663          public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
2664          {
2665              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2666  
2667              if (preferredCore == -2)
2668              {
2669                  preferredCore = currentProcess.DefaultCpuCore;
2670  
2671                  affinityMask = 1UL << preferredCore;
2672              }
2673              else
2674              {
2675                  if ((currentProcess.Capabilities.AllowedCpuCoresMask | affinityMask) !=
2676                       currentProcess.Capabilities.AllowedCpuCoresMask)
2677                  {
2678                      return KernelResult.InvalidCpuCore;
2679                  }
2680  
2681                  if (affinityMask == 0)
2682                  {
2683                      return KernelResult.InvalidCombination;
2684                  }
2685  
2686                  if ((uint)preferredCore > 3)
2687                  {
2688                      if ((preferredCore | 2) != -1)
2689                      {
2690                          return KernelResult.InvalidCpuCore;
2691                      }
2692                  }
2693                  else if ((affinityMask & (1UL << preferredCore)) == 0)
2694                  {
2695                      return KernelResult.InvalidCombination;
2696                  }
2697              }
2698  
2699              KProcess process = KernelStatic.GetCurrentProcess();
2700  
2701              KThread thread = process.HandleTable.GetKThread(handle);
2702  
2703              if (thread == null)
2704              {
2705                  return KernelResult.InvalidHandle;
2706              }
2707  
2708              return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
2709          }
2710  
2711          [Svc(0x10)]
2712          public int GetCurrentProcessorNumber()
2713          {
2714              return KernelStatic.GetCurrentThread().CurrentCore;
2715          }
2716  
2717          [Svc(0x25)]
2718          public Result GetThreadId(out ulong threadUid, int handle)
2719          {
2720              KProcess process = KernelStatic.GetCurrentProcess();
2721  
2722              KThread thread = process.HandleTable.GetKThread(handle);
2723  
2724              if (thread != null)
2725              {
2726                  threadUid = thread.ThreadUid;
2727  
2728                  return Result.Success;
2729              }
2730              else
2731              {
2732                  threadUid = 0;
2733  
2734                  return KernelResult.InvalidHandle;
2735              }
2736          }
2737  
2738          [Svc(0x32)]
2739          public Result SetThreadActivity(int handle, bool pause)
2740          {
2741              KProcess process = KernelStatic.GetCurrentProcess();
2742  
2743              KThread thread = process.HandleTable.GetObject<KThread>(handle);
2744  
2745              if (thread == null)
2746              {
2747                  return KernelResult.InvalidHandle;
2748              }
2749  
2750              if (thread.Owner != process)
2751              {
2752                  return KernelResult.InvalidHandle;
2753              }
2754  
2755              if (thread == KernelStatic.GetCurrentThread())
2756              {
2757                  return KernelResult.InvalidThread;
2758              }
2759  
2760              return thread.SetActivity(pause);
2761          }
2762  
2763          [Svc(0x33)]
2764          public Result GetThreadContext3([PointerSized] ulong address, int handle)
2765          {
2766              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2767              KThread currentThread = KernelStatic.GetCurrentThread();
2768  
2769              KThread thread = currentProcess.HandleTable.GetObject<KThread>(handle);
2770  
2771              if (thread == null)
2772              {
2773                  return KernelResult.InvalidHandle;
2774              }
2775  
2776              if (thread.Owner != currentProcess)
2777              {
2778                  return KernelResult.InvalidHandle;
2779              }
2780  
2781              if (currentThread == thread)
2782              {
2783                  return KernelResult.InvalidThread;
2784              }
2785  
2786              Result result = thread.GetThreadContext3(out ThreadContext context);
2787  
2788              if (result == Result.Success)
2789              {
2790                  return KernelTransfer.KernelToUser(address, context)
2791                      ? Result.Success
2792                      : KernelResult.InvalidMemState;
2793              }
2794  
2795              return result;
2796          }
2797  
2798          // Thread synchronization
2799  
2800          [Svc(0x18)]
2801          public Result WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout)
2802          {
2803              handleIndex = 0;
2804  
2805              if ((uint)handlesCount > KThread.MaxWaitSyncObjects)
2806              {
2807                  return KernelResult.MaximumExceeded;
2808              }
2809  
2810              KThread currentThread = KernelStatic.GetCurrentThread();
2811  
2812              if (handlesCount != 0)
2813              {
2814                  KProcess currentProcess = KernelStatic.GetCurrentProcess();
2815  
2816                  if (currentProcess.MemoryManager.AddrSpaceStart > handlesPtr)
2817                  {
2818                      return KernelResult.UserCopyFailed;
2819                  }
2820  
2821                  long handlesSize = handlesCount * 4;
2822  
2823                  if (handlesPtr + (ulong)handlesSize <= handlesPtr)
2824                  {
2825                      return KernelResult.UserCopyFailed;
2826                  }
2827  
2828                  if (handlesPtr + (ulong)handlesSize - 1 > currentProcess.MemoryManager.AddrSpaceEnd - 1)
2829                  {
2830                      return KernelResult.UserCopyFailed;
2831                  }
2832  
2833                  Span<int> handles = new Span<int>(currentThread.WaitSyncHandles)[..handlesCount];
2834  
2835                  if (!KernelTransfer.UserToKernelArray(handlesPtr, handles))
2836                  {
2837                      return KernelResult.UserCopyFailed;
2838                  }
2839  
2840                  return WaitSynchronization(out handleIndex, handles, timeout);
2841              }
2842  
2843              return WaitSynchronization(out handleIndex, ReadOnlySpan<int>.Empty, timeout);
2844          }
2845  
2846          public Result WaitSynchronization(out int handleIndex, ReadOnlySpan<int> handles, long timeout)
2847          {
2848              handleIndex = 0;
2849  
2850              if ((uint)handles.Length > KThread.MaxWaitSyncObjects)
2851              {
2852                  return KernelResult.MaximumExceeded;
2853              }
2854  
2855              KThread currentThread = KernelStatic.GetCurrentThread();
2856  
2857              var syncObjs = new Span<KSynchronizationObject>(currentThread.WaitSyncObjects)[..handles.Length];
2858  
2859              if (handles.Length != 0)
2860              {
2861                  KProcess currentProcess = KernelStatic.GetCurrentProcess();
2862  
2863                  int processedHandles = 0;
2864  
2865                  for (; processedHandles < handles.Length; processedHandles++)
2866                  {
2867                      KSynchronizationObject syncObj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[processedHandles]);
2868  
2869                      if (syncObj == null)
2870                      {
2871                          break;
2872                      }
2873  
2874                      syncObjs[processedHandles] = syncObj;
2875  
2876                      syncObj.IncrementReferenceCount();
2877                  }
2878  
2879                  if (processedHandles != handles.Length)
2880                  {
2881                      // One or more handles are invalid.
2882                      for (int index = 0; index < processedHandles; index++)
2883                      {
2884                          currentThread.WaitSyncObjects[index].DecrementReferenceCount();
2885                      }
2886  
2887                      return KernelResult.InvalidHandle;
2888                  }
2889              }
2890  
2891              if (timeout > 0)
2892              {
2893                  timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
2894              }
2895  
2896              Result result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex);
2897  
2898              if (result == KernelResult.PortRemoteClosed)
2899              {
2900                  result = Result.Success;
2901              }
2902  
2903              for (int index = 0; index < handles.Length; index++)
2904              {
2905                  currentThread.WaitSyncObjects[index].DecrementReferenceCount();
2906              }
2907  
2908              return result;
2909          }
2910  
2911          [Svc(0x19)]
2912          public Result CancelSynchronization(int handle)
2913          {
2914              KProcess process = KernelStatic.GetCurrentProcess();
2915  
2916              KThread thread = process.HandleTable.GetKThread(handle);
2917  
2918              if (thread == null)
2919              {
2920                  return KernelResult.InvalidHandle;
2921              }
2922  
2923              thread.CancelSynchronization();
2924  
2925              return Result.Success;
2926          }
2927  
2928          [Svc(0x1a)]
2929          public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
2930          {
2931              if (IsPointingInsideKernel(mutexAddress))
2932              {
2933                  return KernelResult.InvalidMemState;
2934              }
2935  
2936              if (IsAddressNotWordAligned(mutexAddress))
2937              {
2938                  return KernelResult.InvalidAddress;
2939              }
2940  
2941              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2942  
2943              return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
2944          }
2945  
2946          [Svc(0x1b)]
2947          public Result ArbitrateUnlock([PointerSized] ulong mutexAddress)
2948          {
2949              if (IsPointingInsideKernel(mutexAddress))
2950              {
2951                  return KernelResult.InvalidMemState;
2952              }
2953  
2954              if (IsAddressNotWordAligned(mutexAddress))
2955              {
2956                  return KernelResult.InvalidAddress;
2957              }
2958  
2959              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2960  
2961              return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
2962          }
2963  
2964          [Svc(0x1c)]
2965          public Result WaitProcessWideKeyAtomic(
2966              [PointerSized] ulong mutexAddress,
2967              [PointerSized] ulong condVarAddress,
2968              int handle,
2969              long timeout)
2970          {
2971              if (IsPointingInsideKernel(mutexAddress))
2972              {
2973                  return KernelResult.InvalidMemState;
2974              }
2975  
2976              if (IsAddressNotWordAligned(mutexAddress))
2977              {
2978                  return KernelResult.InvalidAddress;
2979              }
2980  
2981              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2982  
2983              if (timeout > 0)
2984              {
2985                  timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
2986              }
2987  
2988              return currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
2989                  mutexAddress,
2990                  condVarAddress,
2991                  handle,
2992                  timeout);
2993          }
2994  
2995          [Svc(0x1d)]
2996          public Result SignalProcessWideKey([PointerSized] ulong address, int count)
2997          {
2998              KProcess currentProcess = KernelStatic.GetCurrentProcess();
2999  
3000              currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
3001  
3002              return Result.Success;
3003          }
3004  
3005          [Svc(0x34)]
3006          public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
3007          {
3008              if (IsPointingInsideKernel(address))
3009              {
3010                  return KernelResult.InvalidMemState;
3011              }
3012  
3013              if (IsAddressNotWordAligned(address))
3014              {
3015                  return KernelResult.InvalidAddress;
3016              }
3017  
3018              KProcess currentProcess = KernelStatic.GetCurrentProcess();
3019  
3020              if (timeout > 0)
3021              {
3022                  timeout += KTimeManager.DefaultTimeIncrementNanoseconds;
3023              }
3024  
3025              return type switch
3026              {
3027                  ArbitrationType.WaitIfLessThan
3028                      => currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout),
3029                  ArbitrationType.DecrementAndWaitIfLessThan
3030                      => currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout),
3031                  ArbitrationType.WaitIfEqual
3032                      => currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout),
3033                  _ => KernelResult.InvalidEnumValue,
3034              };
3035          }
3036  
3037          [Svc(0x35)]
3038          public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
3039          {
3040              if (IsPointingInsideKernel(address))
3041              {
3042                  return KernelResult.InvalidMemState;
3043              }
3044  
3045              if (IsAddressNotWordAligned(address))
3046              {
3047                  return KernelResult.InvalidAddress;
3048              }
3049  
3050              KProcess currentProcess = KernelStatic.GetCurrentProcess();
3051  
3052              return type switch
3053              {
3054                  SignalType.Signal
3055                      => currentProcess.AddressArbiter.Signal(address, count),
3056                  SignalType.SignalAndIncrementIfEqual
3057                      => currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count),
3058                  SignalType.SignalAndModifyIfEqual
3059                      => currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count),
3060                  _ => KernelResult.InvalidEnumValue,
3061              };
3062          }
3063  
3064          [Svc(0x36)]
3065          public Result SynchronizePreemptionState()
3066          {
3067              KernelStatic.GetCurrentThread().SynchronizePreemptionState();
3068  
3069              return Result.Success;
3070          }
3071  
3072          // Not actual syscalls, used by HLE services and such.
3073  
3074          public IExternalEvent GetExternalEvent(int handle)
3075          {
3076              KWritableEvent writableEvent = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KWritableEvent>(handle);
3077  
3078              if (writableEvent == null)
3079              {
3080                  return null;
3081              }
3082  
3083              return new ExternalEvent(writableEvent);
3084          }
3085  
3086          public IVirtualMemoryManager GetMemoryManagerByProcessHandle(int handle)
3087          {
3088              return KernelStatic.GetCurrentProcess().HandleTable.GetKProcess(handle).CpuMemory;
3089          }
3090  
3091          public ulong GetTransferMemoryAddress(int handle)
3092          {
3093              KTransferMemory transferMemory = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KTransferMemory>(handle);
3094  
3095              if (transferMemory == null)
3096              {
3097                  return 0;
3098              }
3099  
3100              return transferMemory.Address;
3101          }
3102  
3103          private static bool IsPointingInsideKernel(ulong address)
3104          {
3105              return (address + 0x1000000000) < 0xffffff000;
3106          }
3107  
3108          private static bool IsAddressNotWordAligned(ulong address)
3109          {
3110              return (address & 3) != 0;
3111          }
3112      }
3113  }