private void SvcSignalProcessWideKey(AThreadState ThreadState) { long CondVarAddress = (long)ThreadState.X0; int Count = (int)ThreadState.X1; HThread CurrThread = Process.GetThread(ThreadState.Tpidr); if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv)) { Cv.SetSignal(CurrThread, Count); } ThreadState.X0 = (int)SvcResult.Success; }
public bool TestExclusive(AThreadState ThreadState, long Position) { Position &= ~ErgMask; lock (Monitors) { if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) { return(false); } return(Monitor.HasExclusiveAccess(Position)); } }
private void SvcGetThreadPriority(AThreadState ThreadState) { int Handle = (int)ThreadState.X1; HThread Thread = Ns.Os.Handles.GetData <HThread>(Handle); if (Thread != null) { ThreadState.X1 = (ulong)Thread.Priority; ThreadState.X0 = (int)SvcResult.Success; } //TODO: Error codes. }
private void SvcWaitForAddress(AThreadState ThreadState) { long Address = (long)ThreadState.X0; ArbitrationType Type = (ArbitrationType)ThreadState.X1; int Value = (int)ThreadState.X2; ulong Timeout = ThreadState.X3; Ns.Log.PrintDebug(LogClass.KernelSvc, "Address = " + Address.ToString("x16") + ", " + "ArbitrationType = " + Type.ToString() + ", " + "Value = " + Value.ToString("x8") + ", " + "Timeout = " + Timeout.ToString("x16")); if (IsPointingInsideKernel(Address)) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } if (IsWordAddressUnaligned(Address)) { Ns.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } switch (Type) { case ArbitrationType.WaitIfLessThan: ThreadState.X0 = AddressArbiter.WaitForAddressIfLessThan(Process, ThreadState, Memory, Address, Value, Timeout, false); break; case ArbitrationType.DecrementAndWaitIfLessThan: ThreadState.X0 = AddressArbiter.WaitForAddressIfLessThan(Process, ThreadState, Memory, Address, Value, Timeout, true); break; case ArbitrationType.WaitIfEqual: ThreadState.X0 = AddressArbiter.WaitForAddressIfEqual(Process, ThreadState, Memory, Address, Value, Timeout); break; default: ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); break; } }
public void Frecps_V([Random(10)] float A, [Random(10)] float B) { AThreadState ThreadState = SingleOpcode(0x4E20FC44, V2: new AVec { S0 = A, S1 = A, S2 = A, S3 = A }, V0: new AVec { S0 = B, S1 = B, S2 = B, S3 = B }); Assert.That(ThreadState.V4.S0, Is.EqualTo(2 - (A * B))); Assert.That(ThreadState.V4.S1, Is.EqualTo(2 - (A * B))); Assert.That(ThreadState.V4.S2, Is.EqualTo(2 - (A * B))); Assert.That(ThreadState.V4.S3, Is.EqualTo(2 - (A * B))); }
public void Adds(uint A, bool Zero, bool Carry) { //ADDS WZR, WSP, #5 AThreadState ThreadState = SingleOpcode(0x310017FF, X31: A); Assert.Multiple(() => { Assert.IsFalse(ThreadState.Negative); Assert.IsFalse(ThreadState.Overflow); Assert.AreEqual(Zero, ThreadState.Zero); Assert.AreEqual(Carry, ThreadState.Carry); Assert.AreEqual(A, ThreadState.X31); }); }
public void Fmax_V(uint A, uint B, uint C, uint D, uint Result0, uint Result1) { uint Opcode = 0x4E22F420; Vector128 <float> V1 = MakeVectorE0E1(A, B); Vector128 <float> V2 = MakeVectorE0E1(C, D); AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); Assert.Multiple(() => { Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0)); Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0)); }); CompareAgainstUnicorn(); }
public void Adcs(uint Opcode, uint A, uint B, bool CarryState, bool Negative, bool Zero, bool Carry, uint Result) { //ADCS (X0/W0), (X1, W1), (X2/W2) AThreadState ThreadState = SingleOpcode(Opcode, X1: A, X2: B, Carry: CarryState); Assert.Multiple(() => { Assert.IsFalse(ThreadState.Overflow); Assert.AreEqual(Negative, ThreadState.Negative); Assert.AreEqual(Zero, ThreadState.Zero); Assert.AreEqual(Carry, ThreadState.Carry); Assert.AreEqual(Result, ThreadState.X0); }); }
public void Frintp_S(uint A, bool DefaultNaN, uint Result) { int FpcrTemp = 0x0; if (DefaultNaN) { FpcrTemp = 0x2000000; } Vector128 <float> V1 = MakeVectorE0(A); AThreadState ThreadState = SingleOpcode(0x1E24C020, V1: V1, Fpcr: FpcrTemp); Assert.AreEqual(Result, GetVectorE0(ThreadState.V0)); CompareAgainstUnicorn(); }
public void Trn2_V_4S([Random(2)] uint A0, [Random(2)] uint A1, [Random(2)] uint A2, [Random(2)] uint A3, [Random(2)] uint B0, [Random(2)] uint B1, [Random(2)] uint B2, [Random(2)] uint B3) { uint Opcode = 0x4E826820; Vector128 <float> V1 = Sse.StaticCast <uint, float>(Sse2.SetVector128(A3, A2, A1, A0)); Vector128 <float> V2 = Sse.StaticCast <uint, float>(Sse2.SetVector128(B3, B2, B1, B0)); AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V0), (byte)0), Is.EqualTo(A1)); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V0), (byte)1), Is.EqualTo(B1)); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V0), (byte)2), Is.EqualTo(A3)); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V0), (byte)3), Is.EqualTo(B3)); }
private void SvcGetThreadPriority(AThreadState ThreadState) { int Handle = (int)ThreadState.X1; KThread Thread = Process.HandleTable.GetData <KThread>(Handle); if (Thread != null) { ThreadState.X0 = 0; ThreadState.X1 = (ulong)Thread.Priority; } //TODO: Error codes. }
private void SvcUnmapPhysicalMemory(AThreadState ThreadState) { long Position = (long)ThreadState.X0; long Size = (long)ThreadState.X1; if (!PageAligned(Position)) { Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress); return; } if (!PageAligned(Size) || Size == 0) { Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize); return; } if ((ulong)(Position + Size) <= (ulong)Position) { Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } if (!InsideAddrSpace(Position, Size)) { Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return; } long Result = Process.MemoryManager.UnmapPhysicalMemory(Position, Size); if (Result != 0) { Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!"); } ThreadState.X0 = (ulong)Result; }
private void SvcGetInfo(AThreadState ThreadState) { long StackPtr = (long)ThreadState.X0; int InfoType = (int)ThreadState.X1; long Handle = (long)ThreadState.X2; int InfoId = (int)ThreadState.X3; //Fail for info not available on older Kernel versions. if (InfoType == 18 || InfoType == 19) { ThreadState.X0 = (int)SvcResult.ErrBadInfo; return; } switch (InfoType) { case 0: ThreadState.X1 = AllowedCpuIdBitmask(); break; case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break; case 3: ThreadState.X1 = GetMapRegionSize(); break; case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break; case 5: ThreadState.X1 = GetHeapRegionSize(); break; case 6: ThreadState.X1 = GetTotalMem(); break; case 7: ThreadState.X1 = GetUsedMem(); break; case 8: ThreadState.X1 = IsCurrentProcessBeingDebugged(); break; case 11: ThreadState.X1 = GetRnd64(); break; case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break; case 13: ThreadState.X1 = GetAddrSpaceSize(); break; case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break; case 15: ThreadState.X1 = GetMapRegionSize(); break; default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}"); } ThreadState.X0 = (int)SvcResult.Success; }
private void SvcStartThread(AThreadState ThreadState) { int Handle = (int)ThreadState.X0; HThread Thread = Ns.Os.Handles.GetData <HThread>(Handle); if (Thread != null) { Process.Scheduler.StartThread(Thread); ThreadState.X0 = (int)SvcResult.Success; } //TODO: Error codes. }
private void SvcSleepThread(AThreadState ThreadState) { ulong NanoSecs = ThreadState.X0; HThread CurrThread = Process.GetThread(ThreadState.Tpidr); if (NanoSecs == 0) { Process.Scheduler.Yield(CurrThread); } else { Process.Scheduler.WaitForSignal(CurrThread, (int)(NanoSecs / 1000000)); } }
[TestCase((ushort)0x0001, 0x33800000u)] // 5.96046448e-8 (Smallest Subnormal) public void Fcvtl_V_f16(ushort Value, uint Result) { uint Opcode = 0x0E217801; Vector128 <float> V0 = Sse.StaticCast <ushort, float>(Sse2.SetAllVector128(Value)); AThreadState ThreadState = SingleOpcode(Opcode, V0: V0); Assert.Multiple(() => { Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V1), (byte)0), Is.EqualTo(Result)); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V1), (byte)1), Is.EqualTo(Result)); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V1), (byte)2), Is.EqualTo(Result)); Assert.That(Sse41.Extract(Sse.StaticCast <float, uint>(ThreadState.V1), (byte)3), Is.EqualTo(Result)); }); }
public void Movz_64bit([Values(0u, 31u)] uint Rd, [Values(0u, 65535u)][Random(0u, 65535u, RndCntImm)] uint imm, [Values(0u, 16u, 32u, 48u)] uint shift) { uint Opcode = 0xD2800000; // MOVZ X0, #0, LSL #0 Opcode |= ((Rd & 31) << 0); Opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5); ulong _X31 = TestContext.CurrentContext.Random.NextULong(); AThreadState ThreadState = SingleOpcode(Opcode, X31: _X31); CompareAgainstUnicorn(); }
public void Frinta_S(uint A, bool DefaultNaN, uint Result) { int FpcrTemp = 0x0; if (DefaultNaN) { FpcrTemp = 0x2000000; } AVec V1 = new AVec { X0 = A }; AThreadState ThreadState = SingleOpcode(0x1E264020, V1: V1, Fpcr: FpcrTemp); Assert.AreEqual(Result, ThreadState.V0.X0); }
static ulong WaitForAddress(Process Process, AThreadState ThreadState, long Address, ulong Timeout) { //TODO: Update. KThread CurrentThread = Process.GetThread(ThreadState.Tpidr); CurrentThread.ArbiterWaitAddress = Address; CurrentThread.ArbiterSignaled = false; if (!CurrentThread.ArbiterSignaled) { return(MakeError(ErrorModule.Kernel, KernelErr.Timeout)); } return(0); }
private void SvcConnectToNamedPort(AThreadState ThreadState) { long StackPtr = (long)ThreadState.X0; long NamePtr = (long)ThreadState.X1; string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8); //TODO: Validate that app has perms to access the service, and that the service //actually exists, return error codes otherwise. HSession Session = new HSession(Name); ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session); ThreadState.X0 = (int)SvcResult.Success; }
private void SvcWaitSynchronization(AThreadState ThreadState) { long HandlesPtr = (long)ThreadState.X0; int HandlesCount = (int)ThreadState.X2; long Timeout = (long)ThreadState.X3; //TODO: Implement events. HThread CurrThread = Process.GetThread(ThreadState.Tpidr); Process.Scheduler.Suspend(CurrThread.ProcessorId); Process.Scheduler.Resume(CurrThread); ThreadState.X0 = (int)SvcResult.Success; }
private void SvcUnmapSharedMemory(AThreadState ThreadState) { int Handle = (int)ThreadState.X0; long Position = (long)ThreadState.X1; long Size = (long)ThreadState.X2; HSharedMem HndData = Ns.Os.Handles.GetData <HSharedMem>(Handle); if (HndData != null) { ThreadState.X0 = (int)SvcResult.Success; } //TODO: Error codes. }
public static ulong BinaryUnsignedSatQSub(ulong op1, ulong op2, AThreadState State) { ulong Sub = op1 - op2; if (op1 < op2) { SetFpsrQCFlag(State); return(ulong.MinValue); } else { return(Sub); } }
private void SvcStartThread(AThreadState ThreadState) { int Handle = (int)ThreadState.X0; KThread Thread = Process.HandleTable.GetData <KThread>(Handle); if (Thread != null) { Process.Scheduler.StartThread(Thread); ThreadState.X0 = 0; } //TODO: Error codes. }
public static ulong BinaryUnsignedSatQAdd(ulong op1, ulong op2, AThreadState State) { ulong Add = op1 + op2; if ((Add < op1) && (Add < op2)) { SetFpsrQCFlag(State); return(ulong.MaxValue); } else { return(Add); } }
private void SvcSignalProcessWideKey(AThreadState ThreadState) { long CondVarAddress = (long)ThreadState.X0; int Count = (int)ThreadState.X1; Ns.Log.PrintDebug(LogClass.KernelSvc, "CondVarAddress = " + CondVarAddress.ToString("x16") + ", " + "Count = " + Count.ToString("x8")); KThread CurrThread = Process.GetThread(ThreadState.Tpidr); CondVarSignal(CurrThread, CondVarAddress, Count); ThreadState.X0 = 0; }
public void Dup_Gp_X([Values(0u)] uint Rd, [Values(1u, 31u)] uint Rn, [ValueSource("_X_")][Random(RndCnt)] ulong Xn) { uint Opcode = 0x4E080C00; // DUP V0.2D, X0 Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0); ulong Z = TestContext.CurrentContext.Random.NextULong(); Vector128 <float> V0 = MakeVectorE0E1(Z, Z); AThreadState ThreadState = SingleOpcode(Opcode, X1: Xn, V0: V0); CompareAgainstUnicorn(); }
public void Rbit_64bit([Values(0u, 31u)] uint Rd, [Values(1u, 31u)] uint Rn, [Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul, 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)][Random(RndCnt)] ulong Xn) { uint Opcode = 0xDAC00000; // RBIT X0, X0 Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0); ulong _X31 = TestContext.CurrentContext.Random.NextULong(); AThreadState ThreadState = SingleOpcode(Opcode, X1: Xn, X31: _X31); CompareAgainstUnicorn(); }
public void Zip2_V(uint Q, uint size, ulong Result_0, ulong Result_1) { // ZIP2 V0.<T>, V1.<T>, V2.<T> uint Opcode = 0x0E027820 | (Q << 30) | (size << 22); AVec V1 = new AVec { X0 = 0x1716151413121110, X1 = 0x1F1E1D1C1B1A1918 }; AVec V2 = new AVec { X0 = 0x2726252423222120, X1 = 0x2F2E2D2C2B2A2928 }; AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); Assert.AreEqual(Result_0, ThreadState.V0.X0); Assert.AreEqual(Result_1, ThreadState.V0.X1); }
public void Clz_32bit([Values(0u, 31u)] uint Rd, [Values(1u, 31u)] uint Rn, [Values(0x00000000u, 0x7FFFFFFFu, 0x80000000u, 0xFFFFFFFFu)][Random(RndCnt)] uint Wn) { uint Opcode = 0x5AC01000; // CLZ W0, W0 Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0); uint _W31 = TestContext.CurrentContext.Random.NextUInt(); AThreadState ThreadState = SingleOpcode(Opcode, X1: Wn, X31: _W31); CompareAgainstUnicorn(); }