private static void WriteConfigEntry( AMemory Memory, ref long Position, int Key, int Flags = 0, long Value0 = 0, long Value1 = 0) { Memory.WriteInt32(Position + 0x00, Key); Memory.WriteInt32(Position + 0x04, Flags); Memory.WriteInt64(Position + 0x08, Value0); Memory.WriteInt64(Position + 0x10, Value1); Position += 0x18; }
private static void SvcWaitProcessWideKeyAtomic(Switch Ns, ARegisters Registers, AMemory Memory) { long MutexAddress = (long)Registers.X0; long CondVarAddress = (long)Registers.X1; int ThreadHandle = (int)Registers.X2; long Timeout = (long)Registers.X3; AThread Thread = Ns.Os.Handles.GetData <HThread>(ThreadHandle).Thread; if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M)) { M.GiveUpLock(ThreadHandle); } CondVar Signal = new CondVar(Memory, CondVarAddress, Timeout); Signal = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Signal); Signal.WaitForSignal(ThreadHandle); M = new Mutex(Memory, MutexAddress); M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); //FIXME //M.WaitForLock(Thread, ThreadHandle); Memory.WriteInt32(MutexAddress, 0); Registers.X0 = (int)SvcResult.Success; }
public void Unlock() { lock (EnterWaitLock) { if (CurrRequestingThreadHandle != 0) { Memory.WriteInt32(MutexAddress, CurrRequestingThreadHandle); } else { Memory.WriteInt32(MutexAddress, 0); } CurrRequestingThreadHandle = 0; ThreadEvent.Set(); } }
public void WaitForSignal(int ThreadHandle) { int Count = Memory.ReadInt32(CondVarAddress); if (Count <= 0) { return; } Memory.WriteInt32(CondVarAddress, Count - 1); ManualResetEvent Event = new ManualResetEvent(false); WaitingThreads.Enqueue(new WaitingThread(ThreadHandle, Event)); if (Timeout != -1) { Event.WaitOne((int)(Timeout / 1000000)); } else { Event.WaitOne(); } }
private void CbData(AMemory Memory, NsGpuPBEntry PBEntry) { if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position)) { int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferNOffset); foreach (int Arg in PBEntry.Arguments) { Memory.WriteInt32(Position + Offset, Arg); Offset += 4; } WriteRegister(NvGpuEngine3dReg.ConstBufferNOffset, Offset); } }
public static ulong WaitForAddressIfLessThan(Process Process, AThreadState ThreadState, AMemory Memory, long Address, int Value, ulong Timeout, bool ShouldDecrement) { Memory.SetExclusive(ThreadState, Address); int CurrentValue = Memory.ReadInt32(Address); while (true) { if (Memory.TestExclusive(ThreadState, Address)) { if (CurrentValue < Value) { if (ShouldDecrement) { Memory.WriteInt32(Address, CurrentValue - 1); } Memory.ClearExclusiveForStore(ThreadState); } else { Memory.ClearExclusiveForStore(ThreadState); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); } break; } Memory.SetExclusive(ThreadState, Address); CurrentValue = Memory.ReadInt32(Address); } if (Timeout == 0) { return(MakeError(ErrorModule.Kernel, KernelErr.Timeout)); } return(WaitForAddress(Process, ThreadState, Address, Timeout)); }
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry) { if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position)) { int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence]; int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl]; int Mode = Ctrl & 3; if (Mode == 0) { //Write mode. Memory.WriteInt32(Position, Seq); } } WriteRegister(PBEntry); }
public long SignalAndIncrementIfEqual(AMemory Memory, long Address, int Value, int Count) { System.CriticalSectionLock.Lock(); Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int CurrentValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } while (CurrentValue == Value) { if (Memory.TestExclusive(0, Address)) { Memory.WriteInt32(Address, CurrentValue + 1); Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); CurrentValue = Memory.ReadInt32(Address); } Memory.ClearExclusive(0); if (CurrentValue != Value) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); } WakeArbiterThreads(Address, Count); System.CriticalSectionLock.Unlock(); return(0); }
private static void SvcArbitrateLock(Switch Ns, ARegisters Registers, AMemory Memory) { int OwnerThreadHandle = (int)Registers.X0; long MutexAddress = (long)Registers.X1; int RequestingThreadHandle = (int)Registers.X2; AThread RequestingThread = Ns.Os.Handles.GetData <HThread>(RequestingThreadHandle).Thread; Mutex M = new Mutex(Memory, MutexAddress); M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); //FIXME //M.WaitForLock(RequestingThread, RequestingThreadHandle); Memory.WriteInt32(MutexAddress, 0); Registers.X0 = (int)SvcResult.Success; }
private static void SvcQueryMemory(Switch Ns, ARegisters Registers, AMemory Memory) { long InfoPtr = (long)Registers.X0; long Position = (long)Registers.X2; AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); MemoryInfo Info = new MemoryInfo(MapInfo); Memory.WriteInt64(InfoPtr + 0x00, Info.BaseAddress); Memory.WriteInt64(InfoPtr + 0x08, Info.Size); Memory.WriteInt32(InfoPtr + 0x10, Info.MemType); Memory.WriteInt32(InfoPtr + 0x14, Info.MemAttr); Memory.WriteInt32(InfoPtr + 0x18, Info.MemPerm); Memory.WriteInt32(InfoPtr + 0x1c, Info.IpcRefCount); Memory.WriteInt32(InfoPtr + 0x20, Info.DeviceRefCount); Memory.WriteInt32(InfoPtr + 0x24, Info.Padding); //TODO: X1. Registers.X0 = (int)SvcResult.Success; Registers.X1 = 0; }
public void WriteInt32(int Value) { Memory.WriteInt32(Position, Value); Position += 4; }
private KThread TryAcquireMutex(Process Process, AMemory Memory, KThread Requester) { int Core = Requester.CurrentCore; long Address = Requester.MutexAddress; Memory.SetExclusive(Core, Address); int MutexValue = Memory.ReadInt32(Address); while (MutexValue != 0) { if (Memory.TestExclusive(Core, Address)) { if (MutexValue != 0) { //Update value to indicate there is a mutex waiter now. Memory.WriteInt32(Address, MutexValue | HasListenersMask); } else { //No thread owning the mutex, assign to requesting thread. Memory.WriteInt32(Address, Requester.ThreadHandleForUserMutex); } Memory.ClearExclusiveForStore(Core); break; } Memory.SetExclusive(Core, Address); MutexValue = Memory.ReadInt32(Address); } if (MutexValue == 0) { //We now own the mutex. Requester.SignaledObj = null; Requester.ObjSyncResult = 0; Requester.ReleaseAndResume(); return(null); } MutexValue &= ~HasListenersMask; KThread MutexOwner = Process.HandleTable.GetData <KThread>(MutexValue); if (MutexOwner != null) { //Mutex already belongs to another thread, wait for it. MutexOwner.AddMutexWaiter(Requester); } else { //Invalid mutex owner. Requester.SignaledObj = null; Requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); Requester.ReleaseAndResume(); } return(MutexOwner); }
public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory) { bool HasQuery = false; foreach (NsGpuPBEntry Entry in PushBuffer) { if (Entry.Arguments.Count == 1) { SetRegister(Entry.Register, Entry.Arguments[0]); } switch (Entry.Register) { case NsGpuRegister.BindChannel: if (Entry.Arguments.Count > 0) { SubChannels[Entry.SubChannel] = (NsGpuEngine)Entry.Arguments[0]; } break; case NsGpuRegister._3dVertexArray0Fetch: SendVertexBuffers(Memory); break; case NsGpuRegister._3dCbData0: if (GetRegister(NsGpuRegister._3dCbPos) == 0x20) { SendTexture(Memory); } break; case NsGpuRegister._3dQueryAddressHigh: case NsGpuRegister._3dQueryAddressLow: case NsGpuRegister._3dQuerySequence: case NsGpuRegister._3dQueryGet: HasQuery = true; break; } } if (HasQuery) { long Position = (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 | (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0; int Seq = GetRegister(NsGpuRegister._3dQuerySequence); int Get = GetRegister(NsGpuRegister._3dQueryGet); int Mode = Get & 3; if (Mode == 0) { //Write Position = Gpu.MemoryMgr.GetCpuAddr(Position); if (Position != -1) { Gpu.Renderer.QueueAction(delegate() { Memory.WriteInt32(Position, Seq); }); } } } }
public long SignalAndModifyIfEqual(AMemory Memory, long Address, int Value, int Count) { System.CriticalSectionLock.Lock(); int Offset; //The value is decremented if the number of threads waiting is less //or equal to the Count of threads to be signaled, or Count is zero //or negative. It is incremented if there are no threads waiting. int WaitingCount = 0; foreach (KThread Thread in ArbiterThreads.Where(x => x.MutexAddress == Address)) { if (++WaitingCount > Count) { break; } } if (WaitingCount > 0) { Offset = WaitingCount <= Count || Count <= 0 ? -1 : 0; } else { Offset = 1; } Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int CurrentValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } while (CurrentValue == Value) { if (Memory.TestExclusive(0, Address)) { Memory.WriteInt32(Address, CurrentValue + Offset); Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); CurrentValue = Memory.ReadInt32(Address); } Memory.ClearExclusive(0); if (CurrentValue != Value) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); } WakeArbiterThreads(Address, Count); System.CriticalSectionLock.Unlock(); return(0); }
public long WaitForAddressIfLessThan( AMemory Memory, long Address, int Value, bool ShouldDecrement, long Timeout) { KThread CurrentThread = System.Scheduler.GetCurrentThread(); System.CriticalSectionLock.Lock(); if (CurrentThread.ShallBeTerminated || CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating)); } CurrentThread.SignaledObj = null; CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); //If ShouldDecrement is true, do atomic decrement of the value at Address. Memory.SetExclusive(0, Address); if (!UserToKernelInt32(Memory, Address, out int CurrentValue)) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm)); } if (ShouldDecrement) { while (CurrentValue < Value) { if (Memory.TestExclusive(0, Address)) { Memory.WriteInt32(Address, CurrentValue - 1); Memory.ClearExclusiveForStore(0); break; } Memory.SetExclusive(0, Address); CurrentValue = Memory.ReadInt32(Address); } } Memory.ClearExclusive(0); if (CurrentValue < Value) { if (Timeout == 0) { System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.Timeout)); } CurrentThread.MutexAddress = Address; CurrentThread.WaitingInArbitration = true; InsertSortedByPriority(ArbiterThreads, CurrentThread); CurrentThread.Reschedule(ThreadSchedState.Paused); if (Timeout > 0) { System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); } System.CriticalSectionLock.Unlock(); if (Timeout > 0) { System.TimeManager.UnscheduleFutureInvocation(CurrentThread); } System.CriticalSectionLock.Lock(); if (CurrentThread.WaitingInArbitration) { ArbiterThreads.Remove(CurrentThread); CurrentThread.WaitingInArbitration = false; } System.CriticalSectionLock.Unlock(); return(CurrentThread.ObjSyncResult); } System.CriticalSectionLock.Unlock(); return(MakeError(ErrorModule.Kernel, KernelErr.InvalidState)); }