Ryujinx/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs

733 lines
22 KiB
C#
Raw Normal View History

using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
2018-02-05 00:08:20 +01:00
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
2018-02-05 00:08:20 +01:00
{
partial class SvcHandler
{
public void ExitProcess64()
{
ExitProcess();
}
public void ExitProcess32()
{
ExitProcess();
}
public KernelResult TerminateProcess64([R(0)] int handle)
{
return TerminateProcess(handle);
}
public KernelResult TerminateProcess32([R(0)] int handle)
{
return TerminateProcess(handle);
}
private KernelResult TerminateProcess(int handle)
{
KProcess process = _process.HandleTable.GetObject<KProcess>(handle);
KernelResult result;
if (process != null)
{
if (process == _system.Scheduler.GetCurrentProcess())
{
result = KernelResult.Success;
process.DecrementToZeroWhileTerminatingCurrent();
}
else
{
result = process.Terminate();
process.DecrementReferenceCount();
}
}
else
{
result = KernelResult.InvalidHandle;
}
return result;
}
private void ExitProcess()
{
_system.Scheduler.GetCurrentProcess().TerminateCurrentProcess();
}
public KernelResult SignalEvent64([R(0)] int handle)
{
return SignalEvent(handle);
}
public KernelResult SignalEvent32([R(0)] int handle)
{
return SignalEvent(handle);
}
private KernelResult SignalEvent(int handle)
{
KWritableEvent writableEvent = _process.HandleTable.GetObject<KWritableEvent>(handle);
KernelResult result;
if (writableEvent != null)
{
writableEvent.Signal();
result = KernelResult.Success;
}
else
{
result = KernelResult.InvalidHandle;
}
return result;
}
public KernelResult ClearEvent64([R(0)] int handle)
{
return ClearEvent(handle);
}
public KernelResult ClearEvent32([R(0)] int handle)
{
return ClearEvent(handle);
}
private KernelResult ClearEvent(int handle)
{
KernelResult result;
KWritableEvent writableEvent = _process.HandleTable.GetObject<KWritableEvent>(handle);
if (writableEvent == null)
{
KReadableEvent readableEvent = _process.HandleTable.GetObject<KReadableEvent>(handle);
result = readableEvent?.Clear() ?? KernelResult.InvalidHandle;
}
else
{
result = writableEvent.Clear();
}
return result;
}
public KernelResult CloseHandle64([R(0)] int handle)
2018-02-05 00:08:20 +01:00
{
return CloseHandle(handle);
}
2018-02-05 00:08:20 +01:00
public KernelResult CloseHandle32([R(0)] int handle)
{
return CloseHandle(handle);
}
private KernelResult CloseHandle(int handle)
{
KAutoObject obj = _process.HandleTable.GetObject<KAutoObject>(handle);
_process.HandleTable.CloseHandle(handle);
if (obj == null)
{
return KernelResult.InvalidHandle;
}
if (obj is KSession session)
{
session.Dispose();
}
else if (obj is KTransferMemory transferMemory)
{
_process.MemoryManager.ResetTransferMemory(
transferMemory.Address,
transferMemory.Size);
}
2018-02-05 00:08:20 +01:00
return KernelResult.Success;
2018-02-05 00:08:20 +01:00
}
public KernelResult ResetSignal64([R(0)] int handle)
2018-02-05 00:08:20 +01:00
{
return ResetSignal(handle);
}
2018-02-05 00:08:20 +01:00
public KernelResult ResetSignal32([R(0)] int handle)
{
return ResetSignal(handle);
}
private KernelResult ResetSignal(int handle)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KReadableEvent readableEvent = currentProcess.HandleTable.GetObject<KReadableEvent>(handle);
2018-02-05 00:08:20 +01:00
KernelResult result;
if (readableEvent != null)
{
result = readableEvent.ClearIfSignaled();
}
else
{
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process != null)
{
result = process.ClearIfNotExited();
}
else
{
result = KernelResult.InvalidHandle;
}
}
return result;
2018-02-05 00:08:20 +01:00
}
public ulong GetSystemTick64()
2018-02-05 00:08:20 +01:00
{
Add a new JIT compiler for CPU code (#693) * Start of the ARMeilleure project * Refactoring around the old IRAdapter, now renamed to PreAllocator * Optimize the LowestBitSet method * Add CLZ support and fix CLS implementation * Add missing Equals and GetHashCode overrides on some structs, misc small tweaks * Implement the ByteSwap IR instruction, and some refactoring on the assembler * Implement the DivideUI IR instruction and fix 64-bits IDIV * Correct constant operand type on CSINC * Move division instructions implementation to InstEmitDiv * Fix destination type for the ConditionalSelect IR instruction * Implement UMULH and SMULH, with new IR instructions * Fix some issues with shift instructions * Fix constant types for BFM instructions * Fix up new tests using the new V128 struct * Update tests * Move DIV tests to a separate file * Add support for calls, and some instructions that depends on them * Start adding support for SIMD & FP types, along with some of the related ARM instructions * Fix some typos and the divide instruction with FP operands * Fix wrong method call on Clz_V * Implement ARM FP & SIMD move instructions, Saddlv_V, and misc. fixes * Implement SIMD logical instructions and more misc. fixes * Fix PSRAD x86 instruction encoding, TRN, UABD and UABDL implementations * Implement float conversion instruction, merge in LDj3SNuD fixes, and some other misc. fixes * Implement SIMD shift instruction and fix Dup_V * Add SCVTF and UCVTF (vector, fixed-point) variants to the opcode table * Fix check with tolerance on tester * Implement FP & SIMD comparison instructions, and some fixes * Update FCVT (Scalar) encoding on the table to support the Half-float variants * Support passing V128 structs, some cleanup on the register allocator, merge LDj3SNuD fixes * Use old memory access methods, made a start on SIMD memory insts support, some fixes * Fix float constant passed to functions, save and restore non-volatile XMM registers, other fixes * Fix arguments count with struct return values, other fixes * More instructions * Misc. fixes and integrate LDj3SNuD fixes * Update tests * Add a faster linear scan allocator, unwinding support on windows, and other changes * Update Ryujinx.HLE * Update Ryujinx.Graphics * Fix V128 return pointer passing, RCX is clobbered * Update Ryujinx.Tests * Update ITimeZoneService * Stop using GetFunctionPointer as that can't be called from native code, misc. fixes and tweaks * Use generic GetFunctionPointerForDelegate method and other tweaks * Some refactoring on the code generator, assert on invalid operations and use a separate enum for intrinsics * Remove some unused code on the assembler * Fix REX.W prefix regression on float conversion instructions, add some sort of profiler * Add hardware capability detection * Fix regression on Sha1h and revert Fcm** changes * Add SSE2-only paths on vector extract and insert, some refactoring on the pre-allocator * Fix silly mistake introduced on last commit on CpuId * Generate inline stack probes when the stack allocation is too large * Initial support for the System-V ABI * Support multiple destination operands * Fix SSE2 VectorInsert8 path, and other fixes * Change placement of XMM callee save and restore code to match other compilers * Rename Dest to Destination and Inst to Instruction * Fix a regression related to calls and the V128 type * Add an extra space on comments to match code style * Some refactoring * Fix vector insert FP32 SSE2 path * Port over the ARM32 instructions * Avoid memory protection races on JIT Cache * Another fix on VectorInsert FP32 (thanks to LDj3SNuD * Float operands don't need to use the same register when VEX is supported * Add a new register allocator, higher quality code for hot code (tier up), and other tweaks * Some nits, small improvements on the pre allocator * CpuThreadState is gone * Allow changing CPU emulators with a config entry * Add runtime identifiers on the ARMeilleure project * Allow switching between CPUs through a config entry (pt. 2) * Change win10-x64 to win-x64 on projects * Update the Ryujinx project to use ARMeilleure * Ensure that the selected register is valid on the hybrid allocator * Allow exiting on returns to 0 (should fix test regression) * Remove register assignments for most used variables on the hybrid allocator * Do not use fixed registers as spill temp * Add missing namespace and remove unneeded using * Address PR feedback * Fix types, etc * Enable AssumeStrictAbiCompliance by default * Ensure that Spill and Fill don't load or store any more than necessary
2019-08-08 20:56:22 +02:00
return _system.Scheduler.GetCurrentThread().Context.CntpctEl0;
2018-02-05 00:08:20 +01:00
}
public void GetSystemTick32([R(0)] out uint resultLow, [R(1)] out uint resultHigh)
{
ulong result = _system.Scheduler.GetCurrentThread().Context.CntpctEl0;
resultLow = (uint)(result & uint.MaxValue);
resultHigh = (uint)(result >> 32);
}
public KernelResult GetProcessId64([R(1)] int handle, [R(1)] out long pid)
{
return GetProcessId(handle, out pid);
}
public KernelResult GetProcessId32([R(1)] int handle, [R(1)] out int pidLow, [R(2)] out int pidHigh)
{
KernelResult result = GetProcessId(handle, out long pid);
pidLow = (int)(pid & uint.MaxValue);
pidHigh = (int)(pid >> 32);
return result;
}
private KernelResult GetProcessId(int handle, out long pid)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process == null)
{
KThread thread = currentProcess.HandleTable.GetKThread(handle);
if (thread != null)
{
process = thread.Owner;
}
// TODO: KDebugEvent.
}
pid = process?.Pid ?? 0;
return process != null
? KernelResult.Success
: KernelResult.InvalidHandle;
}
public void Break64([R(0)] ulong reason, [R(1)] ulong x1, [R(2)] ulong info)
2018-02-05 00:08:20 +01:00
{
Break(reason);
}
2018-02-05 00:08:20 +01:00
public void Break32([R(0)] uint reason, [R(1)] uint r1, [R(2)] uint info)
{
Break(reason);
}
private void Break(ulong reason)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
if ((reason & (1UL << 31)) == 0)
{
currentThread.PrintGuestStackTrace();
// As the process is exiting, this is probably caused by emulation termination.
if (currentThread.Owner.State == ProcessState.Exiting)
{
return;
}
// TODO: Debug events.
currentThread.Owner.TerminateCurrentProcess();
throw new GuestBrokeExecutionException();
}
else
{
Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered.");
currentThread.PrintGuestStackTrace();
}
2018-02-05 00:08:20 +01:00
}
public void OutputDebugString64([R(0)] ulong strPtr, [R(1)] ulong size)
2018-02-05 00:08:20 +01:00
{
OutputDebugString(strPtr, size);
}
2018-02-05 00:08:20 +01:00
public void OutputDebugString32([R(0)] uint strPtr, [R(1)] uint size)
{
OutputDebugString(strPtr, size);
}
private void OutputDebugString(ulong strPtr, ulong size)
{
string str = MemoryHelper.ReadAsciiString(_process.CpuMemory, (long)strPtr, (long)size);
2018-02-05 00:08:20 +01:00
Logger.PrintWarning(LogClass.KernelSvc, str);
2018-02-05 00:08:20 +01:00
}
public KernelResult GetInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
2018-02-05 00:08:20 +01:00
{
return GetInfo(id, handle, subId, out value);
}
public KernelResult GetInfo32(
[R(0)] uint subIdLow,
[R(1)] uint id,
[R(2)] int handle,
[R(3)] uint subIdHigh,
[R(1)] out uint valueLow,
[R(2)] out uint valueHigh)
{
long subId = (long)(subIdLow | ((ulong)subIdHigh << 32));
KernelResult result = GetInfo(id, handle, subId, out long value);
valueHigh = (uint)(value >> 32);
valueLow = (uint)(value & uint.MaxValue);
return result;
}
private KernelResult GetInfo(uint id, int handle, long subId, out long value)
{
value = 0;
switch (id)
2018-02-05 00:08:20 +01:00
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 20:
case 21:
case 22:
{
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process == null)
{
return KernelResult.InvalidHandle;
}
switch (id)
{
case 0: value = process.Capabilities.AllowedCpuCoresMask; break;
case 1: value = process.Capabilities.AllowedThreadPriosMask; break;
case 2: value = (long)process.MemoryManager.AliasRegionStart; break;
case 3: value = (long)(process.MemoryManager.AliasRegionEnd -
process.MemoryManager.AliasRegionStart); break;
case 4: value = (long)process.MemoryManager.HeapRegionStart; break;
case 5: value = (long)(process.MemoryManager.HeapRegionEnd -
process.MemoryManager.HeapRegionStart); break;
case 6: value = (long)process.GetMemoryCapacity(); break;
case 7: value = (long)process.GetMemoryUsage(); break;
case 12: value = (long)process.MemoryManager.GetAddrSpaceBaseAddr(); break;
case 13: value = (long)process.MemoryManager.GetAddrSpaceSize(); break;
case 14: value = (long)process.MemoryManager.StackRegionStart; break;
case 15: value = (long)(process.MemoryManager.StackRegionEnd -
process.MemoryManager.StackRegionStart); break;
case 16: value = (long)process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break;
case 17:
if (process.PersonalMmHeapPagesCount != 0)
{
value = process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize;
}
break;
Added GUI to Ryujinx (#695) * Added GUI to Ryujinx * Updated to use Glade Also added scrollbar and default dark theme * Added support for loading icon from .nro files and cleaned up the code a bit * Added General Settings Menu (read-only for now) and moved some functionality from MainMenu.cs to ApplicationLibrary.cs * Added custom GUI theme support and changed the defualt theme to one I just wrote * Added GTK to process path, fixed a bug and minor edits * some more edits and a bug fix * general settings menu is now fully functional. also fixed the bug where ryujinx crashes when it trys to load an invalid gamedir * big rewrite * aesthetic changes to General Settings menu * Added Control Settings one day done feature :P * minor changes * 1st wave of changes * 2nd wave of changes * 3rd wave of changes * Cleanup settings ui * minor edits * new about window added, still needs styling * added spin button for new option and tooltips to settings * Game icons and names are now shown in the games list * add nuget package which contains gtk dependencies * requested changes have been changed * put CreateGameWindow on a new thread and stopped destroying the main menu when a game loads * fixed bug that allowed a user to attempt to load multiple games at a time which causes a crash * Added LastPlayed and TimePlayed columns to the game list * Did some testing and fixed some bugs Im not happy with one of the fixes so i will do it properly an upcoming commit * did some more bug testing and fixed another 2 bugs * caught an exception when ryujinx tries to load non-homebrew as homebrew * Large changes Rewrote ApplicationLibrary.cs (added comments too) so any devs reading it wont get eye cancer, also its probably more efficient now. Added 2 new columns (Developer name and application version) to the game list and wrote the logic for it. Ryujinx now loads NRO's TitleName and TitleID from the NACP file instead of the default NPDM. I also killed a lot of bugs * Moved Files moved ApplicationLibrary.cs to Ryujinx.HLE as that is a better place for it. Moved contents of GUI folder to Ui folder and changed the namespaces of the gui files from Ryujinx to Ryujinx.Ui * Added 'Open Ryujinx Folder' button to the file menu and did some small fixes * New features * updated nuget package with missing dlls and changed emmauss' requested changes * fixed some minor issues * all requested changes marked as resolved have been changed * gdkchan's requested changes * fixed an issue with settings window getting chopped on small res * fixed 2 problems caused by rebase * changed the default theme * applied Thog's patch to fix issue on linux * fixed issue caused by rebase * added update check button that runs ryujinx-updater * reads version info from installer and displays it in about menu * changes completed * requested changes changed * fixed issue with default theme * fixed a bug and completed requested changes * added more tooltips and changed some text
2019-09-02 18:03:57 +02:00
case 18: value = (long)process.TitleId; break;
case 20: value = (long)process.UserExceptionContextAddress; break;
case 21: value = (long)process.GetMemoryCapacityWithoutPersonalMmHeap(); break;
case 22: value = (long)process.GetMemoryUsageWithoutPersonalMmHeap(); break;
}
break;
}
case 8:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
value = _system.Scheduler.GetCurrentProcess().Debug ? 1 : 0;
break;
}
case 9:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (currentProcess.ResourceLimit != null)
{
KHandleTable handleTable = currentProcess.HandleTable;
KResourceLimit resourceLimit = currentProcess.ResourceLimit;
KernelResult result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
if (result != KernelResult.Success)
{
return result;
}
value = (uint)resLimHandle;
}
break;
}
case 10:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
int currentCore = _system.Scheduler.GetCurrentThread().CurrentCore;
if (subId != -1 && subId != currentCore)
{
return KernelResult.InvalidCombination;
}
value = _system.Scheduler.CoreContexts[currentCore].TotalIdleTimeTicks;
break;
}
case 11:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if ((ulong)subId > 3)
{
return KernelResult.InvalidCombination;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
value = currentProcess.RandomEntropy[subId];
break;
}
case 0xf0000002u:
{
if (subId < -1 || subId > 3)
{
return KernelResult.InvalidCombination;
}
KThread thread = _system.Scheduler.GetCurrentProcess().HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
KThread currentThread = _system.Scheduler.GetCurrentThread();
int currentCore = currentThread.CurrentCore;
if (subId != -1 && subId != currentCore)
{
return KernelResult.Success;
}
2018-02-05 00:08:20 +01:00
KCoreContext coreContext = _system.Scheduler.CoreContexts[currentCore];
long timeDelta = PerformanceCounter.ElapsedMilliseconds - coreContext.LastContextSwitchTime;
if (subId != -1)
{
value = KTimeManager.ConvertMillisecondsToTicks(timeDelta);
}
else
{
long totalTimeRunning = thread.TotalTimeRunning;
if (thread == currentThread)
{
totalTimeRunning += timeDelta;
}
value = KTimeManager.ConvertMillisecondsToTicks(totalTimeRunning);
}
break;
}
default: return KernelResult.InvalidEnumValue;
2018-02-05 00:08:20 +01:00
}
return KernelResult.Success;
2018-02-05 00:08:20 +01:00
}
public KernelResult CreateEvent64([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
{
return CreateEvent(out wEventHandle, out rEventHandle);
}
public KernelResult CreateEvent32([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
{
return CreateEvent(out wEventHandle, out rEventHandle);
}
private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
{
KEvent Event = new KEvent(_system);
KernelResult result = _process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
if (result == KernelResult.Success)
{
result = _process.HandleTable.GenerateHandle(Event.ReadableEvent, out rEventHandle);
if (result != KernelResult.Success)
{
_process.HandleTable.CloseHandle(wEventHandle);
}
}
else
{
rEventHandle = 0;
}
return result;
}
public KernelResult GetProcessList64([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
{
return GetProcessList(address, maxCount, out count);
}
public KernelResult GetProcessList32([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
{
return GetProcessList(address, maxCount, out count);
}
private KernelResult GetProcessList(ulong address, int maxCount, out int count)
{
count = 0;
if ((maxCount >> 28) != 0)
{
return KernelResult.MaximumExceeded;
}
if (maxCount != 0)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
ulong copySize = (ulong)maxCount * 8;
if (address + copySize <= address)
{
return KernelResult.InvalidMemState;
}
if (currentProcess.MemoryManager.OutsideAddrSpace(address, copySize))
{
return KernelResult.InvalidMemState;
}
}
int copyCount = 0;
lock (_system.Processes)
{
foreach (KProcess process in _system.Processes.Values)
{
if (copyCount < maxCount)
{
if (!KernelTransfer.KernelToUserInt64(_system, address + (ulong)copyCount * 8, process.Pid))
{
return KernelResult.UserCopyFailed;
}
}
copyCount++;
}
}
count = copyCount;
return KernelResult.Success;
}
public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
{
return GetSystemInfo(id, handle, subId, out value);
}
public KernelResult GetSystemInfo32([R(1)] uint subIdLow, [R(2)] uint id, [R(3)] int handle, [R(3)] uint subIdHigh, [R(1)] out int valueLow, [R(2)] out int valueHigh)
{
long subId = (long)(subIdLow | ((ulong)subIdHigh << 32));
KernelResult result = GetSystemInfo(id, handle, subId, out long value);
valueHigh = (int)(value >> 32);
valueLow = (int)(value & uint.MaxValue);
return result;
}
private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value)
{
value = 0;
if (id > 2)
{
return KernelResult.InvalidEnumValue;
}
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (id < 2)
{
if ((ulong)subId > 3)
{
return KernelResult.InvalidCombination;
}
KMemoryRegionManager region = _system.MemoryRegions[subId];
switch (id)
{
// Memory region capacity.
case 0: value = (long)region.Size; break;
// Memory region free space.
case 1:
{
ulong freePagesCount = region.GetFreePages();
value = (long)(freePagesCount * KMemoryManager.PageSize);
break;
}
}
}
else /* if (Id == 2) */
{
if ((ulong)subId > 1)
{
return KernelResult.InvalidCombination;
}
switch (subId)
{
case 0: value = _system.PrivilegedProcessLowestId; break;
case 1: value = _system.PrivilegedProcessHighestId; break;
}
}
return KernelResult.Success;
}
public KernelResult FlushProcessDataCache32(
[R(0)] uint processHandle,
[R(2)] uint addressLow,
[R(3)] uint addressHigh,
[R(1)] uint sizeLow,
[R(4)] uint sizeHigh)
{
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0. As we don't support (and don't actually need) to flush the cache, this is stubbed.
return KernelResult.Success;
}
2018-02-05 00:08:20 +01:00
}
}