예제 #1
0
        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;
        }
예제 #2
0
        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;
        }
예제 #3
0
        public void Unlock()
        {
            lock (EnterWaitLock)
            {
                if (CurrRequestingThreadHandle != 0)
                {
                    Memory.WriteInt32(MutexAddress, CurrRequestingThreadHandle);
                }
                else
                {
                    Memory.WriteInt32(MutexAddress, 0);
                }

                CurrRequestingThreadHandle = 0;

                ThreadEvent.Set();
            }
        }
예제 #4
0
        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();
            }
        }
예제 #5
0
        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);
            }
        }
예제 #6
0
        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));
        }
예제 #7
0
        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);
        }
예제 #8
0
        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);
        }
예제 #9
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;
        }
예제 #10
0
        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;
        }
예제 #11
0
        public void WriteInt32(int Value)
        {
            Memory.WriteInt32(Position, Value);

            Position += 4;
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
                        });
                    }
                }
            }
        }
예제 #14
0
        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);
        }
예제 #15
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));
        }