Adjust naming conventions and general refactoring in HLE Project (#490)
* Rename enum fields
* Naming conventions
* Remove unneeded ".this"
* Remove unneeded semicolons
* Remove unused Usings
* Don't use var
* Remove unneeded enum underlying types
* Explicitly label class visibility
* Remove unneeded @ prefixes
* Remove unneeded commas
* Remove unneeded if expressions
* Method doesn't use unsafe code
* Remove unneeded casts
* Initialized objects don't need an empty constructor
* Remove settings from DotSettings
* Revert "Explicitly label class visibility"
This reverts commit ad5eb5787c
.
* Small changes
* Revert external enum renaming
* Changes from feedback
* Remove unneeded property setters
This commit is contained in:
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private class PausableThread
|
||||
{
|
||||
public ManualResetEvent Event { get; private set; }
|
||||
public ManualResetEvent Event { get; }
|
||||
|
||||
public bool IsExiting { get; set; }
|
||||
|
||||
@ -17,49 +17,49 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<Thread, PausableThread> Threads;
|
||||
private ConcurrentDictionary<Thread, PausableThread> _threads;
|
||||
|
||||
public HleCoreManager()
|
||||
{
|
||||
Threads = new ConcurrentDictionary<Thread, PausableThread>();
|
||||
_threads = new ConcurrentDictionary<Thread, PausableThread>();
|
||||
}
|
||||
|
||||
public void Set(Thread Thread)
|
||||
public void Set(Thread thread)
|
||||
{
|
||||
GetThread(Thread).Event.Set();
|
||||
GetThread(thread).Event.Set();
|
||||
}
|
||||
|
||||
public void Reset(Thread Thread)
|
||||
public void Reset(Thread thread)
|
||||
{
|
||||
GetThread(Thread).Event.Reset();
|
||||
GetThread(thread).Event.Reset();
|
||||
}
|
||||
|
||||
public void Wait(Thread Thread)
|
||||
public void Wait(Thread thread)
|
||||
{
|
||||
PausableThread PausableThread = GetThread(Thread);
|
||||
PausableThread pausableThread = GetThread(thread);
|
||||
|
||||
if (!PausableThread.IsExiting)
|
||||
if (!pausableThread.IsExiting)
|
||||
{
|
||||
PausableThread.Event.WaitOne();
|
||||
pausableThread.Event.WaitOne();
|
||||
}
|
||||
}
|
||||
|
||||
public void Exit(Thread Thread)
|
||||
public void Exit(Thread thread)
|
||||
{
|
||||
GetThread(Thread).IsExiting = true;
|
||||
GetThread(thread).IsExiting = true;
|
||||
}
|
||||
|
||||
private PausableThread GetThread(Thread Thread)
|
||||
private PausableThread GetThread(Thread thread)
|
||||
{
|
||||
return Threads.GetOrAdd(Thread, (Key) => new PausableThread());
|
||||
return _threads.GetOrAdd(thread, (key) => new PausableThread());
|
||||
}
|
||||
|
||||
public void RemoveThread(Thread Thread)
|
||||
public void RemoveThread(Thread thread)
|
||||
{
|
||||
if (Threads.TryRemove(Thread, out PausableThread PausableThread))
|
||||
if (_threads.TryRemove(thread, out PausableThread pausableThread))
|
||||
{
|
||||
PausableThread.Event.Set();
|
||||
PausableThread.Event.Dispose();
|
||||
pausableThread.Event.Set();
|
||||
pausableThread.Event.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,138 +14,138 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private const int Mod0 = 'M' << 0 | 'O' << 8 | 'D' << 16 | '0' << 24;
|
||||
|
||||
private KProcess Owner;
|
||||
private KProcess _owner;
|
||||
|
||||
private class Image
|
||||
{
|
||||
public long BaseAddress { get; private set; }
|
||||
public long BaseAddress { get; }
|
||||
|
||||
public ElfSymbol[] Symbols { get; private set; }
|
||||
public ElfSymbol[] Symbols { get; }
|
||||
|
||||
public Image(long BaseAddress, ElfSymbol[] Symbols)
|
||||
public Image(long baseAddress, ElfSymbol[] symbols)
|
||||
{
|
||||
this.BaseAddress = BaseAddress;
|
||||
this.Symbols = Symbols;
|
||||
BaseAddress = baseAddress;
|
||||
Symbols = symbols;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Image> Images;
|
||||
private List<Image> _images;
|
||||
|
||||
private int Loaded;
|
||||
private int _loaded;
|
||||
|
||||
public HleProcessDebugger(KProcess Owner)
|
||||
public HleProcessDebugger(KProcess owner)
|
||||
{
|
||||
this.Owner = Owner;
|
||||
_owner = owner;
|
||||
|
||||
Images = new List<Image>();
|
||||
_images = new List<Image>();
|
||||
}
|
||||
|
||||
public void PrintGuestStackTrace(CpuThreadState ThreadState)
|
||||
public void PrintGuestStackTrace(CpuThreadState threadState)
|
||||
{
|
||||
EnsureLoaded();
|
||||
|
||||
StringBuilder Trace = new StringBuilder();
|
||||
StringBuilder trace = new StringBuilder();
|
||||
|
||||
Trace.AppendLine("Guest stack trace:");
|
||||
trace.AppendLine("Guest stack trace:");
|
||||
|
||||
void AppendTrace(long Address)
|
||||
void AppendTrace(long address)
|
||||
{
|
||||
Image Image = GetImage(Address, out int ImageIndex);
|
||||
Image image = GetImage(address, out int imageIndex);
|
||||
|
||||
if (Image == null || !TryGetSubName(Image, Address, out string SubName))
|
||||
if (image == null || !TryGetSubName(image, address, out string subName))
|
||||
{
|
||||
SubName = $"Sub{Address:x16}";
|
||||
subName = $"Sub{address:x16}";
|
||||
}
|
||||
else if (SubName.StartsWith("_Z"))
|
||||
else if (subName.StartsWith("_Z"))
|
||||
{
|
||||
SubName = Demangler.Parse(SubName);
|
||||
subName = Demangler.Parse(subName);
|
||||
}
|
||||
|
||||
if (Image != null)
|
||||
if (image != null)
|
||||
{
|
||||
long Offset = Address - Image.BaseAddress;
|
||||
long offset = address - image.BaseAddress;
|
||||
|
||||
string ImageName = GetGuessedNsoNameFromIndex(ImageIndex);
|
||||
string imageName = GetGuessedNsoNameFromIndex(imageIndex);
|
||||
|
||||
string ImageNameAndOffset = $"[{Owner.Name}] {ImageName}:0x{Offset:x8}";
|
||||
string imageNameAndOffset = $"[{_owner.Name}] {imageName}:0x{offset:x8}";
|
||||
|
||||
Trace.AppendLine($" {ImageNameAndOffset} {SubName}");
|
||||
trace.AppendLine($" {imageNameAndOffset} {subName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.AppendLine($" [{Owner.Name}] ??? {SubName}");
|
||||
trace.AppendLine($" [{_owner.Name}] ??? {subName}");
|
||||
}
|
||||
}
|
||||
|
||||
long FramePointer = (long)ThreadState.X29;
|
||||
long framePointer = (long)threadState.X29;
|
||||
|
||||
while (FramePointer != 0)
|
||||
while (framePointer != 0)
|
||||
{
|
||||
if ((FramePointer & 7) != 0 ||
|
||||
!Owner.CpuMemory.IsMapped(FramePointer) ||
|
||||
!Owner.CpuMemory.IsMapped(FramePointer + 8))
|
||||
if ((framePointer & 7) != 0 ||
|
||||
!_owner.CpuMemory.IsMapped(framePointer) ||
|
||||
!_owner.CpuMemory.IsMapped(framePointer + 8))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//Note: This is the return address, we need to subtract one instruction
|
||||
//worth of bytes to get the branch instruction address.
|
||||
AppendTrace(Owner.CpuMemory.ReadInt64(FramePointer + 8) - 4);
|
||||
AppendTrace(_owner.CpuMemory.ReadInt64(framePointer + 8) - 4);
|
||||
|
||||
FramePointer = Owner.CpuMemory.ReadInt64(FramePointer);
|
||||
framePointer = _owner.CpuMemory.ReadInt64(framePointer);
|
||||
}
|
||||
|
||||
Logger.PrintInfo(LogClass.Cpu, Trace.ToString());
|
||||
Logger.PrintInfo(LogClass.Cpu, trace.ToString());
|
||||
}
|
||||
|
||||
private bool TryGetSubName(Image Image, long Address, out string Name)
|
||||
private bool TryGetSubName(Image image, long address, out string name)
|
||||
{
|
||||
Address -= Image.BaseAddress;
|
||||
address -= image.BaseAddress;
|
||||
|
||||
int Left = 0;
|
||||
int Right = Image.Symbols.Length - 1;
|
||||
int left = 0;
|
||||
int right = image.Symbols.Length - 1;
|
||||
|
||||
while (Left <= Right)
|
||||
while (left <= right)
|
||||
{
|
||||
int Size = Right - Left;
|
||||
int size = right - left;
|
||||
|
||||
int Middle = Left + (Size >> 1);
|
||||
int middle = left + (size >> 1);
|
||||
|
||||
ElfSymbol Symbol = Image.Symbols[Middle];
|
||||
ElfSymbol symbol = image.Symbols[middle];
|
||||
|
||||
long EndAddr = Symbol.Value + Symbol.Size;
|
||||
long endAddr = symbol.Value + symbol.Size;
|
||||
|
||||
if ((ulong)Address >= (ulong)Symbol.Value && (ulong)Address < (ulong)EndAddr)
|
||||
if ((ulong)address >= (ulong)symbol.Value && (ulong)address < (ulong)endAddr)
|
||||
{
|
||||
Name = Symbol.Name;
|
||||
name = symbol.Name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((ulong)Address < (ulong)Symbol.Value)
|
||||
if ((ulong)address < (ulong)symbol.Value)
|
||||
{
|
||||
Right = Middle - 1;
|
||||
right = middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Left = Middle + 1;
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
Name = null;
|
||||
name = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Image GetImage(long Address, out int Index)
|
||||
private Image GetImage(long address, out int index)
|
||||
{
|
||||
lock (Images)
|
||||
lock (_images)
|
||||
{
|
||||
for (Index = Images.Count - 1; Index >= 0; Index--)
|
||||
for (index = _images.Count - 1; index >= 0; index--)
|
||||
{
|
||||
if ((ulong)Address >= (ulong)Images[Index].BaseAddress)
|
||||
if ((ulong)address >= (ulong)_images[index].BaseAddress)
|
||||
{
|
||||
return Images[Index];
|
||||
return _images[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -153,42 +153,42 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetGuessedNsoNameFromIndex(int Index)
|
||||
private string GetGuessedNsoNameFromIndex(int index)
|
||||
{
|
||||
if ((uint)Index > 11)
|
||||
if ((uint)index > 11)
|
||||
{
|
||||
return "???";
|
||||
}
|
||||
|
||||
if (Index == 0)
|
||||
if (index == 0)
|
||||
{
|
||||
return "rtld";
|
||||
}
|
||||
else if (Index == 1)
|
||||
else if (index == 1)
|
||||
{
|
||||
return "main";
|
||||
}
|
||||
else if (Index == GetImagesCount() - 1)
|
||||
else if (index == GetImagesCount() - 1)
|
||||
{
|
||||
return "sdk";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "subsdk" + (Index - 2);
|
||||
return "subsdk" + (index - 2);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetImagesCount()
|
||||
{
|
||||
lock (Images)
|
||||
lock (_images)
|
||||
{
|
||||
return Images.Count;
|
||||
return _images.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureLoaded()
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref Loaded, 1, 0) == 0)
|
||||
if (Interlocked.CompareExchange(ref _loaded, 1, 0) == 0)
|
||||
{
|
||||
ScanMemoryForTextSegments();
|
||||
}
|
||||
@ -196,115 +196,115 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
private void ScanMemoryForTextSegments()
|
||||
{
|
||||
ulong OldAddress = 0;
|
||||
ulong Address = 0;
|
||||
ulong oldAddress = 0;
|
||||
ulong address = 0;
|
||||
|
||||
while (Address >= OldAddress)
|
||||
while (address >= oldAddress)
|
||||
{
|
||||
KMemoryInfo Info = Owner.MemoryManager.QueryMemory(Address);
|
||||
KMemoryInfo info = _owner.MemoryManager.QueryMemory(address);
|
||||
|
||||
if (Info.State == MemoryState.Reserved)
|
||||
if (info.State == MemoryState.Reserved)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Info.State == MemoryState.CodeStatic && Info.Permission == MemoryPermission.ReadAndExecute)
|
||||
if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute)
|
||||
{
|
||||
LoadMod0Symbols(Owner.CpuMemory, (long)Info.Address);
|
||||
LoadMod0Symbols(_owner.CpuMemory, (long)info.Address);
|
||||
}
|
||||
|
||||
OldAddress = Address;
|
||||
oldAddress = address;
|
||||
|
||||
Address = Info.Address + Info.Size;
|
||||
address = info.Address + info.Size;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadMod0Symbols(MemoryManager Memory, long TextOffset)
|
||||
private void LoadMod0Symbols(MemoryManager memory, long textOffset)
|
||||
{
|
||||
long Mod0Offset = TextOffset + Memory.ReadUInt32(TextOffset + 4);
|
||||
long mod0Offset = textOffset + memory.ReadUInt32(textOffset + 4);
|
||||
|
||||
if (Mod0Offset < TextOffset || !Memory.IsMapped(Mod0Offset) || (Mod0Offset & 3) != 0)
|
||||
if (mod0Offset < textOffset || !memory.IsMapped(mod0Offset) || (mod0Offset & 3) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<ElfDynamicTag, long> Dynamic = new Dictionary<ElfDynamicTag, long>();
|
||||
Dictionary<ElfDynamicTag, long> dynamic = new Dictionary<ElfDynamicTag, long>();
|
||||
|
||||
int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0);
|
||||
int mod0Magic = memory.ReadInt32(mod0Offset + 0x0);
|
||||
|
||||
if (Mod0Magic != Mod0)
|
||||
if (mod0Magic != Mod0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset;
|
||||
long BssStartOffset = Memory.ReadInt32(Mod0Offset + 0x8) + Mod0Offset;
|
||||
long BssEndOffset = Memory.ReadInt32(Mod0Offset + 0xc) + Mod0Offset;
|
||||
long EhHdrStartOffset = Memory.ReadInt32(Mod0Offset + 0x10) + Mod0Offset;
|
||||
long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset;
|
||||
long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset;
|
||||
long dynamicOffset = memory.ReadInt32(mod0Offset + 0x4) + mod0Offset;
|
||||
long bssStartOffset = memory.ReadInt32(mod0Offset + 0x8) + mod0Offset;
|
||||
long bssEndOffset = memory.ReadInt32(mod0Offset + 0xc) + mod0Offset;
|
||||
long ehHdrStartOffset = memory.ReadInt32(mod0Offset + 0x10) + mod0Offset;
|
||||
long ehHdrEndOffset = memory.ReadInt32(mod0Offset + 0x14) + mod0Offset;
|
||||
long modObjOffset = memory.ReadInt32(mod0Offset + 0x18) + mod0Offset;
|
||||
|
||||
while (true)
|
||||
{
|
||||
long TagVal = Memory.ReadInt64(DynamicOffset + 0);
|
||||
long Value = Memory.ReadInt64(DynamicOffset + 8);
|
||||
long tagVal = memory.ReadInt64(dynamicOffset + 0);
|
||||
long value = memory.ReadInt64(dynamicOffset + 8);
|
||||
|
||||
DynamicOffset += 0x10;
|
||||
dynamicOffset += 0x10;
|
||||
|
||||
ElfDynamicTag Tag = (ElfDynamicTag)TagVal;
|
||||
ElfDynamicTag tag = (ElfDynamicTag)tagVal;
|
||||
|
||||
if (Tag == ElfDynamicTag.DT_NULL)
|
||||
if (tag == ElfDynamicTag.DT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Dynamic[Tag] = Value;
|
||||
dynamic[tag] = value;
|
||||
}
|
||||
|
||||
if (!Dynamic.TryGetValue(ElfDynamicTag.DT_STRTAB, out long StrTab) ||
|
||||
!Dynamic.TryGetValue(ElfDynamicTag.DT_SYMTAB, out long SymTab) ||
|
||||
!Dynamic.TryGetValue(ElfDynamicTag.DT_SYMENT, out long SymEntSize))
|
||||
if (!dynamic.TryGetValue(ElfDynamicTag.DT_STRTAB, out long strTab) ||
|
||||
!dynamic.TryGetValue(ElfDynamicTag.DT_SYMTAB, out long symTab) ||
|
||||
!dynamic.TryGetValue(ElfDynamicTag.DT_SYMENT, out long symEntSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long StrTblAddr = TextOffset + StrTab;
|
||||
long SymTblAddr = TextOffset + SymTab;
|
||||
long strTblAddr = textOffset + strTab;
|
||||
long symTblAddr = textOffset + symTab;
|
||||
|
||||
List<ElfSymbol> Symbols = new List<ElfSymbol>();
|
||||
List<ElfSymbol> symbols = new List<ElfSymbol>();
|
||||
|
||||
while ((ulong)SymTblAddr < (ulong)StrTblAddr)
|
||||
while ((ulong)symTblAddr < (ulong)strTblAddr)
|
||||
{
|
||||
ElfSymbol Sym = GetSymbol(Memory, SymTblAddr, StrTblAddr);
|
||||
ElfSymbol sym = GetSymbol(memory, symTblAddr, strTblAddr);
|
||||
|
||||
Symbols.Add(Sym);
|
||||
symbols.Add(sym);
|
||||
|
||||
SymTblAddr += SymEntSize;
|
||||
symTblAddr += symEntSize;
|
||||
}
|
||||
|
||||
lock (Images)
|
||||
lock (_images)
|
||||
{
|
||||
Images.Add(new Image(TextOffset, Symbols.OrderBy(x => x.Value).ToArray()));
|
||||
_images.Add(new Image(textOffset, symbols.OrderBy(x => x.Value).ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
private ElfSymbol GetSymbol(MemoryManager Memory, long Address, long StrTblAddr)
|
||||
private ElfSymbol GetSymbol(MemoryManager memory, long address, long strTblAddr)
|
||||
{
|
||||
int NameIndex = Memory.ReadInt32(Address + 0);
|
||||
int Info = Memory.ReadByte (Address + 4);
|
||||
int Other = Memory.ReadByte (Address + 5);
|
||||
int SHIdx = Memory.ReadInt16(Address + 6);
|
||||
long Value = Memory.ReadInt64(Address + 8);
|
||||
long Size = Memory.ReadInt64(Address + 16);
|
||||
int nameIndex = memory.ReadInt32(address + 0);
|
||||
int info = memory.ReadByte (address + 4);
|
||||
int other = memory.ReadByte (address + 5);
|
||||
int shIdx = memory.ReadInt16(address + 6);
|
||||
long value = memory.ReadInt64(address + 8);
|
||||
long size = memory.ReadInt64(address + 16);
|
||||
|
||||
string Name = string.Empty;
|
||||
string name = string.Empty;
|
||||
|
||||
for (int Chr; (Chr = Memory.ReadByte(StrTblAddr + NameIndex++)) != 0;)
|
||||
for (int chr; (chr = memory.ReadByte(strTblAddr + nameIndex++)) != 0;)
|
||||
{
|
||||
Name += (char)Chr;
|
||||
name += (char)chr;
|
||||
}
|
||||
|
||||
return new ElfSymbol(Name, Info, Other, SHIdx, Value, Size);
|
||||
return new ElfSymbol(name, info, other, shIdx, value, size);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,21 +7,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private const int RoundRobinTimeQuantumMs = 10;
|
||||
|
||||
private int CurrentCore;
|
||||
private int _currentCore;
|
||||
|
||||
public bool MultiCoreScheduling { get; set; }
|
||||
|
||||
public HleCoreManager CoreManager { get; private set; }
|
||||
public HleCoreManager CoreManager { get; }
|
||||
|
||||
private bool KeepPreempting;
|
||||
private bool _keepPreempting;
|
||||
|
||||
public void StartAutoPreemptionThread()
|
||||
{
|
||||
Thread PreemptionThread = new Thread(PreemptCurrentThread);
|
||||
Thread preemptionThread = new Thread(PreemptCurrentThread);
|
||||
|
||||
KeepPreempting = true;
|
||||
_keepPreempting = true;
|
||||
|
||||
PreemptionThread.Start();
|
||||
preemptionThread.Start();
|
||||
}
|
||||
|
||||
public void ContextSwitch()
|
||||
@ -30,28 +30,28 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
if (MultiCoreScheduling)
|
||||
{
|
||||
int SelectedCount = 0;
|
||||
int selectedCount = 0;
|
||||
|
||||
for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
KCoreContext CoreContext = CoreContexts[Core];
|
||||
KCoreContext coreContext = CoreContexts[core];
|
||||
|
||||
if (CoreContext.ContextSwitchNeeded && (CoreContext.CurrentThread?.Context.IsCurrentThread() ?? false))
|
||||
if (coreContext.ContextSwitchNeeded && (coreContext.CurrentThread?.Context.IsCurrentThread() ?? false))
|
||||
{
|
||||
CoreContext.ContextSwitch();
|
||||
coreContext.ContextSwitch();
|
||||
}
|
||||
|
||||
if (CoreContext.CurrentThread?.Context.IsCurrentThread() ?? false)
|
||||
if (coreContext.CurrentThread?.Context.IsCurrentThread() ?? false)
|
||||
{
|
||||
SelectedCount++;
|
||||
selectedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectedCount == 0)
|
||||
if (selectedCount == 0)
|
||||
{
|
||||
CoreManager.Reset(Thread.CurrentThread);
|
||||
}
|
||||
else if (SelectedCount == 1)
|
||||
else if (selectedCount == 1)
|
||||
{
|
||||
CoreManager.Set(Thread.CurrentThread);
|
||||
}
|
||||
@ -62,41 +62,41 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
}
|
||||
else
|
||||
{
|
||||
KThread CurrentThread = CoreContexts[CurrentCore].CurrentThread;
|
||||
KThread currentThread = CoreContexts[_currentCore].CurrentThread;
|
||||
|
||||
bool HasThreadExecuting = CurrentThread != null;
|
||||
bool hasThreadExecuting = currentThread != null;
|
||||
|
||||
if (HasThreadExecuting)
|
||||
if (hasThreadExecuting)
|
||||
{
|
||||
//If this is not the thread that is currently executing, we need
|
||||
//to request an interrupt to allow safely starting another thread.
|
||||
if (!CurrentThread.Context.IsCurrentThread())
|
||||
if (!currentThread.Context.IsCurrentThread())
|
||||
{
|
||||
CurrentThread.Context.RequestInterrupt();
|
||||
currentThread.Context.RequestInterrupt();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CoreManager.Reset(CurrentThread.Context.Work);
|
||||
CoreManager.Reset(currentThread.Context.Work);
|
||||
}
|
||||
|
||||
//Advance current core and try picking a thread,
|
||||
//keep advancing if it is null.
|
||||
for (int Core = 0; Core < 4; Core++)
|
||||
for (int core = 0; core < 4; core++)
|
||||
{
|
||||
CurrentCore = (CurrentCore + 1) % CpuCoresCount;
|
||||
_currentCore = (_currentCore + 1) % CpuCoresCount;
|
||||
|
||||
KCoreContext CoreContext = CoreContexts[CurrentCore];
|
||||
KCoreContext coreContext = CoreContexts[_currentCore];
|
||||
|
||||
CoreContext.UpdateCurrentThread();
|
||||
coreContext.UpdateCurrentThread();
|
||||
|
||||
if (CoreContext.CurrentThread != null)
|
||||
if (coreContext.CurrentThread != null)
|
||||
{
|
||||
CoreContext.CurrentThread.ClearExclusive();
|
||||
coreContext.CurrentThread.ClearExclusive();
|
||||
|
||||
CoreManager.Set(CoreContext.CurrentThread.Context.Work);
|
||||
CoreManager.Set(coreContext.CurrentThread.Context.Work);
|
||||
|
||||
CoreContext.CurrentThread.Context.Execute();
|
||||
coreContext.CurrentThread.Context.Execute();
|
||||
|
||||
break;
|
||||
}
|
||||
@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
//If nothing was running before, then we are on a "external"
|
||||
//HLE thread, we don't need to wait.
|
||||
if (!HasThreadExecuting)
|
||||
if (!hasThreadExecuting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -119,13 +119,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
//Preempts current thread every 10 milliseconds on a round-robin fashion,
|
||||
//when multi core scheduling is disabled, to try ensuring that all threads
|
||||
//gets a chance to run.
|
||||
while (KeepPreempting)
|
||||
while (_keepPreempting)
|
||||
{
|
||||
lock (CoreContexts)
|
||||
{
|
||||
KThread CurrentThread = CoreContexts[CurrentCore].CurrentThread;
|
||||
KThread currentThread = CoreContexts[_currentCore].CurrentThread;
|
||||
|
||||
CurrentThread?.Context.RequestInterrupt();
|
||||
currentThread?.Context.RequestInterrupt();
|
||||
}
|
||||
|
||||
PreemptThreads();
|
||||
@ -134,16 +134,16 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
}
|
||||
}
|
||||
|
||||
public void ExitThread(KThread Thread)
|
||||
public void ExitThread(KThread thread)
|
||||
{
|
||||
Thread.Context.StopExecution();
|
||||
thread.Context.StopExecution();
|
||||
|
||||
CoreManager.Exit(Thread.Context.Work);
|
||||
CoreManager.Exit(thread.Context.Work);
|
||||
}
|
||||
|
||||
public void RemoveThread(KThread Thread)
|
||||
public void RemoveThread(KThread thread)
|
||||
{
|
||||
CoreManager.RemoveThread(Thread.Context.Work);
|
||||
CoreManager.RemoveThread(thread.Context.Work);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,641 +9,641 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private const int HasListenersMask = 0x40000000;
|
||||
|
||||
private Horizon System;
|
||||
private Horizon _system;
|
||||
|
||||
public List<KThread> CondVarThreads;
|
||||
public List<KThread> ArbiterThreads;
|
||||
|
||||
public KAddressArbiter(Horizon System)
|
||||
public KAddressArbiter(Horizon system)
|
||||
{
|
||||
this.System = System;
|
||||
_system = system;
|
||||
|
||||
CondVarThreads = new List<KThread>();
|
||||
ArbiterThreads = new List<KThread>();
|
||||
}
|
||||
|
||||
public long ArbitrateLock(int OwnerHandle, long MutexAddress, int RequesterHandle)
|
||||
public long ArbitrateLock(int ownerHandle, long mutexAddress, int requesterHandle)
|
||||
{
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
CurrentThread.SignaledObj = null;
|
||||
CurrentThread.ObjSyncResult = 0;
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = 0;
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32(System, MutexAddress, out int MutexValue))
|
||||
if (!KernelTransfer.UserToKernelInt32(_system, mutexAddress, out int mutexValue))
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);;
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
if (MutexValue != (OwnerHandle | HasListenersMask))
|
||||
if (mutexValue != (ownerHandle | HasListenersMask))
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
KThread MutexOwner = CurrentProcess.HandleTable.GetObject<KThread>(OwnerHandle);
|
||||
KThread mutexOwner = currentProcess.HandleTable.GetObject<KThread>(ownerHandle);
|
||||
|
||||
if (MutexOwner == null)
|
||||
if (mutexOwner == null)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
||||
CurrentThread.MutexAddress = MutexAddress;
|
||||
CurrentThread.ThreadHandleForUserMutex = RequesterHandle;
|
||||
currentThread.MutexAddress = mutexAddress;
|
||||
currentThread.ThreadHandleForUserMutex = requesterHandle;
|
||||
|
||||
MutexOwner.AddMutexWaiter(CurrentThread);
|
||||
mutexOwner.AddMutexWaiter(currentThread);
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Leave();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (CurrentThread.MutexOwner != null)
|
||||
if (currentThread.MutexOwner != null)
|
||||
{
|
||||
CurrentThread.MutexOwner.RemoveMutexWaiter(CurrentThread);
|
||||
currentThread.MutexOwner.RemoveMutexWaiter(currentThread);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return (uint)CurrentThread.ObjSyncResult;
|
||||
return (uint)currentThread.ObjSyncResult;
|
||||
}
|
||||
|
||||
public long ArbitrateUnlock(long MutexAddress)
|
||||
public long ArbitrateUnlock(long mutexAddress)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
(long Result, KThread NewOwnerThread) = MutexUnlock(CurrentThread, MutexAddress);
|
||||
(long result, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress);
|
||||
|
||||
if (Result != 0 && NewOwnerThread != null)
|
||||
if (result != 0 && newOwnerThread != null)
|
||||
{
|
||||
NewOwnerThread.SignaledObj = null;
|
||||
NewOwnerThread.ObjSyncResult = (int)Result;
|
||||
newOwnerThread.SignaledObj = null;
|
||||
newOwnerThread.ObjSyncResult = (int)result;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long WaitProcessWideKeyAtomic(
|
||||
long MutexAddress,
|
||||
long CondVarAddress,
|
||||
int ThreadHandle,
|
||||
long Timeout)
|
||||
long mutexAddress,
|
||||
long condVarAddress,
|
||||
int threadHandle,
|
||||
long timeout)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
CurrentThread.SignaledObj = null;
|
||||
CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
|
||||
if (CurrentThread.ShallBeTerminated ||
|
||||
CurrentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
if (currentThread.ShallBeTerminated ||
|
||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
|
||||
}
|
||||
|
||||
(long Result, _) = MutexUnlock(CurrentThread, MutexAddress);
|
||||
(long result, _) = MutexUnlock(currentThread, mutexAddress);
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
CurrentThread.MutexAddress = MutexAddress;
|
||||
CurrentThread.ThreadHandleForUserMutex = ThreadHandle;
|
||||
CurrentThread.CondVarAddress = CondVarAddress;
|
||||
currentThread.MutexAddress = mutexAddress;
|
||||
currentThread.ThreadHandleForUserMutex = threadHandle;
|
||||
currentThread.CondVarAddress = condVarAddress;
|
||||
|
||||
CondVarThreads.Add(CurrentThread);
|
||||
CondVarThreads.Add(currentThread);
|
||||
|
||||
if (Timeout != 0)
|
||||
if (timeout != 0)
|
||||
{
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout);
|
||||
_system.TimeManager.ScheduleFutureInvocation(currentThread, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.UnscheduleFutureInvocation(CurrentThread);
|
||||
_system.TimeManager.UnscheduleFutureInvocation(currentThread);
|
||||
}
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (CurrentThread.MutexOwner != null)
|
||||
if (currentThread.MutexOwner != null)
|
||||
{
|
||||
CurrentThread.MutexOwner.RemoveMutexWaiter(CurrentThread);
|
||||
currentThread.MutexOwner.RemoveMutexWaiter(currentThread);
|
||||
}
|
||||
|
||||
CondVarThreads.Remove(CurrentThread);
|
||||
CondVarThreads.Remove(currentThread);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return (uint)CurrentThread.ObjSyncResult;
|
||||
return (uint)currentThread.ObjSyncResult;
|
||||
}
|
||||
|
||||
private (long, KThread) MutexUnlock(KThread CurrentThread, long MutexAddress)
|
||||
private (long, KThread) MutexUnlock(KThread currentThread, long mutexAddress)
|
||||
{
|
||||
KThread NewOwnerThread = CurrentThread.RelinquishMutex(MutexAddress, out int Count);
|
||||
KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count);
|
||||
|
||||
int MutexValue = 0;
|
||||
int mutexValue = 0;
|
||||
|
||||
if (NewOwnerThread != null)
|
||||
if (newOwnerThread != null)
|
||||
{
|
||||
MutexValue = NewOwnerThread.ThreadHandleForUserMutex;
|
||||
mutexValue = newOwnerThread.ThreadHandleForUserMutex;
|
||||
|
||||
if (Count >= 2)
|
||||
if (count >= 2)
|
||||
{
|
||||
MutexValue |= HasListenersMask;
|
||||
mutexValue |= HasListenersMask;
|
||||
}
|
||||
|
||||
NewOwnerThread.SignaledObj = null;
|
||||
NewOwnerThread.ObjSyncResult = 0;
|
||||
newOwnerThread.SignaledObj = null;
|
||||
newOwnerThread.ObjSyncResult = 0;
|
||||
|
||||
NewOwnerThread.ReleaseAndResume();
|
||||
newOwnerThread.ReleaseAndResume();
|
||||
}
|
||||
|
||||
long Result = 0;
|
||||
long result = 0;
|
||||
|
||||
if (!KernelTransfer.KernelToUserInt32(System, MutexAddress, MutexValue))
|
||||
if (!KernelTransfer.KernelToUserInt32(_system, mutexAddress, mutexValue))
|
||||
{
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
result = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
return (Result, NewOwnerThread);
|
||||
return (result, newOwnerThread);
|
||||
}
|
||||
|
||||
public void SignalProcessWideKey(long Address, int Count)
|
||||
public void SignalProcessWideKey(long address, int count)
|
||||
{
|
||||
Queue<KThread> SignaledThreads = new Queue<KThread>();
|
||||
Queue<KThread> signaledThreads = new Queue<KThread>();
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
IOrderedEnumerable<KThread> SortedThreads = CondVarThreads.OrderBy(x => x.DynamicPriority);
|
||||
IOrderedEnumerable<KThread> sortedThreads = CondVarThreads.OrderBy(x => x.DynamicPriority);
|
||||
|
||||
foreach (KThread Thread in SortedThreads.Where(x => x.CondVarAddress == Address))
|
||||
foreach (KThread thread in sortedThreads.Where(x => x.CondVarAddress == address))
|
||||
{
|
||||
TryAcquireMutex(Thread);
|
||||
TryAcquireMutex(thread);
|
||||
|
||||
SignaledThreads.Enqueue(Thread);
|
||||
signaledThreads.Enqueue(thread);
|
||||
|
||||
//If the count is <= 0, we should signal all threads waiting.
|
||||
if (Count >= 1 && --Count == 0)
|
||||
if (count >= 1 && --count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (SignaledThreads.TryDequeue(out KThread Thread))
|
||||
while (signaledThreads.TryDequeue(out KThread thread))
|
||||
{
|
||||
CondVarThreads.Remove(Thread);
|
||||
CondVarThreads.Remove(thread);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
private KThread TryAcquireMutex(KThread Requester)
|
||||
private KThread TryAcquireMutex(KThread requester)
|
||||
{
|
||||
long Address = Requester.MutexAddress;
|
||||
long address = requester.MutexAddress;
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32(System, Address, out int MutexValue))
|
||||
if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue))
|
||||
{
|
||||
//Invalid address.
|
||||
CurrentProcess.CpuMemory.ClearExclusive(0);
|
||||
currentProcess.CpuMemory.ClearExclusive(0);
|
||||
|
||||
Requester.SignaledObj = null;
|
||||
Requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
requester.SignaledObj = null;
|
||||
requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (CurrentProcess.CpuMemory.TestExclusive(0, Address))
|
||||
if (currentProcess.CpuMemory.TestExclusive(0, address))
|
||||
{
|
||||
if (MutexValue != 0)
|
||||
if (mutexValue != 0)
|
||||
{
|
||||
//Update value to indicate there is a mutex waiter now.
|
||||
CurrentProcess.CpuMemory.WriteInt32(Address, MutexValue | HasListenersMask);
|
||||
currentProcess.CpuMemory.WriteInt32(address, mutexValue | HasListenersMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
//No thread owning the mutex, assign to requesting thread.
|
||||
CurrentProcess.CpuMemory.WriteInt32(Address, Requester.ThreadHandleForUserMutex);
|
||||
currentProcess.CpuMemory.WriteInt32(address, requester.ThreadHandleForUserMutex);
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
currentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
MutexValue = CurrentProcess.CpuMemory.ReadInt32(Address);
|
||||
mutexValue = currentProcess.CpuMemory.ReadInt32(address);
|
||||
}
|
||||
|
||||
if (MutexValue == 0)
|
||||
if (mutexValue == 0)
|
||||
{
|
||||
//We now own the mutex.
|
||||
Requester.SignaledObj = null;
|
||||
Requester.ObjSyncResult = 0;
|
||||
requester.SignaledObj = null;
|
||||
requester.ObjSyncResult = 0;
|
||||
|
||||
Requester.ReleaseAndResume();
|
||||
requester.ReleaseAndResume();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
MutexValue &= ~HasListenersMask;
|
||||
mutexValue &= ~HasListenersMask;
|
||||
|
||||
KThread MutexOwner = CurrentProcess.HandleTable.GetObject<KThread>(MutexValue);
|
||||
KThread mutexOwner = currentProcess.HandleTable.GetObject<KThread>(mutexValue);
|
||||
|
||||
if (MutexOwner != null)
|
||||
if (mutexOwner != null)
|
||||
{
|
||||
//Mutex already belongs to another thread, wait for it.
|
||||
MutexOwner.AddMutexWaiter(Requester);
|
||||
mutexOwner.AddMutexWaiter(requester);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Invalid mutex owner.
|
||||
Requester.SignaledObj = null;
|
||||
Requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
requester.SignaledObj = null;
|
||||
requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
Requester.ReleaseAndResume();
|
||||
requester.ReleaseAndResume();
|
||||
}
|
||||
|
||||
return MutexOwner;
|
||||
return mutexOwner;
|
||||
}
|
||||
|
||||
public long WaitForAddressIfEqual(long Address, int Value, long Timeout)
|
||||
public long WaitForAddressIfEqual(long address, int value, long timeout)
|
||||
{
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (CurrentThread.ShallBeTerminated ||
|
||||
CurrentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
if (currentThread.ShallBeTerminated ||
|
||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
|
||||
}
|
||||
|
||||
CurrentThread.SignaledObj = null;
|
||||
CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32(System, Address, out int CurrentValue))
|
||||
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
if (CurrentValue == Value)
|
||||
if (currentValue == value)
|
||||
{
|
||||
if (Timeout == 0)
|
||||
if (timeout == 0)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
}
|
||||
|
||||
CurrentThread.MutexAddress = Address;
|
||||
CurrentThread.WaitingInArbitration = true;
|
||||
currentThread.MutexAddress = address;
|
||||
currentThread.WaitingInArbitration = true;
|
||||
|
||||
InsertSortedByPriority(ArbiterThreads, CurrentThread);
|
||||
InsertSortedByPriority(ArbiterThreads, currentThread);
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout);
|
||||
_system.TimeManager.ScheduleFutureInvocation(currentThread, timeout);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.UnscheduleFutureInvocation(CurrentThread);
|
||||
_system.TimeManager.UnscheduleFutureInvocation(currentThread);
|
||||
}
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (CurrentThread.WaitingInArbitration)
|
||||
if (currentThread.WaitingInArbitration)
|
||||
{
|
||||
ArbiterThreads.Remove(CurrentThread);
|
||||
ArbiterThreads.Remove(currentThread);
|
||||
|
||||
CurrentThread.WaitingInArbitration = false;
|
||||
currentThread.WaitingInArbitration = false;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return CurrentThread.ObjSyncResult;
|
||||
return currentThread.ObjSyncResult;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
}
|
||||
|
||||
public long WaitForAddressIfLessThan(long Address, int Value, bool ShouldDecrement, long Timeout)
|
||||
public long WaitForAddressIfLessThan(long address, int value, bool shouldDecrement, long timeout)
|
||||
{
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (CurrentThread.ShallBeTerminated ||
|
||||
CurrentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
if (currentThread.ShallBeTerminated ||
|
||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
|
||||
}
|
||||
|
||||
CurrentThread.SignaledObj = null;
|
||||
CurrentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
//If ShouldDecrement is true, do atomic decrement of the value at Address.
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32(System, Address, out int CurrentValue))
|
||||
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
if (ShouldDecrement)
|
||||
if (shouldDecrement)
|
||||
{
|
||||
while (CurrentValue < Value)
|
||||
while (currentValue < value)
|
||||
{
|
||||
if (CurrentProcess.CpuMemory.TestExclusive(0, Address))
|
||||
if (currentProcess.CpuMemory.TestExclusive(0, address))
|
||||
{
|
||||
CurrentProcess.CpuMemory.WriteInt32(Address, CurrentValue - 1);
|
||||
currentProcess.CpuMemory.WriteInt32(address, currentValue - 1);
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
currentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
CurrentValue = CurrentProcess.CpuMemory.ReadInt32(Address);
|
||||
currentValue = currentProcess.CpuMemory.ReadInt32(address);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusive(0);
|
||||
currentProcess.CpuMemory.ClearExclusive(0);
|
||||
|
||||
if (CurrentValue < Value)
|
||||
if (currentValue < value)
|
||||
{
|
||||
if (Timeout == 0)
|
||||
if (timeout == 0)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
}
|
||||
|
||||
CurrentThread.MutexAddress = Address;
|
||||
CurrentThread.WaitingInArbitration = true;
|
||||
currentThread.MutexAddress = address;
|
||||
currentThread.WaitingInArbitration = true;
|
||||
|
||||
InsertSortedByPriority(ArbiterThreads, CurrentThread);
|
||||
InsertSortedByPriority(ArbiterThreads, currentThread);
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout);
|
||||
_system.TimeManager.ScheduleFutureInvocation(currentThread, timeout);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.UnscheduleFutureInvocation(CurrentThread);
|
||||
_system.TimeManager.UnscheduleFutureInvocation(currentThread);
|
||||
}
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (CurrentThread.WaitingInArbitration)
|
||||
if (currentThread.WaitingInArbitration)
|
||||
{
|
||||
ArbiterThreads.Remove(CurrentThread);
|
||||
ArbiterThreads.Remove(currentThread);
|
||||
|
||||
CurrentThread.WaitingInArbitration = false;
|
||||
currentThread.WaitingInArbitration = false;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return CurrentThread.ObjSyncResult;
|
||||
return currentThread.ObjSyncResult;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
}
|
||||
|
||||
private void InsertSortedByPriority(List<KThread> Threads, KThread Thread)
|
||||
private void InsertSortedByPriority(List<KThread> threads, KThread thread)
|
||||
{
|
||||
int NextIndex = -1;
|
||||
int nextIndex = -1;
|
||||
|
||||
for (int Index = 0; Index < Threads.Count; Index++)
|
||||
for (int index = 0; index < threads.Count; index++)
|
||||
{
|
||||
if (Threads[Index].DynamicPriority > Thread.DynamicPriority)
|
||||
if (threads[index].DynamicPriority > thread.DynamicPriority)
|
||||
{
|
||||
NextIndex = Index;
|
||||
nextIndex = index;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NextIndex != -1)
|
||||
if (nextIndex != -1)
|
||||
{
|
||||
Threads.Insert(NextIndex, Thread);
|
||||
threads.Insert(nextIndex, thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
Threads.Add(Thread);
|
||||
threads.Add(thread);
|
||||
}
|
||||
}
|
||||
|
||||
public long Signal(long Address, int Count)
|
||||
public long Signal(long address, int count)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
WakeArbiterThreads(Address, Count);
|
||||
WakeArbiterThreads(address, count);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SignalAndIncrementIfEqual(long Address, int Value, int Count)
|
||||
public long SignalAndIncrementIfEqual(long address, int value, int count)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32(System, Address, out int CurrentValue))
|
||||
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
while (CurrentValue == Value)
|
||||
while (currentValue == value)
|
||||
{
|
||||
if (CurrentProcess.CpuMemory.TestExclusive(0, Address))
|
||||
if (currentProcess.CpuMemory.TestExclusive(0, address))
|
||||
{
|
||||
CurrentProcess.CpuMemory.WriteInt32(Address, CurrentValue + 1);
|
||||
currentProcess.CpuMemory.WriteInt32(address, currentValue + 1);
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
currentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
CurrentValue = CurrentProcess.CpuMemory.ReadInt32(Address);
|
||||
currentValue = currentProcess.CpuMemory.ReadInt32(address);
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusive(0);
|
||||
currentProcess.CpuMemory.ClearExclusive(0);
|
||||
|
||||
if (CurrentValue != Value)
|
||||
if (currentValue != value)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
}
|
||||
|
||||
WakeArbiterThreads(Address, Count);
|
||||
WakeArbiterThreads(address, count);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SignalAndModifyIfEqual(long Address, int Value, int Count)
|
||||
public long SignalAndModifyIfEqual(long address, int value, int count)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
int Offset;
|
||||
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;
|
||||
int waitingCount = 0;
|
||||
|
||||
foreach (KThread Thread in ArbiterThreads.Where(x => x.MutexAddress == Address))
|
||||
foreach (KThread thread in ArbiterThreads.Where(x => x.MutexAddress == address))
|
||||
{
|
||||
if (++WaitingCount > Count)
|
||||
if (++waitingCount > count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WaitingCount > 0)
|
||||
if (waitingCount > 0)
|
||||
{
|
||||
Offset = WaitingCount <= Count || Count <= 0 ? -1 : 0;
|
||||
offset = waitingCount <= count || count <= 0 ? -1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Offset = 1;
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
if (!KernelTransfer.UserToKernelInt32(System, Address, out int CurrentValue))
|
||||
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
while (CurrentValue == Value)
|
||||
while (currentValue == value)
|
||||
{
|
||||
if (CurrentProcess.CpuMemory.TestExclusive(0, Address))
|
||||
if (currentProcess.CpuMemory.TestExclusive(0, address))
|
||||
{
|
||||
CurrentProcess.CpuMemory.WriteInt32(Address, CurrentValue + Offset);
|
||||
currentProcess.CpuMemory.WriteInt32(address, currentValue + offset);
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
currentProcess.CpuMemory.ClearExclusiveForStore(0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.SetExclusive(0, Address);
|
||||
currentProcess.CpuMemory.SetExclusive(0, address);
|
||||
|
||||
CurrentValue = CurrentProcess.CpuMemory.ReadInt32(Address);
|
||||
currentValue = currentProcess.CpuMemory.ReadInt32(address);
|
||||
}
|
||||
|
||||
CurrentProcess.CpuMemory.ClearExclusive(0);
|
||||
currentProcess.CpuMemory.ClearExclusive(0);
|
||||
|
||||
if (CurrentValue != Value)
|
||||
if (currentValue != value)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
}
|
||||
|
||||
WakeArbiterThreads(Address, Count);
|
||||
WakeArbiterThreads(address, count);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void WakeArbiterThreads(long Address, int Count)
|
||||
private void WakeArbiterThreads(long address, int count)
|
||||
{
|
||||
Queue<KThread> SignaledThreads = new Queue<KThread>();
|
||||
Queue<KThread> signaledThreads = new Queue<KThread>();
|
||||
|
||||
foreach (KThread Thread in ArbiterThreads.Where(x => x.MutexAddress == Address))
|
||||
foreach (KThread thread in ArbiterThreads.Where(x => x.MutexAddress == address))
|
||||
{
|
||||
SignaledThreads.Enqueue(Thread);
|
||||
signaledThreads.Enqueue(thread);
|
||||
|
||||
//If the count is <= 0, we should signal all threads waiting.
|
||||
if (Count >= 1 && --Count == 0)
|
||||
if (count >= 1 && --count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (SignaledThreads.TryDequeue(out KThread Thread))
|
||||
while (signaledThreads.TryDequeue(out KThread thread))
|
||||
{
|
||||
Thread.SignaledObj = null;
|
||||
Thread.ObjSyncResult = 0;
|
||||
thread.SignaledObj = null;
|
||||
thread.ObjSyncResult = 0;
|
||||
|
||||
Thread.ReleaseAndResume();
|
||||
thread.ReleaseAndResume();
|
||||
|
||||
Thread.WaitingInArbitration = false;
|
||||
thread.WaitingInArbitration = false;
|
||||
|
||||
ArbiterThreads.Remove(Thread);
|
||||
ArbiterThreads.Remove(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
protected Horizon System;
|
||||
|
||||
public KAutoObject(Horizon System)
|
||||
public KAutoObject(Horizon system)
|
||||
{
|
||||
this.System = System;
|
||||
System = system;
|
||||
}
|
||||
|
||||
public virtual KernelResult SetName(string Name)
|
||||
public virtual KernelResult SetName(string name)
|
||||
{
|
||||
if (!System.AutoObjectNames.TryAdd(Name, this))
|
||||
if (!System.AutoObjectNames.TryAdd(name, this))
|
||||
{
|
||||
return KernelResult.InvalidState;
|
||||
}
|
||||
@ -19,9 +19,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public static KernelResult RemoveName(Horizon System, string Name)
|
||||
public static KernelResult RemoveName(Horizon system, string name)
|
||||
{
|
||||
if (!System.AutoObjectNames.TryRemove(Name, out _))
|
||||
if (!system.AutoObjectNames.TryRemove(name, out _))
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
@ -29,11 +29,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public static KAutoObject FindNamedObject(Horizon System, string Name)
|
||||
public static KAutoObject FindNamedObject(Horizon system, string name)
|
||||
{
|
||||
if (System.AutoObjectNames.TryGetValue(Name, out KAutoObject Obj))
|
||||
if (system.AutoObjectNames.TryGetValue(name, out KAutoObject obj))
|
||||
{
|
||||
return Obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -2,30 +2,30 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KClientPort : KSynchronizationObject
|
||||
{
|
||||
private int SessionsCount;
|
||||
private int CurrentCapacity;
|
||||
private int MaxSessions;
|
||||
private int _sessionsCount;
|
||||
private int _currentCapacity;
|
||||
private int _maxSessions;
|
||||
|
||||
private KPort Parent;
|
||||
private KPort _parent;
|
||||
|
||||
public KClientPort(Horizon System) : base(System) { }
|
||||
public KClientPort(Horizon system) : base(system) { }
|
||||
|
||||
public void Initialize(KPort Parent, int MaxSessions)
|
||||
public void Initialize(KPort parent, int maxSessions)
|
||||
{
|
||||
this.MaxSessions = MaxSessions;
|
||||
this.Parent = Parent;
|
||||
_maxSessions = maxSessions;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public new static KernelResult RemoveName(Horizon System, string Name)
|
||||
public new static KernelResult RemoveName(Horizon system, string name)
|
||||
{
|
||||
KAutoObject FoundObj = KAutoObject.FindNamedObject(System, Name);
|
||||
KAutoObject foundObj = FindNamedObject(system, name);
|
||||
|
||||
if (!(FoundObj is KClientPort))
|
||||
if (!(foundObj is KClientPort))
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
|
||||
return KAutoObject.RemoveName(System, Name);
|
||||
return KAutoObject.RemoveName(system, name);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,67 +5,67 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
static class KConditionVariable
|
||||
{
|
||||
public static void Wait(Horizon System, LinkedList<KThread> ThreadList, object Mutex, long Timeout)
|
||||
public static void Wait(Horizon system, LinkedList<KThread> threadList, object mutex, long timeout)
|
||||
{
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = system.Scheduler.GetCurrentThread();
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
system.CriticalSection.Enter();
|
||||
|
||||
Monitor.Exit(Mutex);
|
||||
Monitor.Exit(mutex);
|
||||
|
||||
CurrentThread.Withholder = ThreadList;
|
||||
currentThread.Withholder = threadList;
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
CurrentThread.WithholderNode = ThreadList.AddLast(CurrentThread);
|
||||
currentThread.WithholderNode = threadList.AddLast(currentThread);
|
||||
|
||||
if (CurrentThread.ShallBeTerminated ||
|
||||
CurrentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
if (currentThread.ShallBeTerminated ||
|
||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
{
|
||||
ThreadList.Remove(CurrentThread.WithholderNode);
|
||||
threadList.Remove(currentThread.WithholderNode);
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Running);
|
||||
currentThread.Reschedule(ThreadSchedState.Running);
|
||||
|
||||
CurrentThread.Withholder = null;
|
||||
currentThread.Withholder = null;
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
system.CriticalSection.Leave();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout);
|
||||
system.TimeManager.ScheduleFutureInvocation(currentThread, timeout);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
system.CriticalSection.Leave();
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.UnscheduleFutureInvocation(CurrentThread);
|
||||
system.TimeManager.UnscheduleFutureInvocation(currentThread);
|
||||
}
|
||||
}
|
||||
|
||||
Monitor.Enter(Mutex);
|
||||
Monitor.Enter(mutex);
|
||||
}
|
||||
|
||||
public static void NotifyAll(Horizon System, LinkedList<KThread> ThreadList)
|
||||
public static void NotifyAll(Horizon system, LinkedList<KThread> threadList)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
system.CriticalSection.Enter();
|
||||
|
||||
LinkedListNode<KThread> Node = ThreadList.First;
|
||||
LinkedListNode<KThread> node = threadList.First;
|
||||
|
||||
for (; Node != null; Node = ThreadList.First)
|
||||
for (; node != null; node = threadList.First)
|
||||
{
|
||||
KThread Thread = Node.Value;
|
||||
KThread thread = node.Value;
|
||||
|
||||
ThreadList.Remove(Thread.WithholderNode);
|
||||
threadList.Remove(thread.WithholderNode);
|
||||
|
||||
Thread.Withholder = null;
|
||||
thread.Withholder = null;
|
||||
|
||||
Thread.Reschedule(ThreadSchedState.Running);
|
||||
thread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
system.CriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,77 +7,77 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private const int IdMasksCount = 8;
|
||||
|
||||
private int[] IdMasks;
|
||||
private int[] _idMasks;
|
||||
|
||||
private int NextFreeBitHint;
|
||||
private int _nextFreeBitHint;
|
||||
|
||||
public KContextIdManager()
|
||||
{
|
||||
IdMasks = new int[IdMasksCount];
|
||||
_idMasks = new int[IdMasksCount];
|
||||
}
|
||||
|
||||
public int GetId()
|
||||
{
|
||||
lock (IdMasks)
|
||||
lock (_idMasks)
|
||||
{
|
||||
int Id = 0;
|
||||
int id = 0;
|
||||
|
||||
if (!TestBit(NextFreeBitHint))
|
||||
if (!TestBit(_nextFreeBitHint))
|
||||
{
|
||||
Id = NextFreeBitHint;
|
||||
id = _nextFreeBitHint;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int Index = 0; Index < IdMasksCount; Index++)
|
||||
for (int index = 0; index < IdMasksCount; index++)
|
||||
{
|
||||
int Mask = IdMasks[Index];
|
||||
int mask = _idMasks[index];
|
||||
|
||||
int FirstFreeBit = BitUtils.CountLeadingZeros32((Mask + 1) & ~Mask);
|
||||
int firstFreeBit = BitUtils.CountLeadingZeros32((mask + 1) & ~mask);
|
||||
|
||||
if (FirstFreeBit < 32)
|
||||
if (firstFreeBit < 32)
|
||||
{
|
||||
int BaseBit = Index * 32 + 31;
|
||||
int baseBit = index * 32 + 31;
|
||||
|
||||
Id = BaseBit - FirstFreeBit;
|
||||
id = baseBit - firstFreeBit;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (Index == IdMasksCount - 1)
|
||||
else if (index == IdMasksCount - 1)
|
||||
{
|
||||
throw new InvalidOperationException("Maximum number of Ids reached!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NextFreeBitHint = Id + 1;
|
||||
_nextFreeBitHint = id + 1;
|
||||
|
||||
SetBit(Id);
|
||||
SetBit(id);
|
||||
|
||||
return Id;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
public void PutId(int Id)
|
||||
public void PutId(int id)
|
||||
{
|
||||
lock (IdMasks)
|
||||
lock (_idMasks)
|
||||
{
|
||||
ClearBit(Id);
|
||||
ClearBit(id);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TestBit(int Bit)
|
||||
private bool TestBit(int bit)
|
||||
{
|
||||
return (IdMasks[NextFreeBitHint / 32] & (1 << (NextFreeBitHint & 31))) != 0;
|
||||
return (_idMasks[_nextFreeBitHint / 32] & (1 << (_nextFreeBitHint & 31))) != 0;
|
||||
}
|
||||
|
||||
private void SetBit(int Bit)
|
||||
private void SetBit(int bit)
|
||||
{
|
||||
IdMasks[NextFreeBitHint / 32] |= (1 << (NextFreeBitHint & 31));
|
||||
_idMasks[_nextFreeBitHint / 32] |= (1 << (_nextFreeBitHint & 31));
|
||||
}
|
||||
|
||||
private void ClearBit(int Bit)
|
||||
private void ClearBit(int bit)
|
||||
{
|
||||
IdMasks[NextFreeBitHint / 32] &= ~(1 << (NextFreeBitHint & 31));
|
||||
_idMasks[_nextFreeBitHint / 32] &= ~(1 << (_nextFreeBitHint & 31));
|
||||
}
|
||||
}
|
||||
}
|
@ -4,9 +4,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KCoreContext
|
||||
{
|
||||
private KScheduler Scheduler;
|
||||
private KScheduler _scheduler;
|
||||
|
||||
private HleCoreManager CoreManager;
|
||||
private HleCoreManager _coreManager;
|
||||
|
||||
public bool ContextSwitchNeeded { get; private set; }
|
||||
|
||||
@ -17,15 +17,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
public KThread CurrentThread { get; private set; }
|
||||
public KThread SelectedThread { get; private set; }
|
||||
|
||||
public KCoreContext(KScheduler Scheduler, HleCoreManager CoreManager)
|
||||
public KCoreContext(KScheduler scheduler, HleCoreManager coreManager)
|
||||
{
|
||||
this.Scheduler = Scheduler;
|
||||
this.CoreManager = CoreManager;
|
||||
_scheduler = scheduler;
|
||||
_coreManager = coreManager;
|
||||
}
|
||||
|
||||
public void SelectThread(KThread Thread)
|
||||
public void SelectThread(KThread thread)
|
||||
{
|
||||
SelectedThread = Thread;
|
||||
SelectedThread = thread;
|
||||
|
||||
if (SelectedThread != CurrentThread)
|
||||
{
|
||||
@ -43,10 +43,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
if (CurrentThread != null)
|
||||
{
|
||||
long CurrentTime = PerformanceCounter.ElapsedMilliseconds;
|
||||
long currentTime = PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
CurrentThread.TotalTimeRunning += CurrentTime - CurrentThread.LastScheduledTime;
|
||||
CurrentThread.LastScheduledTime = CurrentTime;
|
||||
CurrentThread.TotalTimeRunning += currentTime - CurrentThread.LastScheduledTime;
|
||||
CurrentThread.LastScheduledTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,21 +58,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
if (CurrentThread != null)
|
||||
{
|
||||
CoreManager.Reset(CurrentThread.Context.Work);
|
||||
_coreManager.Reset(CurrentThread.Context.Work);
|
||||
}
|
||||
|
||||
CurrentThread = SelectedThread;
|
||||
|
||||
if (CurrentThread != null)
|
||||
{
|
||||
long CurrentTime = PerformanceCounter.ElapsedMilliseconds;
|
||||
long currentTime = PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
CurrentThread.TotalTimeRunning += CurrentTime - CurrentThread.LastScheduledTime;
|
||||
CurrentThread.LastScheduledTime = CurrentTime;
|
||||
CurrentThread.TotalTimeRunning += currentTime - CurrentThread.LastScheduledTime;
|
||||
CurrentThread.LastScheduledTime = currentTime;
|
||||
|
||||
CurrentThread.ClearExclusive();
|
||||
|
||||
CoreManager.Set(CurrentThread.Context.Work);
|
||||
_coreManager.Set(CurrentThread.Context.Work);
|
||||
|
||||
CurrentThread.Context.Execute();
|
||||
}
|
||||
|
@ -5,15 +5,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KCriticalSection
|
||||
{
|
||||
private Horizon System;
|
||||
private Horizon _system;
|
||||
|
||||
public object LockObj { get; private set; }
|
||||
public object LockObj { get; }
|
||||
|
||||
private int RecursionCount;
|
||||
private int _recursionCount;
|
||||
|
||||
public KCriticalSection(Horizon System)
|
||||
public KCriticalSection(Horizon system)
|
||||
{
|
||||
this.System = System;
|
||||
_system = system;
|
||||
|
||||
LockObj = new object();
|
||||
}
|
||||
@ -22,53 +22,53 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
Monitor.Enter(LockObj);
|
||||
|
||||
RecursionCount++;
|
||||
_recursionCount++;
|
||||
}
|
||||
|
||||
public void Leave()
|
||||
{
|
||||
if (RecursionCount == 0)
|
||||
if (_recursionCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool DoContextSwitch = false;
|
||||
bool doContextSwitch = false;
|
||||
|
||||
if (--RecursionCount == 0)
|
||||
if (--_recursionCount == 0)
|
||||
{
|
||||
if (System.Scheduler.ThreadReselectionRequested)
|
||||
if (_system.Scheduler.ThreadReselectionRequested)
|
||||
{
|
||||
System.Scheduler.SelectThreads();
|
||||
_system.Scheduler.SelectThreads();
|
||||
}
|
||||
|
||||
Monitor.Exit(LockObj);
|
||||
|
||||
if (System.Scheduler.MultiCoreScheduling)
|
||||
if (_system.Scheduler.MultiCoreScheduling)
|
||||
{
|
||||
lock (System.Scheduler.CoreContexts)
|
||||
lock (_system.Scheduler.CoreContexts)
|
||||
{
|
||||
for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
|
||||
for (int core = 0; core < KScheduler.CpuCoresCount; core++)
|
||||
{
|
||||
KCoreContext CoreContext = System.Scheduler.CoreContexts[Core];
|
||||
KCoreContext coreContext = _system.Scheduler.CoreContexts[core];
|
||||
|
||||
if (CoreContext.ContextSwitchNeeded)
|
||||
if (coreContext.ContextSwitchNeeded)
|
||||
{
|
||||
CpuThread CurrentHleThread = CoreContext.CurrentThread?.Context;
|
||||
CpuThread currentHleThread = coreContext.CurrentThread?.Context;
|
||||
|
||||
if (CurrentHleThread == null)
|
||||
if (currentHleThread == null)
|
||||
{
|
||||
//Nothing is running, we can perform the context switch immediately.
|
||||
CoreContext.ContextSwitch();
|
||||
coreContext.ContextSwitch();
|
||||
}
|
||||
else if (CurrentHleThread.IsCurrentThread())
|
||||
else if (currentHleThread.IsCurrentThread())
|
||||
{
|
||||
//Thread running on the current core, context switch will block.
|
||||
DoContextSwitch = true;
|
||||
doContextSwitch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Thread running on another core, request a interrupt.
|
||||
CurrentHleThread.RequestInterrupt();
|
||||
currentHleThread.RequestInterrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
}
|
||||
else
|
||||
{
|
||||
DoContextSwitch = true;
|
||||
doContextSwitch = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -84,9 +84,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
Monitor.Exit(LockObj);
|
||||
}
|
||||
|
||||
if (DoContextSwitch)
|
||||
if (doContextSwitch)
|
||||
{
|
||||
System.Scheduler.ContextSwitch();
|
||||
_system.Scheduler.ContextSwitch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KEvent
|
||||
{
|
||||
public KReadableEvent ReadableEvent { get; private set; }
|
||||
public KWritableEvent WritableEvent { get; private set; }
|
||||
public KReadableEvent ReadableEvent { get; }
|
||||
public KWritableEvent WritableEvent { get; }
|
||||
|
||||
public KEvent(Horizon System)
|
||||
public KEvent(Horizon system)
|
||||
{
|
||||
ReadableEvent = new KReadableEvent(System, this);
|
||||
ReadableEvent = new KReadableEvent(system, this);
|
||||
WritableEvent = new KWritableEvent(this);
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
public KHandleEntry Next { get; set; }
|
||||
|
||||
public int Index { get; private set; }
|
||||
public int Index { get; }
|
||||
|
||||
public ushort HandleId { get; set; }
|
||||
public object Obj { get; set; }
|
||||
|
||||
public KHandleEntry(int Index)
|
||||
public KHandleEntry(int index)
|
||||
{
|
||||
this.Index = Index;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,148 +7,148 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
private const int SelfThreadHandle = (0x1ffff << 15) | 0;
|
||||
private const int SelfProcessHandle = (0x1ffff << 15) | 1;
|
||||
|
||||
private Horizon System;
|
||||
private Horizon _system;
|
||||
|
||||
private KHandleEntry[] Table;
|
||||
private KHandleEntry[] _table;
|
||||
|
||||
private KHandleEntry TableHead;
|
||||
private KHandleEntry NextFreeEntry;
|
||||
private KHandleEntry _tableHead;
|
||||
private KHandleEntry _nextFreeEntry;
|
||||
|
||||
private int ActiveSlotsCount;
|
||||
private int _activeSlotsCount;
|
||||
|
||||
private int Size;
|
||||
private int _size;
|
||||
|
||||
private ushort IdCounter;
|
||||
private ushort _idCounter;
|
||||
|
||||
public KHandleTable(Horizon System)
|
||||
public KHandleTable(Horizon system)
|
||||
{
|
||||
this.System = System;
|
||||
_system = system;
|
||||
}
|
||||
|
||||
public KernelResult Initialize(int Size)
|
||||
public KernelResult Initialize(int size)
|
||||
{
|
||||
if ((uint)Size > 1024)
|
||||
if ((uint)size > 1024)
|
||||
{
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
if (Size < 1)
|
||||
if (size < 1)
|
||||
{
|
||||
Size = 1024;
|
||||
size = 1024;
|
||||
}
|
||||
|
||||
this.Size = Size;
|
||||
_size = size;
|
||||
|
||||
IdCounter = 1;
|
||||
_idCounter = 1;
|
||||
|
||||
Table = new KHandleEntry[Size];
|
||||
_table = new KHandleEntry[size];
|
||||
|
||||
TableHead = new KHandleEntry(0);
|
||||
_tableHead = new KHandleEntry(0);
|
||||
|
||||
KHandleEntry Entry = TableHead;
|
||||
KHandleEntry entry = _tableHead;
|
||||
|
||||
for (int Index = 0; Index < Size; Index++)
|
||||
for (int index = 0; index < size; index++)
|
||||
{
|
||||
Table[Index] = Entry;
|
||||
_table[index] = entry;
|
||||
|
||||
Entry.Next = new KHandleEntry(Index + 1);
|
||||
entry.Next = new KHandleEntry(index + 1);
|
||||
|
||||
Entry = Entry.Next;
|
||||
entry = entry.Next;
|
||||
}
|
||||
|
||||
Table[Size - 1].Next = null;
|
||||
_table[size - 1].Next = null;
|
||||
|
||||
NextFreeEntry = TableHead;
|
||||
_nextFreeEntry = _tableHead;
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult GenerateHandle(object Obj, out int Handle)
|
||||
public KernelResult GenerateHandle(object obj, out int handle)
|
||||
{
|
||||
Handle = 0;
|
||||
handle = 0;
|
||||
|
||||
lock (Table)
|
||||
lock (_table)
|
||||
{
|
||||
if (ActiveSlotsCount >= Size)
|
||||
if (_activeSlotsCount >= _size)
|
||||
{
|
||||
return KernelResult.HandleTableFull;
|
||||
}
|
||||
|
||||
KHandleEntry Entry = NextFreeEntry;
|
||||
KHandleEntry entry = _nextFreeEntry;
|
||||
|
||||
NextFreeEntry = Entry.Next;
|
||||
_nextFreeEntry = entry.Next;
|
||||
|
||||
Entry.Obj = Obj;
|
||||
Entry.HandleId = IdCounter;
|
||||
entry.Obj = obj;
|
||||
entry.HandleId = _idCounter;
|
||||
|
||||
ActiveSlotsCount++;
|
||||
_activeSlotsCount++;
|
||||
|
||||
Handle = (int)((IdCounter << 15) & (uint)0xffff8000) | Entry.Index;
|
||||
handle = (int)((_idCounter << 15) & 0xffff8000) | entry.Index;
|
||||
|
||||
if ((short)(IdCounter + 1) >= 0)
|
||||
if ((short)(_idCounter + 1) >= 0)
|
||||
{
|
||||
IdCounter++;
|
||||
_idCounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
IdCounter = 1;
|
||||
_idCounter = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public bool CloseHandle(int Handle)
|
||||
public bool CloseHandle(int handle)
|
||||
{
|
||||
if ((Handle >> 30) != 0 ||
|
||||
Handle == SelfThreadHandle ||
|
||||
Handle == SelfProcessHandle)
|
||||
if ((handle >> 30) != 0 ||
|
||||
handle == SelfThreadHandle ||
|
||||
handle == SelfProcessHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int Index = (Handle >> 0) & 0x7fff;
|
||||
int HandleId = (Handle >> 15);
|
||||
int index = (handle >> 0) & 0x7fff;
|
||||
int handleId = (handle >> 15);
|
||||
|
||||
bool Result = false;
|
||||
bool result = false;
|
||||
|
||||
lock (Table)
|
||||
lock (_table)
|
||||
{
|
||||
if (HandleId != 0 && Index < Size)
|
||||
if (handleId != 0 && index < _size)
|
||||
{
|
||||
KHandleEntry Entry = Table[Index];
|
||||
KHandleEntry entry = _table[index];
|
||||
|
||||
if (Entry.Obj != null && Entry.HandleId == HandleId)
|
||||
if (entry.Obj != null && entry.HandleId == handleId)
|
||||
{
|
||||
Entry.Obj = null;
|
||||
Entry.Next = NextFreeEntry;
|
||||
entry.Obj = null;
|
||||
entry.Next = _nextFreeEntry;
|
||||
|
||||
NextFreeEntry = Entry;
|
||||
_nextFreeEntry = entry;
|
||||
|
||||
ActiveSlotsCount--;
|
||||
_activeSlotsCount--;
|
||||
|
||||
Result = true;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public T GetObject<T>(int Handle)
|
||||
public T GetObject<T>(int handle)
|
||||
{
|
||||
int Index = (Handle >> 0) & 0x7fff;
|
||||
int HandleId = (Handle >> 15);
|
||||
int index = (handle >> 0) & 0x7fff;
|
||||
int handleId = (handle >> 15);
|
||||
|
||||
lock (Table)
|
||||
lock (_table)
|
||||
{
|
||||
if ((Handle >> 30) == 0 && HandleId != 0)
|
||||
if ((handle >> 30) == 0 && handleId != 0)
|
||||
{
|
||||
KHandleEntry Entry = Table[Index];
|
||||
KHandleEntry entry = _table[index];
|
||||
|
||||
if (Entry.HandleId == HandleId && Entry.Obj is T Obj)
|
||||
if (entry.HandleId == handleId && entry.Obj is T obj)
|
||||
{
|
||||
return Obj;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,49 +156,49 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public KThread GetKThread(int Handle)
|
||||
public KThread GetKThread(int handle)
|
||||
{
|
||||
if (Handle == SelfThreadHandle)
|
||||
if (handle == SelfThreadHandle)
|
||||
{
|
||||
return System.Scheduler.GetCurrentThread();
|
||||
return _system.Scheduler.GetCurrentThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetObject<KThread>(Handle);
|
||||
return GetObject<KThread>(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public KProcess GetKProcess(int Handle)
|
||||
public KProcess GetKProcess(int handle)
|
||||
{
|
||||
if (Handle == SelfProcessHandle)
|
||||
if (handle == SelfProcessHandle)
|
||||
{
|
||||
return System.Scheduler.GetCurrentProcess();
|
||||
return _system.Scheduler.GetCurrentProcess();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetObject<KProcess>(Handle);
|
||||
return GetObject<KProcess>(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
lock (Table)
|
||||
lock (_table)
|
||||
{
|
||||
for (int Index = 0; Index < Size; Index++)
|
||||
for (int index = 0; index < _size; index++)
|
||||
{
|
||||
KHandleEntry Entry = Table[Index];
|
||||
KHandleEntry entry = _table[index];
|
||||
|
||||
if (Entry.Obj != null)
|
||||
if (entry.Obj != null)
|
||||
{
|
||||
if (Entry.Obj is IDisposable DisposableObj)
|
||||
if (entry.Obj is IDisposable disposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
disposableObj.Dispose();
|
||||
}
|
||||
|
||||
Entry.Obj = null;
|
||||
Entry.Next = NextFreeEntry;
|
||||
entry.Obj = null;
|
||||
entry.Next = _nextFreeEntry;
|
||||
|
||||
NextFreeEntry = Entry;
|
||||
_nextFreeEntry = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KMemoryArrange
|
||||
{
|
||||
public KMemoryArrangeRegion Service { get; private set; }
|
||||
public KMemoryArrangeRegion NvServices { get; private set; }
|
||||
public KMemoryArrangeRegion Applet { get; private set; }
|
||||
public KMemoryArrangeRegion Application { get; private set; }
|
||||
public KMemoryArrangeRegion Service { get; }
|
||||
public KMemoryArrangeRegion NvServices { get; }
|
||||
public KMemoryArrangeRegion Applet { get; }
|
||||
public KMemoryArrangeRegion Application { get; }
|
||||
|
||||
public KMemoryArrange(
|
||||
KMemoryArrangeRegion Service,
|
||||
KMemoryArrangeRegion NvServices,
|
||||
KMemoryArrangeRegion Applet,
|
||||
KMemoryArrangeRegion Application)
|
||||
KMemoryArrangeRegion service,
|
||||
KMemoryArrangeRegion nvServices,
|
||||
KMemoryArrangeRegion applet,
|
||||
KMemoryArrangeRegion application)
|
||||
{
|
||||
this.Service = Service;
|
||||
this.NvServices = NvServices;
|
||||
this.Applet = Applet;
|
||||
this.Application = Application;
|
||||
Service = service;
|
||||
NvServices = nvServices;
|
||||
Applet = applet;
|
||||
Application = application;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,15 +2,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
struct KMemoryArrangeRegion
|
||||
{
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
public ulong EndAddr => Address + Size;
|
||||
|
||||
public KMemoryArrangeRegion(ulong Address, ulong Size)
|
||||
public KMemoryArrangeRegion(ulong address, ulong size)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
Address = address;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
}
|
@ -13,26 +13,26 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
public int DeviceRefCount { get; set; }
|
||||
|
||||
public KMemoryBlock(
|
||||
ulong BaseAddress,
|
||||
ulong PagesCount,
|
||||
MemoryState State,
|
||||
MemoryPermission Permission,
|
||||
MemoryAttribute Attribute)
|
||||
ulong baseAddress,
|
||||
ulong pagesCount,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
MemoryAttribute attribute)
|
||||
{
|
||||
this.BaseAddress = BaseAddress;
|
||||
this.PagesCount = PagesCount;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
this.Permission = Permission;
|
||||
BaseAddress = baseAddress;
|
||||
PagesCount = pagesCount;
|
||||
State = state;
|
||||
Attribute = attribute;
|
||||
Permission = permission;
|
||||
}
|
||||
|
||||
public KMemoryInfo GetInfo()
|
||||
{
|
||||
ulong Size = PagesCount * KMemoryManager.PageSize;
|
||||
ulong size = PagesCount * KMemoryManager.PageSize;
|
||||
|
||||
return new KMemoryInfo(
|
||||
BaseAddress,
|
||||
Size,
|
||||
size,
|
||||
State,
|
||||
Permission,
|
||||
Attribute,
|
||||
|
@ -2,18 +2,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KMemoryBlockAllocator
|
||||
{
|
||||
private ulong CapacityElements;
|
||||
private ulong _capacityElements;
|
||||
|
||||
public int Count { get; set; }
|
||||
|
||||
public KMemoryBlockAllocator(ulong CapacityElements)
|
||||
public KMemoryBlockAllocator(ulong capacityElements)
|
||||
{
|
||||
this.CapacityElements = CapacityElements;
|
||||
_capacityElements = capacityElements;
|
||||
}
|
||||
|
||||
public bool CanAllocate(int Count)
|
||||
public bool CanAllocate(int count)
|
||||
{
|
||||
return (ulong)(this.Count + Count) <= CapacityElements;
|
||||
return (ulong)(Count + count) <= _capacityElements;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,32 +2,32 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KMemoryInfo
|
||||
{
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
public MemoryState State { get; private set; }
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
public MemoryAttribute Attribute { get; private set; }
|
||||
public MemoryState State { get; }
|
||||
public MemoryPermission Permission { get; }
|
||||
public MemoryAttribute Attribute { get; }
|
||||
|
||||
public int IpcRefCount { get; private set; }
|
||||
public int DeviceRefCount { get; private set; }
|
||||
public int IpcRefCount { get; }
|
||||
public int DeviceRefCount { get; }
|
||||
|
||||
public KMemoryInfo(
|
||||
ulong Address,
|
||||
ulong Size,
|
||||
MemoryState State,
|
||||
MemoryPermission Permission,
|
||||
MemoryAttribute Attribute,
|
||||
int IpcRefCount,
|
||||
int DeviceRefCount)
|
||||
ulong address,
|
||||
ulong size,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
MemoryAttribute attribute,
|
||||
int ipcRefCount,
|
||||
int deviceRefCount)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
this.Permission = Permission;
|
||||
this.IpcRefCount = IpcRefCount;
|
||||
this.DeviceRefCount = DeviceRefCount;
|
||||
Address = address;
|
||||
Size = size;
|
||||
State = state;
|
||||
Attribute = attribute;
|
||||
Permission = permission;
|
||||
IpcRefCount = ipcRefCount;
|
||||
DeviceRefCount = deviceRefCount;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -12,30 +12,30 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
public int Order;
|
||||
public int NextOrder;
|
||||
|
||||
public bool TryCoalesce(int Index, int Size)
|
||||
public bool TryCoalesce(int index, int size)
|
||||
{
|
||||
long Mask = ((1L << Size) - 1) << (Index & 63);
|
||||
long mask = ((1L << size) - 1) << (index & 63);
|
||||
|
||||
Index /= 64;
|
||||
index /= 64;
|
||||
|
||||
if ((Mask & ~Masks[MaxLevel - 1][Index]) != 0)
|
||||
if ((mask & ~Masks[MaxLevel - 1][index]) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Masks[MaxLevel - 1][Index] &= ~Mask;
|
||||
Masks[MaxLevel - 1][index] &= ~mask;
|
||||
|
||||
for (int Level = MaxLevel - 2; Level >= 0; Level--, Index /= 64)
|
||||
for (int level = MaxLevel - 2; level >= 0; level--, index /= 64)
|
||||
{
|
||||
Masks[Level][Index / 64] &= ~(1L << (Index & 63));
|
||||
Masks[level][index / 64] &= ~(1L << (index & 63));
|
||||
|
||||
if (Masks[Level][Index / 64] != 0)
|
||||
if (Masks[level][index / 64] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreeCount -= (ulong)Size;
|
||||
FreeCount -= (ulong)size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6,404 +6,404 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private static readonly int[] BlockOrders = new int[] { 12, 16, 21, 22, 25, 29, 30 };
|
||||
|
||||
public ulong Address { get; private set; }
|
||||
public ulong EndAddr { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
public ulong Address { get; }
|
||||
public ulong EndAddr { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
private int BlockOrdersCount;
|
||||
private int _blockOrdersCount;
|
||||
|
||||
private KMemoryRegionBlock[] Blocks;
|
||||
private KMemoryRegionBlock[] _blocks;
|
||||
|
||||
public KMemoryRegionManager(ulong Address, ulong Size, ulong EndAddr)
|
||||
public KMemoryRegionManager(ulong address, ulong size, ulong endAddr)
|
||||
{
|
||||
Blocks = new KMemoryRegionBlock[BlockOrders.Length];
|
||||
_blocks = new KMemoryRegionBlock[BlockOrders.Length];
|
||||
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
this.EndAddr = EndAddr;
|
||||
Address = address;
|
||||
Size = size;
|
||||
EndAddr = endAddr;
|
||||
|
||||
BlockOrdersCount = BlockOrders.Length;
|
||||
_blockOrdersCount = BlockOrders.Length;
|
||||
|
||||
for (int BlockIndex = 0; BlockIndex < BlockOrdersCount; BlockIndex++)
|
||||
for (int blockIndex = 0; blockIndex < _blockOrdersCount; blockIndex++)
|
||||
{
|
||||
Blocks[BlockIndex] = new KMemoryRegionBlock();
|
||||
_blocks[blockIndex] = new KMemoryRegionBlock();
|
||||
|
||||
Blocks[BlockIndex].Order = BlockOrders[BlockIndex];
|
||||
_blocks[blockIndex].Order = BlockOrders[blockIndex];
|
||||
|
||||
int NextOrder = BlockIndex == BlockOrdersCount - 1 ? 0 : BlockOrders[BlockIndex + 1];
|
||||
int nextOrder = blockIndex == _blockOrdersCount - 1 ? 0 : BlockOrders[blockIndex + 1];
|
||||
|
||||
Blocks[BlockIndex].NextOrder = NextOrder;
|
||||
_blocks[blockIndex].NextOrder = nextOrder;
|
||||
|
||||
int CurrBlockSize = 1 << BlockOrders[BlockIndex];
|
||||
int NextBlockSize = CurrBlockSize;
|
||||
int currBlockSize = 1 << BlockOrders[blockIndex];
|
||||
int nextBlockSize = currBlockSize;
|
||||
|
||||
if (NextOrder != 0)
|
||||
if (nextOrder != 0)
|
||||
{
|
||||
NextBlockSize = 1 << NextOrder;
|
||||
nextBlockSize = 1 << nextOrder;
|
||||
}
|
||||
|
||||
ulong StartAligned = BitUtils.AlignDown(Address, NextBlockSize);
|
||||
ulong EndAddrAligned = BitUtils.AlignDown(EndAddr, CurrBlockSize);
|
||||
ulong startAligned = BitUtils.AlignDown(address, nextBlockSize);
|
||||
ulong endAddrAligned = BitUtils.AlignDown(endAddr, currBlockSize);
|
||||
|
||||
ulong SizeInBlocksTruncated = (EndAddrAligned - StartAligned) >> BlockOrders[BlockIndex];
|
||||
ulong sizeInBlocksTruncated = (endAddrAligned - startAligned) >> BlockOrders[blockIndex];
|
||||
|
||||
ulong EndAddrRounded = BitUtils.AlignUp(Address + Size, NextBlockSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp(address + size, nextBlockSize);
|
||||
|
||||
ulong SizeInBlocksRounded = (EndAddrRounded - StartAligned) >> BlockOrders[BlockIndex];
|
||||
ulong sizeInBlocksRounded = (endAddrRounded - startAligned) >> BlockOrders[blockIndex];
|
||||
|
||||
Blocks[BlockIndex].StartAligned = StartAligned;
|
||||
Blocks[BlockIndex].SizeInBlocksTruncated = SizeInBlocksTruncated;
|
||||
Blocks[BlockIndex].SizeInBlocksRounded = SizeInBlocksRounded;
|
||||
_blocks[blockIndex].StartAligned = startAligned;
|
||||
_blocks[blockIndex].SizeInBlocksTruncated = sizeInBlocksTruncated;
|
||||
_blocks[blockIndex].SizeInBlocksRounded = sizeInBlocksRounded;
|
||||
|
||||
ulong CurrSizeInBlocks = SizeInBlocksRounded;
|
||||
ulong currSizeInBlocks = sizeInBlocksRounded;
|
||||
|
||||
int MaxLevel = 0;
|
||||
int maxLevel = 0;
|
||||
|
||||
do
|
||||
{
|
||||
MaxLevel++;
|
||||
maxLevel++;
|
||||
}
|
||||
while ((CurrSizeInBlocks /= 64) != 0);
|
||||
while ((currSizeInBlocks /= 64) != 0);
|
||||
|
||||
Blocks[BlockIndex].MaxLevel = MaxLevel;
|
||||
_blocks[blockIndex].MaxLevel = maxLevel;
|
||||
|
||||
Blocks[BlockIndex].Masks = new long[MaxLevel][];
|
||||
_blocks[blockIndex].Masks = new long[maxLevel][];
|
||||
|
||||
CurrSizeInBlocks = SizeInBlocksRounded;
|
||||
currSizeInBlocks = sizeInBlocksRounded;
|
||||
|
||||
for (int Level = MaxLevel - 1; Level >= 0; Level--)
|
||||
for (int level = maxLevel - 1; level >= 0; level--)
|
||||
{
|
||||
CurrSizeInBlocks = (CurrSizeInBlocks + 63) / 64;
|
||||
currSizeInBlocks = (currSizeInBlocks + 63) / 64;
|
||||
|
||||
Blocks[BlockIndex].Masks[Level] = new long[CurrSizeInBlocks];
|
||||
_blocks[blockIndex].Masks[level] = new long[currSizeInBlocks];
|
||||
}
|
||||
}
|
||||
|
||||
if (Size != 0)
|
||||
if (size != 0)
|
||||
{
|
||||
FreePages(Address, Size / KMemoryManager.PageSize);
|
||||
FreePages(address, size / KMemoryManager.PageSize);
|
||||
}
|
||||
}
|
||||
|
||||
public KernelResult AllocatePages(ulong PagesCount, bool Backwards, out KPageList PageList)
|
||||
public KernelResult AllocatePages(ulong pagesCount, bool backwards, out KPageList pageList)
|
||||
{
|
||||
lock (Blocks)
|
||||
lock (_blocks)
|
||||
{
|
||||
return AllocatePagesImpl(PagesCount, Backwards, out PageList);
|
||||
return AllocatePagesImpl(pagesCount, backwards, out pageList);
|
||||
}
|
||||
}
|
||||
|
||||
private KernelResult AllocatePagesImpl(ulong PagesCount, bool Backwards, out KPageList PageList)
|
||||
private KernelResult AllocatePagesImpl(ulong pagesCount, bool backwards, out KPageList pageList)
|
||||
{
|
||||
PageList = new KPageList();
|
||||
pageList = new KPageList();
|
||||
|
||||
if (BlockOrdersCount > 0)
|
||||
if (_blockOrdersCount > 0)
|
||||
{
|
||||
if (GetFreePagesImpl() < PagesCount)
|
||||
if (GetFreePagesImpl() < pagesCount)
|
||||
{
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
}
|
||||
else if (PagesCount != 0)
|
||||
else if (pagesCount != 0)
|
||||
{
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
for (int BlockIndex = BlockOrdersCount - 1; BlockIndex >= 0; BlockIndex--)
|
||||
for (int blockIndex = _blockOrdersCount - 1; blockIndex >= 0; blockIndex--)
|
||||
{
|
||||
KMemoryRegionBlock Block = Blocks[BlockIndex];
|
||||
KMemoryRegionBlock block = _blocks[blockIndex];
|
||||
|
||||
ulong BestFitBlockSize = 1UL << Block.Order;
|
||||
ulong bestFitBlockSize = 1UL << block.Order;
|
||||
|
||||
ulong BlockPagesCount = BestFitBlockSize / KMemoryManager.PageSize;
|
||||
ulong blockPagesCount = bestFitBlockSize / KMemoryManager.PageSize;
|
||||
|
||||
//Check if this is the best fit for this page size.
|
||||
//If so, try allocating as much requested pages as possible.
|
||||
while (BlockPagesCount <= PagesCount)
|
||||
while (blockPagesCount <= pagesCount)
|
||||
{
|
||||
ulong Address = 0;
|
||||
ulong address = 0;
|
||||
|
||||
for (int CurrBlockIndex = BlockIndex;
|
||||
CurrBlockIndex < BlockOrdersCount && Address == 0;
|
||||
CurrBlockIndex++)
|
||||
for (int currBlockIndex = blockIndex;
|
||||
currBlockIndex < _blockOrdersCount && address == 0;
|
||||
currBlockIndex++)
|
||||
{
|
||||
Block = Blocks[CurrBlockIndex];
|
||||
block = _blocks[currBlockIndex];
|
||||
|
||||
int Index = 0;
|
||||
int index = 0;
|
||||
|
||||
bool ZeroMask = false;
|
||||
bool zeroMask = false;
|
||||
|
||||
for (int Level = 0; Level < Block.MaxLevel; Level++)
|
||||
for (int level = 0; level < block.MaxLevel; level++)
|
||||
{
|
||||
long Mask = Block.Masks[Level][Index];
|
||||
long mask = block.Masks[level][index];
|
||||
|
||||
if (Mask == 0)
|
||||
if (mask == 0)
|
||||
{
|
||||
ZeroMask = true;
|
||||
zeroMask = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (Backwards)
|
||||
if (backwards)
|
||||
{
|
||||
Index = (Index * 64 + 63) - BitUtils.CountLeadingZeros64(Mask);
|
||||
index = (index * 64 + 63) - BitUtils.CountLeadingZeros64(mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
Index = Index * 64 + BitUtils.CountLeadingZeros64(BitUtils.ReverseBits64(Mask));
|
||||
index = index * 64 + BitUtils.CountLeadingZeros64(BitUtils.ReverseBits64(mask));
|
||||
}
|
||||
}
|
||||
|
||||
if (Block.SizeInBlocksTruncated <= (ulong)Index || ZeroMask)
|
||||
if (block.SizeInBlocksTruncated <= (ulong)index || zeroMask)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Block.FreeCount--;
|
||||
block.FreeCount--;
|
||||
|
||||
int TempIdx = Index;
|
||||
int tempIdx = index;
|
||||
|
||||
for (int Level = Block.MaxLevel - 1; Level >= 0; Level--, TempIdx /= 64)
|
||||
for (int level = block.MaxLevel - 1; level >= 0; level--, tempIdx /= 64)
|
||||
{
|
||||
Block.Masks[Level][TempIdx / 64] &= ~(1L << (TempIdx & 63));
|
||||
block.Masks[level][tempIdx / 64] &= ~(1L << (tempIdx & 63));
|
||||
|
||||
if (Block.Masks[Level][TempIdx / 64] != 0)
|
||||
if (block.Masks[level][tempIdx / 64] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Address = Block.StartAligned + ((ulong)Index << Block.Order);
|
||||
address = block.StartAligned + ((ulong)index << block.Order);
|
||||
}
|
||||
|
||||
for (int CurrBlockIndex = BlockIndex;
|
||||
CurrBlockIndex < BlockOrdersCount && Address == 0;
|
||||
CurrBlockIndex++)
|
||||
for (int currBlockIndex = blockIndex;
|
||||
currBlockIndex < _blockOrdersCount && address == 0;
|
||||
currBlockIndex++)
|
||||
{
|
||||
Block = Blocks[CurrBlockIndex];
|
||||
block = _blocks[currBlockIndex];
|
||||
|
||||
int Index = 0;
|
||||
int index = 0;
|
||||
|
||||
bool ZeroMask = false;
|
||||
bool zeroMask = false;
|
||||
|
||||
for (int Level = 0; Level < Block.MaxLevel; Level++)
|
||||
for (int level = 0; level < block.MaxLevel; level++)
|
||||
{
|
||||
long Mask = Block.Masks[Level][Index];
|
||||
long mask = block.Masks[level][index];
|
||||
|
||||
if (Mask == 0)
|
||||
if (mask == 0)
|
||||
{
|
||||
ZeroMask = true;
|
||||
zeroMask = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (Backwards)
|
||||
if (backwards)
|
||||
{
|
||||
Index = Index * 64 + BitUtils.CountLeadingZeros64(BitUtils.ReverseBits64(Mask));
|
||||
index = index * 64 + BitUtils.CountLeadingZeros64(BitUtils.ReverseBits64(mask));
|
||||
}
|
||||
else
|
||||
{
|
||||
Index = (Index * 64 + 63) - BitUtils.CountLeadingZeros64(Mask);
|
||||
index = (index * 64 + 63) - BitUtils.CountLeadingZeros64(mask);
|
||||
}
|
||||
}
|
||||
|
||||
if (Block.SizeInBlocksTruncated <= (ulong)Index || ZeroMask)
|
||||
if (block.SizeInBlocksTruncated <= (ulong)index || zeroMask)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Block.FreeCount--;
|
||||
block.FreeCount--;
|
||||
|
||||
int TempIdx = Index;
|
||||
int tempIdx = index;
|
||||
|
||||
for (int Level = Block.MaxLevel - 1; Level >= 0; Level--, TempIdx /= 64)
|
||||
for (int level = block.MaxLevel - 1; level >= 0; level--, tempIdx /= 64)
|
||||
{
|
||||
Block.Masks[Level][TempIdx / 64] &= ~(1L << (TempIdx & 63));
|
||||
block.Masks[level][tempIdx / 64] &= ~(1L << (tempIdx & 63));
|
||||
|
||||
if (Block.Masks[Level][TempIdx / 64] != 0)
|
||||
if (block.Masks[level][tempIdx / 64] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Address = Block.StartAligned + ((ulong)Index << Block.Order);
|
||||
address = block.StartAligned + ((ulong)index << block.Order);
|
||||
}
|
||||
|
||||
//The address being zero means that no free space was found on that order,
|
||||
//just give up and try with the next one.
|
||||
if (Address == 0)
|
||||
if (address == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//If we are using a larger order than best fit, then we should
|
||||
//split it into smaller blocks.
|
||||
ulong FirstFreeBlockSize = 1UL << Block.Order;
|
||||
ulong firstFreeBlockSize = 1UL << block.Order;
|
||||
|
||||
if (FirstFreeBlockSize > BestFitBlockSize)
|
||||
if (firstFreeBlockSize > bestFitBlockSize)
|
||||
{
|
||||
FreePages(Address + BestFitBlockSize, (FirstFreeBlockSize - BestFitBlockSize) / KMemoryManager.PageSize);
|
||||
FreePages(address + bestFitBlockSize, (firstFreeBlockSize - bestFitBlockSize) / KMemoryManager.PageSize);
|
||||
}
|
||||
|
||||
//Add new allocated page(s) to the pages list.
|
||||
//If an error occurs, then free all allocated pages and fail.
|
||||
KernelResult Result = PageList.AddRange(Address, BlockPagesCount);
|
||||
KernelResult result = pageList.AddRange(address, blockPagesCount);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
FreePages(Address, BlockPagesCount);
|
||||
FreePages(address, blockPagesCount);
|
||||
|
||||
foreach (KPageNode PageNode in PageList)
|
||||
foreach (KPageNode pageNode in pageList)
|
||||
{
|
||||
FreePages(PageNode.Address, PageNode.PagesCount);
|
||||
FreePages(pageNode.Address, pageNode.PagesCount);
|
||||
}
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
PagesCount -= BlockPagesCount;
|
||||
pagesCount -= blockPagesCount;
|
||||
}
|
||||
}
|
||||
|
||||
//Success case, all requested pages were allocated successfully.
|
||||
if (PagesCount == 0)
|
||||
if (pagesCount == 0)
|
||||
{
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
//Error case, free allocated pages and return out of memory.
|
||||
foreach (KPageNode PageNode in PageList)
|
||||
foreach (KPageNode pageNode in pageList)
|
||||
{
|
||||
FreePages(PageNode.Address, PageNode.PagesCount);
|
||||
FreePages(pageNode.Address, pageNode.PagesCount);
|
||||
}
|
||||
|
||||
PageList = null;
|
||||
pageList = null;
|
||||
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
public void FreePages(KPageList PageList)
|
||||
public void FreePages(KPageList pageList)
|
||||
{
|
||||
lock (Blocks)
|
||||
lock (_blocks)
|
||||
{
|
||||
foreach (KPageNode PageNode in PageList)
|
||||
foreach (KPageNode pageNode in pageList)
|
||||
{
|
||||
FreePages(PageNode.Address, PageNode.PagesCount);
|
||||
FreePages(pageNode.Address, pageNode.PagesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FreePages(ulong Address, ulong PagesCount)
|
||||
private void FreePages(ulong address, ulong pagesCount)
|
||||
{
|
||||
ulong EndAddr = Address + PagesCount * KMemoryManager.PageSize;
|
||||
ulong endAddr = address + pagesCount * KMemoryManager.PageSize;
|
||||
|
||||
int BlockIndex = BlockOrdersCount - 1;
|
||||
int blockIndex = _blockOrdersCount - 1;
|
||||
|
||||
ulong AddressRounded = 0;
|
||||
ulong EndAddrTruncated = 0;
|
||||
ulong addressRounded = 0;
|
||||
ulong endAddrTruncated = 0;
|
||||
|
||||
for (; BlockIndex >= 0; BlockIndex--)
|
||||
for (; blockIndex >= 0; blockIndex--)
|
||||
{
|
||||
KMemoryRegionBlock AllocInfo = Blocks[BlockIndex];
|
||||
KMemoryRegionBlock allocInfo = _blocks[blockIndex];
|
||||
|
||||
int BlockSize = 1 << AllocInfo.Order;
|
||||
int blockSize = 1 << allocInfo.Order;
|
||||
|
||||
AddressRounded = BitUtils.AlignUp (Address, BlockSize);
|
||||
EndAddrTruncated = BitUtils.AlignDown(EndAddr, BlockSize);
|
||||
addressRounded = BitUtils.AlignUp (address, blockSize);
|
||||
endAddrTruncated = BitUtils.AlignDown(endAddr, blockSize);
|
||||
|
||||
if (AddressRounded < EndAddrTruncated)
|
||||
if (addressRounded < endAddrTruncated)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeRegion(ulong CurrAddress)
|
||||
void FreeRegion(ulong currAddress)
|
||||
{
|
||||
for (int CurrBlockIndex = BlockIndex;
|
||||
CurrBlockIndex < BlockOrdersCount && CurrAddress != 0;
|
||||
CurrBlockIndex++)
|
||||
for (int currBlockIndex = blockIndex;
|
||||
currBlockIndex < _blockOrdersCount && currAddress != 0;
|
||||
currBlockIndex++)
|
||||
{
|
||||
KMemoryRegionBlock Block = Blocks[CurrBlockIndex];
|
||||
KMemoryRegionBlock block = _blocks[currBlockIndex];
|
||||
|
||||
Block.FreeCount++;
|
||||
block.FreeCount++;
|
||||
|
||||
ulong FreedBlocks = (CurrAddress - Block.StartAligned) >> Block.Order;
|
||||
ulong freedBlocks = (currAddress - block.StartAligned) >> block.Order;
|
||||
|
||||
int Index = (int)FreedBlocks;
|
||||
int index = (int)freedBlocks;
|
||||
|
||||
for (int Level = Block.MaxLevel - 1; Level >= 0; Level--, Index /= 64)
|
||||
for (int level = block.MaxLevel - 1; level >= 0; level--, index /= 64)
|
||||
{
|
||||
long Mask = Block.Masks[Level][Index / 64];
|
||||
long mask = block.Masks[level][index / 64];
|
||||
|
||||
Block.Masks[Level][Index / 64] = Mask | (1L << (Index & 63));
|
||||
block.Masks[level][index / 64] = mask | (1L << (index & 63));
|
||||
|
||||
if (Mask != 0)
|
||||
if (mask != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int BlockSizeDelta = 1 << (Block.NextOrder - Block.Order);
|
||||
int blockSizeDelta = 1 << (block.NextOrder - block.Order);
|
||||
|
||||
int FreedBlocksTruncated = BitUtils.AlignDown((int)FreedBlocks, BlockSizeDelta);
|
||||
int freedBlocksTruncated = BitUtils.AlignDown((int)freedBlocks, blockSizeDelta);
|
||||
|
||||
if (!Block.TryCoalesce(FreedBlocksTruncated, BlockSizeDelta))
|
||||
if (!block.TryCoalesce(freedBlocksTruncated, blockSizeDelta))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CurrAddress = Block.StartAligned + ((ulong)FreedBlocksTruncated << Block.Order);
|
||||
currAddress = block.StartAligned + ((ulong)freedBlocksTruncated << block.Order);
|
||||
}
|
||||
}
|
||||
|
||||
//Free inside aligned region.
|
||||
ulong BaseAddress = AddressRounded;
|
||||
ulong baseAddress = addressRounded;
|
||||
|
||||
while (BaseAddress < EndAddrTruncated)
|
||||
while (baseAddress < endAddrTruncated)
|
||||
{
|
||||
ulong BlockSize = 1UL << Blocks[BlockIndex].Order;
|
||||
ulong blockSize = 1UL << _blocks[blockIndex].Order;
|
||||
|
||||
FreeRegion(BaseAddress);
|
||||
FreeRegion(baseAddress);
|
||||
|
||||
BaseAddress += BlockSize;
|
||||
baseAddress += blockSize;
|
||||
}
|
||||
|
||||
int NextBlockIndex = BlockIndex - 1;
|
||||
int nextBlockIndex = blockIndex - 1;
|
||||
|
||||
//Free region between Address and aligned region start.
|
||||
BaseAddress = AddressRounded;
|
||||
baseAddress = addressRounded;
|
||||
|
||||
for (BlockIndex = NextBlockIndex; BlockIndex >= 0; BlockIndex--)
|
||||
for (blockIndex = nextBlockIndex; blockIndex >= 0; blockIndex--)
|
||||
{
|
||||
ulong BlockSize = 1UL << Blocks[BlockIndex].Order;
|
||||
ulong blockSize = 1UL << _blocks[blockIndex].Order;
|
||||
|
||||
while (BaseAddress - BlockSize >= Address)
|
||||
while (baseAddress - blockSize >= address)
|
||||
{
|
||||
BaseAddress -= BlockSize;
|
||||
baseAddress -= blockSize;
|
||||
|
||||
FreeRegion(BaseAddress);
|
||||
FreeRegion(baseAddress);
|
||||
}
|
||||
}
|
||||
|
||||
//Free region between aligned region end and End Address.
|
||||
BaseAddress = EndAddrTruncated;
|
||||
baseAddress = endAddrTruncated;
|
||||
|
||||
for (BlockIndex = NextBlockIndex; BlockIndex >= 0; BlockIndex--)
|
||||
for (blockIndex = nextBlockIndex; blockIndex >= 0; blockIndex--)
|
||||
{
|
||||
ulong BlockSize = 1UL << Blocks[BlockIndex].Order;
|
||||
ulong blockSize = 1UL << _blocks[blockIndex].Order;
|
||||
|
||||
while (BaseAddress + BlockSize <= EndAddr)
|
||||
while (baseAddress + blockSize <= endAddr)
|
||||
{
|
||||
FreeRegion(BaseAddress);
|
||||
FreeRegion(baseAddress);
|
||||
|
||||
BaseAddress += BlockSize;
|
||||
baseAddress += blockSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ulong GetFreePages()
|
||||
{
|
||||
lock (Blocks)
|
||||
lock (_blocks)
|
||||
{
|
||||
return GetFreePagesImpl();
|
||||
}
|
||||
@ -411,18 +411,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
private ulong GetFreePagesImpl()
|
||||
{
|
||||
ulong AvailablePages = 0;
|
||||
ulong availablePages = 0;
|
||||
|
||||
for (int BlockIndex = 0; BlockIndex < BlockOrdersCount; BlockIndex++)
|
||||
for (int blockIndex = 0; blockIndex < _blockOrdersCount; blockIndex++)
|
||||
{
|
||||
KMemoryRegionBlock Block = Blocks[BlockIndex];
|
||||
KMemoryRegionBlock block = _blocks[blockIndex];
|
||||
|
||||
ulong BlockPagesCount = (1UL << Block.Order) / KMemoryManager.PageSize;
|
||||
ulong blockPagesCount = (1UL << block.Order) / KMemoryManager.PageSize;
|
||||
|
||||
AvailablePages += BlockPagesCount * Block.FreeCount;
|
||||
availablePages += blockPagesCount * block.FreeCount;
|
||||
}
|
||||
|
||||
return AvailablePages;
|
||||
return availablePages;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,31 +5,31 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KPageList : IEnumerable<KPageNode>
|
||||
{
|
||||
public LinkedList<KPageNode> Nodes { get; private set; }
|
||||
public LinkedList<KPageNode> Nodes { get; }
|
||||
|
||||
public KPageList()
|
||||
{
|
||||
Nodes = new LinkedList<KPageNode>();
|
||||
}
|
||||
|
||||
public KernelResult AddRange(ulong Address, ulong PagesCount)
|
||||
public KernelResult AddRange(ulong address, ulong pagesCount)
|
||||
{
|
||||
if (PagesCount != 0)
|
||||
if (pagesCount != 0)
|
||||
{
|
||||
if (Nodes.Last != null)
|
||||
{
|
||||
KPageNode LastNode = Nodes.Last.Value;
|
||||
KPageNode lastNode = Nodes.Last.Value;
|
||||
|
||||
if (LastNode.Address + LastNode.PagesCount * KMemoryManager.PageSize == Address)
|
||||
if (lastNode.Address + lastNode.PagesCount * KMemoryManager.PageSize == address)
|
||||
{
|
||||
Address = LastNode.Address;
|
||||
PagesCount += LastNode.PagesCount;
|
||||
address = lastNode.Address;
|
||||
pagesCount += lastNode.PagesCount;
|
||||
|
||||
Nodes.RemoveLast();
|
||||
}
|
||||
}
|
||||
|
||||
Nodes.AddLast(new KPageNode(Address, PagesCount));
|
||||
Nodes.AddLast(new KPageNode(address, pagesCount));
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
@ -37,34 +37,34 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
public ulong GetPagesCount()
|
||||
{
|
||||
ulong Sum = 0;
|
||||
ulong sum = 0;
|
||||
|
||||
foreach (KPageNode Node in Nodes)
|
||||
foreach (KPageNode node in Nodes)
|
||||
{
|
||||
Sum += Node.PagesCount;
|
||||
sum += node.PagesCount;
|
||||
}
|
||||
|
||||
return Sum;
|
||||
return sum;
|
||||
}
|
||||
|
||||
public bool IsEqual(KPageList Other)
|
||||
public bool IsEqual(KPageList other)
|
||||
{
|
||||
LinkedListNode<KPageNode> ThisNode = Nodes.First;
|
||||
LinkedListNode<KPageNode> OtherNode = Other.Nodes.First;
|
||||
LinkedListNode<KPageNode> thisNode = Nodes.First;
|
||||
LinkedListNode<KPageNode> otherNode = other.Nodes.First;
|
||||
|
||||
while (ThisNode != null && OtherNode != null)
|
||||
while (thisNode != null && otherNode != null)
|
||||
{
|
||||
if (ThisNode.Value.Address != OtherNode.Value.Address ||
|
||||
ThisNode.Value.PagesCount != OtherNode.Value.PagesCount)
|
||||
if (thisNode.Value.Address != otherNode.Value.Address ||
|
||||
thisNode.Value.PagesCount != otherNode.Value.PagesCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ThisNode = ThisNode.Next;
|
||||
OtherNode = OtherNode.Next;
|
||||
thisNode = thisNode.Next;
|
||||
otherNode = otherNode.Next;
|
||||
}
|
||||
|
||||
return ThisNode == null && OtherNode == null;
|
||||
return thisNode == null && otherNode == null;
|
||||
}
|
||||
|
||||
public IEnumerator<KPageNode> GetEnumerator()
|
||||
|
@ -5,10 +5,10 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
public ulong Address;
|
||||
public ulong PagesCount;
|
||||
|
||||
public KPageNode(ulong Address, ulong PagesCount)
|
||||
public KPageNode(ulong address, ulong pagesCount)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.PagesCount = PagesCount;
|
||||
Address = address;
|
||||
PagesCount = pagesCount;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,25 +2,25 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KPort : KAutoObject
|
||||
{
|
||||
public KServerPort ServerPort { get; private set; }
|
||||
public KClientPort ClientPort { get; private set; }
|
||||
public KServerPort ServerPort { get; }
|
||||
public KClientPort ClientPort { get; }
|
||||
|
||||
private long NameAddress;
|
||||
private bool IsLight;
|
||||
private long _nameAddress;
|
||||
private bool _isLight;
|
||||
|
||||
public KPort(Horizon System) : base(System)
|
||||
public KPort(Horizon system) : base(system)
|
||||
{
|
||||
ServerPort = new KServerPort(System);
|
||||
ClientPort = new KClientPort(System);
|
||||
ServerPort = new KServerPort(system);
|
||||
ClientPort = new KClientPort(system);
|
||||
}
|
||||
|
||||
public void Initialize(int MaxSessions, bool IsLight, long NameAddress)
|
||||
public void Initialize(int maxSessions, bool isLight, long nameAddress)
|
||||
{
|
||||
ServerPort.Initialize(this);
|
||||
ClientPort.Initialize(this, MaxSessions);
|
||||
ClientPort.Initialize(this, maxSessions);
|
||||
|
||||
this.IsLight = IsLight;
|
||||
this.NameAddress = NameAddress;
|
||||
_isLight = isLight;
|
||||
_nameAddress = nameAddress;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -4,8 +4,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KProcessCapabilities
|
||||
{
|
||||
public byte[] SvcAccessMask { get; private set; }
|
||||
public byte[] IrqAccessMask { get; private set; }
|
||||
public byte[] SvcAccessMask { get; }
|
||||
public byte[] IrqAccessMask { get; }
|
||||
|
||||
public long AllowedCpuCoresMask { get; private set; }
|
||||
public long AllowedThreadPriosMask { get; private set; }
|
||||
@ -21,91 +21,91 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
IrqAccessMask = new byte[0x80];
|
||||
}
|
||||
|
||||
public KernelResult InitializeForKernel(int[] Caps, KMemoryManager MemoryManager)
|
||||
public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager)
|
||||
{
|
||||
AllowedCpuCoresMask = 0xf;
|
||||
AllowedThreadPriosMask = -1;
|
||||
DebuggingFlags &= ~3;
|
||||
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
||||
|
||||
return Parse(Caps, MemoryManager);
|
||||
return Parse(caps, memoryManager);
|
||||
}
|
||||
|
||||
public KernelResult InitializeForUser(int[] Caps, KMemoryManager MemoryManager)
|
||||
public KernelResult InitializeForUser(int[] caps, KMemoryManager memoryManager)
|
||||
{
|
||||
return Parse(Caps, MemoryManager);
|
||||
return Parse(caps, memoryManager);
|
||||
}
|
||||
|
||||
private KernelResult Parse(int[] Caps, KMemoryManager MemoryManager)
|
||||
private KernelResult Parse(int[] caps, KMemoryManager memoryManager)
|
||||
{
|
||||
int Mask0 = 0;
|
||||
int Mask1 = 0;
|
||||
int mask0 = 0;
|
||||
int mask1 = 0;
|
||||
|
||||
for (int Index = 0; Index < Caps.Length; Index++)
|
||||
for (int index = 0; index < caps.Length; index++)
|
||||
{
|
||||
int Cap = Caps[Index];
|
||||
int cap = caps[index];
|
||||
|
||||
if (((Cap + 1) & ~Cap) != 0x40)
|
||||
if (((cap + 1) & ~cap) != 0x40)
|
||||
{
|
||||
KernelResult Result = ParseCapability(Cap, ref Mask0, ref Mask1, MemoryManager);
|
||||
KernelResult result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uint)Index + 1 >= Caps.Length)
|
||||
if ((uint)index + 1 >= caps.Length)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
int PrevCap = Cap;
|
||||
int prevCap = cap;
|
||||
|
||||
Cap = Caps[++Index];
|
||||
cap = caps[++index];
|
||||
|
||||
if (((Cap + 1) & ~Cap) != 0x40)
|
||||
if (((cap + 1) & ~cap) != 0x40)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if ((Cap & 0x78000000) != 0)
|
||||
if ((cap & 0x78000000) != 0)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
if ((Cap & 0x7ffff80) == 0)
|
||||
if ((cap & 0x7ffff80) == 0)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
long Address = ((long)(uint)PrevCap << 5) & 0xffffff000;
|
||||
long Size = ((long)(uint)Cap << 5) & 0xfffff000;
|
||||
long address = ((long)(uint)prevCap << 5) & 0xffffff000;
|
||||
long size = ((long)(uint)cap << 5) & 0xfffff000;
|
||||
|
||||
if (((ulong)(Address + Size - 1) >> 36) != 0)
|
||||
if (((ulong)(address + size - 1) >> 36) != 0)
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
MemoryPermission Perm = (PrevCap >> 31) != 0
|
||||
MemoryPermission perm = (prevCap >> 31) != 0
|
||||
? MemoryPermission.Read
|
||||
: MemoryPermission.ReadAndWrite;
|
||||
|
||||
KernelResult Result;
|
||||
KernelResult result;
|
||||
|
||||
if ((Cap >> 31) != 0)
|
||||
if ((cap >> 31) != 0)
|
||||
{
|
||||
Result = MemoryManager.MapNormalMemory(Address, Size, Perm);
|
||||
result = memoryManager.MapNormalMemory(address, size, perm);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = MemoryManager.MapIoMemory(Address, Size, Perm);
|
||||
result = memoryManager.MapIoMemory(address, size, perm);
|
||||
}
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,30 +113,30 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
private KernelResult ParseCapability(int Cap, ref int Mask0, ref int Mask1, KMemoryManager MemoryManager)
|
||||
private KernelResult ParseCapability(int cap, ref int mask0, ref int mask1, KMemoryManager memoryManager)
|
||||
{
|
||||
int Code = (Cap + 1) & ~Cap;
|
||||
int code = (cap + 1) & ~cap;
|
||||
|
||||
if (Code == 1)
|
||||
if (code == 1)
|
||||
{
|
||||
return KernelResult.InvalidCapability;
|
||||
}
|
||||
else if (Code == 0)
|
||||
else if (code == 0)
|
||||
{
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
int CodeMask = 1 << (32 - BitUtils.CountLeadingZeros32(Code + 1));
|
||||
int codeMask = 1 << (32 - BitUtils.CountLeadingZeros32(code + 1));
|
||||
|
||||
//Check if the property was already set.
|
||||
if (((Mask0 & CodeMask) & 0x1e008) != 0)
|
||||
if (((mask0 & codeMask) & 0x1e008) != 0)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
Mask0 |= CodeMask;
|
||||
mask0 |= codeMask;
|
||||
|
||||
switch (Code)
|
||||
switch (code)
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
@ -145,65 +145,65 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return KernelResult.InvalidCapability;
|
||||
}
|
||||
|
||||
int LowestCpuCore = (Cap >> 16) & 0xff;
|
||||
int HighestCpuCore = (Cap >> 24) & 0xff;
|
||||
int lowestCpuCore = (cap >> 16) & 0xff;
|
||||
int highestCpuCore = (cap >> 24) & 0xff;
|
||||
|
||||
if (LowestCpuCore > HighestCpuCore)
|
||||
if (lowestCpuCore > highestCpuCore)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
int HighestThreadPrio = (Cap >> 4) & 0x3f;
|
||||
int LowestThreadPrio = (Cap >> 10) & 0x3f;
|
||||
int highestThreadPrio = (cap >> 4) & 0x3f;
|
||||
int lowestThreadPrio = (cap >> 10) & 0x3f;
|
||||
|
||||
if (LowestThreadPrio > HighestThreadPrio)
|
||||
if (lowestThreadPrio > highestThreadPrio)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if (HighestCpuCore >= KScheduler.CpuCoresCount)
|
||||
if (highestCpuCore >= KScheduler.CpuCoresCount)
|
||||
{
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
|
||||
AllowedCpuCoresMask = GetMaskFromMinMax(LowestCpuCore, HighestCpuCore);
|
||||
AllowedThreadPriosMask = GetMaskFromMinMax(LowestThreadPrio, HighestThreadPrio);
|
||||
AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore);
|
||||
AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x10:
|
||||
{
|
||||
int Slot = (Cap >> 29) & 7;
|
||||
int slot = (cap >> 29) & 7;
|
||||
|
||||
int SvcSlotMask = 1 << Slot;
|
||||
int svcSlotMask = 1 << slot;
|
||||
|
||||
if ((Mask1 & SvcSlotMask) != 0)
|
||||
if ((mask1 & svcSlotMask) != 0)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
Mask1 |= SvcSlotMask;
|
||||
mask1 |= svcSlotMask;
|
||||
|
||||
int SvcMask = (Cap >> 5) & 0xffffff;
|
||||
int svcMask = (cap >> 5) & 0xffffff;
|
||||
|
||||
int BaseSvc = Slot * 24;
|
||||
int baseSvc = slot * 24;
|
||||
|
||||
for (int Index = 0; Index < 24; Index++)
|
||||
for (int index = 0; index < 24; index++)
|
||||
{
|
||||
if (((SvcMask >> Index) & 1) == 0)
|
||||
if (((svcMask >> index) & 1) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int SvcId = BaseSvc + Index;
|
||||
int svcId = baseSvc + index;
|
||||
|
||||
if (SvcId > 0x7f)
|
||||
if (svcId > 0x7f)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
SvcAccessMask[SvcId / 8] |= (byte)(1 << (SvcId & 7));
|
||||
SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -211,9 +211,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
case 0x80:
|
||||
{
|
||||
long Address = ((long)(uint)Cap << 4) & 0xffffff000;
|
||||
long address = ((long)(uint)cap << 4) & 0xffffff000;
|
||||
|
||||
MemoryManager.MapIoMemory(Address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -221,17 +221,17 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
case 0x800:
|
||||
{
|
||||
//TODO: GIC distributor check.
|
||||
int Irq0 = (Cap >> 12) & 0x3ff;
|
||||
int Irq1 = (Cap >> 22) & 0x3ff;
|
||||
int irq0 = (cap >> 12) & 0x3ff;
|
||||
int irq1 = (cap >> 22) & 0x3ff;
|
||||
|
||||
if (Irq0 != 0x3ff)
|
||||
if (irq0 != 0x3ff)
|
||||
{
|
||||
IrqAccessMask[Irq0 / 8] |= (byte)(1 << (Irq0 & 7));
|
||||
IrqAccessMask[irq0 / 8] |= (byte)(1 << (irq0 & 7));
|
||||
}
|
||||
|
||||
if (Irq1 != 0x3ff)
|
||||
if (irq1 != 0x3ff)
|
||||
{
|
||||
IrqAccessMask[Irq1 / 8] |= (byte)(1 << (Irq1 & 7));
|
||||
IrqAccessMask[irq1 / 8] |= (byte)(1 << (irq1 & 7));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -239,14 +239,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
case 0x2000:
|
||||
{
|
||||
int ApplicationType = Cap >> 14;
|
||||
int applicationType = cap >> 14;
|
||||
|
||||
if ((uint)ApplicationType > 7)
|
||||
if ((uint)applicationType > 7)
|
||||
{
|
||||
return KernelResult.ReservedValue;
|
||||
}
|
||||
|
||||
this.ApplicationType = ApplicationType;
|
||||
ApplicationType = applicationType;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -254,41 +254,41 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
case 0x4000:
|
||||
{
|
||||
//Note: This check is bugged on kernel too, we are just replicating the bug here.
|
||||
if ((KernelReleaseVersion >> 17) != 0 || Cap < 0x80000)
|
||||
if ((KernelReleaseVersion >> 17) != 0 || cap < 0x80000)
|
||||
{
|
||||
return KernelResult.ReservedValue;
|
||||
}
|
||||
|
||||
KernelReleaseVersion = Cap;
|
||||
KernelReleaseVersion = cap;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8000:
|
||||
{
|
||||
int HandleTableSize = Cap >> 26;
|
||||
int handleTableSize = cap >> 26;
|
||||
|
||||
if ((uint)HandleTableSize > 0x3ff)
|
||||
if ((uint)handleTableSize > 0x3ff)
|
||||
{
|
||||
return KernelResult.ReservedValue;
|
||||
}
|
||||
|
||||
this.HandleTableSize = HandleTableSize;
|
||||
HandleTableSize = handleTableSize;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x10000:
|
||||
{
|
||||
int DebuggingFlags = Cap >> 19;
|
||||
int debuggingFlags = cap >> 19;
|
||||
|
||||
if ((uint)DebuggingFlags > 3)
|
||||
if ((uint)debuggingFlags > 3)
|
||||
{
|
||||
return KernelResult.ReservedValue;
|
||||
}
|
||||
|
||||
this.DebuggingFlags &= ~3;
|
||||
this.DebuggingFlags |= DebuggingFlags;
|
||||
DebuggingFlags &= ~3;
|
||||
DebuggingFlags |= debuggingFlags;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -299,13 +299,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
private static long GetMaskFromMinMax(int Min, int Max)
|
||||
private static long GetMaskFromMinMax(int min, int max)
|
||||
{
|
||||
int Range = Max - Min + 1;
|
||||
int range = max - min + 1;
|
||||
|
||||
long Mask = (1L << Range) - 1;
|
||||
long mask = (1L << range) - 1;
|
||||
|
||||
return Mask << Min;
|
||||
return mask << min;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,22 +2,22 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KReadableEvent : KSynchronizationObject
|
||||
{
|
||||
private KEvent Parent;
|
||||
private KEvent _parent;
|
||||
|
||||
private bool Signaled;
|
||||
private bool _signaled;
|
||||
|
||||
public KReadableEvent(Horizon System, KEvent Parent) : base(System)
|
||||
public KReadableEvent(Horizon system, KEvent parent) : base(system)
|
||||
{
|
||||
this.Parent = Parent;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public override void Signal()
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
if (!Signaled)
|
||||
if (!_signaled)
|
||||
{
|
||||
Signaled = true;
|
||||
_signaled = true;
|
||||
|
||||
base.Signal();
|
||||
}
|
||||
@ -27,36 +27,36 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
public KernelResult Clear()
|
||||
{
|
||||
Signaled = false;
|
||||
_signaled = false;
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult ClearIfSignaled()
|
||||
{
|
||||
KernelResult Result;
|
||||
KernelResult result;
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
|
||||
if (Signaled)
|
||||
if (_signaled)
|
||||
{
|
||||
Signaled = false;
|
||||
_signaled = false;
|
||||
|
||||
Result = KernelResult.Success;
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = KernelResult.InvalidState;
|
||||
result = KernelResult.InvalidState;
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public override bool IsSignaled()
|
||||
{
|
||||
return Signaled;
|
||||
return _signaled;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,127 +7,127 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private const int Time10SecondsMs = 10000;
|
||||
|
||||
private long[] Current;
|
||||
private long[] Limit;
|
||||
private long[] Available;
|
||||
private long[] _current;
|
||||
private long[] _limit;
|
||||
private long[] _available;
|
||||
|
||||
private object LockObj;
|
||||
private object _lockObj;
|
||||
|
||||
private LinkedList<KThread> WaitingThreads;
|
||||
private LinkedList<KThread> _waitingThreads;
|
||||
|
||||
private int WaitingThreadsCount;
|
||||
private int _waitingThreadsCount;
|
||||
|
||||
private Horizon System;
|
||||
private Horizon _system;
|
||||
|
||||
public KResourceLimit(Horizon System)
|
||||
public KResourceLimit(Horizon system)
|
||||
{
|
||||
Current = new long[(int)LimitableResource.Count];
|
||||
Limit = new long[(int)LimitableResource.Count];
|
||||
Available = new long[(int)LimitableResource.Count];
|
||||
_current = new long[(int)LimitableResource.Count];
|
||||
_limit = new long[(int)LimitableResource.Count];
|
||||
_available = new long[(int)LimitableResource.Count];
|
||||
|
||||
LockObj = new object();
|
||||
_lockObj = new object();
|
||||
|
||||
WaitingThreads = new LinkedList<KThread>();
|
||||
_waitingThreads = new LinkedList<KThread>();
|
||||
|
||||
this.System = System;
|
||||
_system = system;
|
||||
}
|
||||
|
||||
public bool Reserve(LimitableResource Resource, ulong Amount)
|
||||
public bool Reserve(LimitableResource resource, ulong amount)
|
||||
{
|
||||
return Reserve(Resource, (long)Amount);
|
||||
return Reserve(resource, (long)amount);
|
||||
}
|
||||
|
||||
public bool Reserve(LimitableResource Resource, long Amount)
|
||||
public bool Reserve(LimitableResource resource, long amount)
|
||||
{
|
||||
return Reserve(Resource, Amount, KTimeManager.ConvertMillisecondsToNanoseconds(Time10SecondsMs));
|
||||
return Reserve(resource, amount, KTimeManager.ConvertMillisecondsToNanoseconds(Time10SecondsMs));
|
||||
}
|
||||
|
||||
public bool Reserve(LimitableResource Resource, long Amount, long Timeout)
|
||||
public bool Reserve(LimitableResource resource, long amount, long timeout)
|
||||
{
|
||||
long EndTimePoint = KTimeManager.ConvertNanosecondsToMilliseconds(Timeout);
|
||||
long endTimePoint = KTimeManager.ConvertNanosecondsToMilliseconds(timeout);
|
||||
|
||||
EndTimePoint += PerformanceCounter.ElapsedMilliseconds;
|
||||
endTimePoint += PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
bool Success = false;
|
||||
bool success = false;
|
||||
|
||||
int Index = GetIndex(Resource);
|
||||
int index = GetIndex(resource);
|
||||
|
||||
lock (LockObj)
|
||||
lock (_lockObj)
|
||||
{
|
||||
long NewCurrent = Current[Index] + Amount;
|
||||
long newCurrent = _current[index] + amount;
|
||||
|
||||
while (NewCurrent > Limit[Index] && Available[Index] + Amount <= Limit[Index])
|
||||
while (newCurrent > _limit[index] && _available[index] + amount <= _limit[index])
|
||||
{
|
||||
WaitingThreadsCount++;
|
||||
_waitingThreadsCount++;
|
||||
|
||||
KConditionVariable.Wait(System, WaitingThreads, LockObj, Timeout);
|
||||
KConditionVariable.Wait(_system, _waitingThreads, _lockObj, timeout);
|
||||
|
||||
WaitingThreadsCount--;
|
||||
_waitingThreadsCount--;
|
||||
|
||||
NewCurrent = Current[Index] + Amount;
|
||||
newCurrent = _current[index] + amount;
|
||||
|
||||
if (Timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > EndTimePoint)
|
||||
if (timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > endTimePoint)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewCurrent <= Limit[Index])
|
||||
if (newCurrent <= _limit[index])
|
||||
{
|
||||
Current[Index] = NewCurrent;
|
||||
_current[index] = newCurrent;
|
||||
|
||||
Success = true;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
return success;
|
||||
}
|
||||
|
||||
public void Release(LimitableResource Resource, ulong Amount)
|
||||
public void Release(LimitableResource resource, ulong amount)
|
||||
{
|
||||
Release(Resource, (long)Amount);
|
||||
Release(resource, (long)amount);
|
||||
}
|
||||
|
||||
public void Release(LimitableResource Resource, long Amount)
|
||||
public void Release(LimitableResource resource, long amount)
|
||||
{
|
||||
Release(Resource, Amount, Amount);
|
||||
Release(resource, amount, amount);
|
||||
}
|
||||
|
||||
private void Release(LimitableResource Resource, long UsedAmount, long AvailableAmount)
|
||||
private void Release(LimitableResource resource, long usedAmount, long availableAmount)
|
||||
{
|
||||
int Index = GetIndex(Resource);
|
||||
int index = GetIndex(resource);
|
||||
|
||||
lock (LockObj)
|
||||
lock (_lockObj)
|
||||
{
|
||||
Current [Index] -= UsedAmount;
|
||||
Available[Index] -= AvailableAmount;
|
||||
_current [index] -= usedAmount;
|
||||
_available[index] -= availableAmount;
|
||||
|
||||
if (WaitingThreadsCount > 0)
|
||||
if (_waitingThreadsCount > 0)
|
||||
{
|
||||
KConditionVariable.NotifyAll(System, WaitingThreads);
|
||||
KConditionVariable.NotifyAll(_system, _waitingThreads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long GetRemainingValue(LimitableResource Resource)
|
||||
public long GetRemainingValue(LimitableResource resource)
|
||||
{
|
||||
int Index = GetIndex(Resource);
|
||||
int index = GetIndex(resource);
|
||||
|
||||
lock (LockObj)
|
||||
lock (_lockObj)
|
||||
{
|
||||
return Limit[Index] - Current[Index];
|
||||
return _limit[index] - _current[index];
|
||||
}
|
||||
}
|
||||
|
||||
public KernelResult SetLimitValue(LimitableResource Resource, long Limit)
|
||||
public KernelResult SetLimitValue(LimitableResource resource, long limit)
|
||||
{
|
||||
int Index = GetIndex(Resource);
|
||||
int index = GetIndex(resource);
|
||||
|
||||
lock (LockObj)
|
||||
lock (_lockObj)
|
||||
{
|
||||
if (Current[Index] <= Limit)
|
||||
if (_current[index] <= limit)
|
||||
{
|
||||
this.Limit[Index] = Limit;
|
||||
_limit[index] = limit;
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
@ -138,9 +138,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetIndex(LimitableResource Resource)
|
||||
private static int GetIndex(LimitableResource resource)
|
||||
{
|
||||
return (int)Resource;
|
||||
return (int)resource;
|
||||
}
|
||||
}
|
||||
}
|
@ -12,17 +12,17 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
private const int PreemptionPriorityCores012 = 59;
|
||||
private const int PreemptionPriorityCore3 = 63;
|
||||
|
||||
private Horizon System;
|
||||
private Horizon _system;
|
||||
|
||||
public KSchedulingData SchedulingData { get; private set; }
|
||||
public KSchedulingData SchedulingData { get; }
|
||||
|
||||
public KCoreContext[] CoreContexts { get; private set; }
|
||||
public KCoreContext[] CoreContexts { get; }
|
||||
|
||||
public bool ThreadReselectionRequested { get; set; }
|
||||
|
||||
public KScheduler(Horizon System)
|
||||
public KScheduler(Horizon system)
|
||||
{
|
||||
this.System = System;
|
||||
_system = system;
|
||||
|
||||
SchedulingData = new KSchedulingData();
|
||||
|
||||
@ -30,87 +30,87 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
CoreContexts = new KCoreContext[CpuCoresCount];
|
||||
|
||||
for (int Core = 0; Core < CpuCoresCount; Core++)
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
CoreContexts[Core] = new KCoreContext(this, CoreManager);
|
||||
CoreContexts[core] = new KCoreContext(this, CoreManager);
|
||||
}
|
||||
}
|
||||
|
||||
private void PreemptThreads()
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
PreemptThread(PreemptionPriorityCores012, 0);
|
||||
PreemptThread(PreemptionPriorityCores012, 1);
|
||||
PreemptThread(PreemptionPriorityCores012, 2);
|
||||
PreemptThread(PreemptionPriorityCore3, 3);
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
private void PreemptThread(int Prio, int Core)
|
||||
private void PreemptThread(int prio, int core)
|
||||
{
|
||||
IEnumerable<KThread> ScheduledThreads = SchedulingData.ScheduledThreads(Core);
|
||||
IEnumerable<KThread> scheduledThreads = SchedulingData.ScheduledThreads(core);
|
||||
|
||||
KThread SelectedThread = ScheduledThreads.FirstOrDefault(x => x.DynamicPriority == Prio);
|
||||
KThread selectedThread = scheduledThreads.FirstOrDefault(x => x.DynamicPriority == prio);
|
||||
|
||||
//Yield priority queue.
|
||||
if (SelectedThread != null)
|
||||
if (selectedThread != null)
|
||||
{
|
||||
SchedulingData.Reschedule(Prio, Core, SelectedThread);
|
||||
SchedulingData.Reschedule(prio, core, selectedThread);
|
||||
}
|
||||
|
||||
IEnumerable<KThread> SuitableCandidates()
|
||||
{
|
||||
foreach (KThread Thread in SchedulingData.SuggestedThreads(Core))
|
||||
foreach (KThread thread in SchedulingData.SuggestedThreads(core))
|
||||
{
|
||||
int SrcCore = Thread.CurrentCore;
|
||||
int srcCore = thread.CurrentCore;
|
||||
|
||||
if (SrcCore >= 0)
|
||||
if (srcCore >= 0)
|
||||
{
|
||||
KThread HighestPrioSrcCore = SchedulingData.ScheduledThreads(SrcCore).FirstOrDefault();
|
||||
KThread highestPrioSrcCore = SchedulingData.ScheduledThreads(srcCore).FirstOrDefault();
|
||||
|
||||
if (HighestPrioSrcCore != null && HighestPrioSrcCore.DynamicPriority < 2)
|
||||
if (highestPrioSrcCore != null && highestPrioSrcCore.DynamicPriority < 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (HighestPrioSrcCore == Thread)
|
||||
if (highestPrioSrcCore == thread)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//If the candidate was scheduled after the current thread, then it's not worth it.
|
||||
if (SelectedThread == null || SelectedThread.LastScheduledTime >= Thread.LastScheduledTime)
|
||||
if (selectedThread == null || selectedThread.LastScheduledTime >= thread.LastScheduledTime)
|
||||
{
|
||||
yield return Thread;
|
||||
yield return thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Select candidate threads that could run on this core.
|
||||
//Only take into account threads that are not yet selected.
|
||||
KThread Dst = SuitableCandidates().FirstOrDefault(x => x.DynamicPriority == Prio);
|
||||
KThread dst = SuitableCandidates().FirstOrDefault(x => x.DynamicPriority == prio);
|
||||
|
||||
if (Dst != null)
|
||||
if (dst != null)
|
||||
{
|
||||
SchedulingData.TransferToCore(Prio, Core, Dst);
|
||||
SchedulingData.TransferToCore(prio, core, dst);
|
||||
|
||||
SelectedThread = Dst;
|
||||
selectedThread = dst;
|
||||
}
|
||||
|
||||
//If the priority of the currently selected thread is lower than preemption priority,
|
||||
//then allow threads with lower priorities to be selected aswell.
|
||||
if (SelectedThread != null && SelectedThread.DynamicPriority > Prio)
|
||||
if (selectedThread != null && selectedThread.DynamicPriority > prio)
|
||||
{
|
||||
Func<KThread, bool> Predicate = x => x.DynamicPriority >= SelectedThread.DynamicPriority;
|
||||
Func<KThread, bool> predicate = x => x.DynamicPriority >= selectedThread.DynamicPriority;
|
||||
|
||||
Dst = SuitableCandidates().FirstOrDefault(Predicate);
|
||||
dst = SuitableCandidates().FirstOrDefault(predicate);
|
||||
|
||||
if (Dst != null)
|
||||
if (dst != null)
|
||||
{
|
||||
SchedulingData.TransferToCore(Dst.DynamicPriority, Core, Dst);
|
||||
SchedulingData.TransferToCore(dst.DynamicPriority, core, dst);
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,52 +121,52 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
ThreadReselectionRequested = false;
|
||||
|
||||
for (int Core = 0; Core < CpuCoresCount; Core++)
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
KThread Thread = SchedulingData.ScheduledThreads(Core).FirstOrDefault();
|
||||
KThread thread = SchedulingData.ScheduledThreads(core).FirstOrDefault();
|
||||
|
||||
CoreContexts[Core].SelectThread(Thread);
|
||||
CoreContexts[core].SelectThread(thread);
|
||||
}
|
||||
|
||||
for (int Core = 0; Core < CpuCoresCount; Core++)
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
//If the core is not idle (there's already a thread running on it),
|
||||
//then we don't need to attempt load balancing.
|
||||
if (SchedulingData.ScheduledThreads(Core).Any())
|
||||
if (SchedulingData.ScheduledThreads(core).Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int[] SrcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
int[] srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
|
||||
int SrcCoresHighestPrioThreadsCount = 0;
|
||||
int srcCoresHighestPrioThreadsCount = 0;
|
||||
|
||||
KThread Dst = null;
|
||||
KThread dst = null;
|
||||
|
||||
//Select candidate threads that could run on this core.
|
||||
//Give preference to threads that are not yet selected.
|
||||
foreach (KThread Thread in SchedulingData.SuggestedThreads(Core))
|
||||
foreach (KThread thread in SchedulingData.SuggestedThreads(core))
|
||||
{
|
||||
if (Thread.CurrentCore < 0 || Thread != CoreContexts[Thread.CurrentCore].SelectedThread)
|
||||
if (thread.CurrentCore < 0 || thread != CoreContexts[thread.CurrentCore].SelectedThread)
|
||||
{
|
||||
Dst = Thread;
|
||||
dst = thread;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SrcCoresHighestPrioThreads[SrcCoresHighestPrioThreadsCount++] = Thread.CurrentCore;
|
||||
srcCoresHighestPrioThreads[srcCoresHighestPrioThreadsCount++] = thread.CurrentCore;
|
||||
}
|
||||
|
||||
//Not yet selected candidate found.
|
||||
if (Dst != null)
|
||||
if (dst != null)
|
||||
{
|
||||
//Priorities < 2 are used for the kernel message dispatching
|
||||
//threads, we should skip load balancing entirely.
|
||||
if (Dst.DynamicPriority >= 2)
|
||||
if (dst.DynamicPriority >= 2)
|
||||
{
|
||||
SchedulingData.TransferToCore(Dst.DynamicPriority, Core, Dst);
|
||||
SchedulingData.TransferToCore(dst.DynamicPriority, core, dst);
|
||||
|
||||
CoreContexts[Core].SelectThread(Dst);
|
||||
CoreContexts[core].SelectThread(dst);
|
||||
}
|
||||
|
||||
continue;
|
||||
@ -174,23 +174,23 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
//All candiates are already selected, choose the best one
|
||||
//(the first one that doesn't make the source core idle if moved).
|
||||
for (int Index = 0; Index < SrcCoresHighestPrioThreadsCount; Index++)
|
||||
for (int index = 0; index < srcCoresHighestPrioThreadsCount; index++)
|
||||
{
|
||||
int SrcCore = SrcCoresHighestPrioThreads[Index];
|
||||
int srcCore = srcCoresHighestPrioThreads[index];
|
||||
|
||||
KThread Src = SchedulingData.ScheduledThreads(SrcCore).ElementAtOrDefault(1);
|
||||
KThread src = SchedulingData.ScheduledThreads(srcCore).ElementAtOrDefault(1);
|
||||
|
||||
if (Src != null)
|
||||
if (src != null)
|
||||
{
|
||||
//Run the second thread on the queue on the source core,
|
||||
//move the first one to the current core.
|
||||
KThread OrigSelectedCoreSrc = CoreContexts[SrcCore].SelectedThread;
|
||||
KThread origSelectedCoreSrc = CoreContexts[srcCore].SelectedThread;
|
||||
|
||||
CoreContexts[SrcCore].SelectThread(Src);
|
||||
CoreContexts[srcCore].SelectThread(src);
|
||||
|
||||
SchedulingData.TransferToCore(OrigSelectedCoreSrc.DynamicPriority, Core, OrigSelectedCoreSrc);
|
||||
SchedulingData.TransferToCore(origSelectedCoreSrc.DynamicPriority, core, origSelectedCoreSrc);
|
||||
|
||||
CoreContexts[Core].SelectThread(OrigSelectedCoreSrc);
|
||||
CoreContexts[core].SelectThread(origSelectedCoreSrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -200,11 +200,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
lock (CoreContexts)
|
||||
{
|
||||
for (int Core = 0; Core < CpuCoresCount; Core++)
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
if (CoreContexts[Core].CurrentThread?.Context.IsCurrentThread() ?? false)
|
||||
if (CoreContexts[core].CurrentThread?.Context.IsCurrentThread() ?? false)
|
||||
{
|
||||
return CoreContexts[Core].CurrentThread;
|
||||
return CoreContexts[core].CurrentThread;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,11 +222,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposing)
|
||||
if (disposing)
|
||||
{
|
||||
KeepPreempting = false;
|
||||
_keepPreempting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,204 +4,204 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KSchedulingData
|
||||
{
|
||||
private LinkedList<KThread>[][] ScheduledThreadsPerPrioPerCore;
|
||||
private LinkedList<KThread>[][] SuggestedThreadsPerPrioPerCore;
|
||||
private LinkedList<KThread>[][] _scheduledThreadsPerPrioPerCore;
|
||||
private LinkedList<KThread>[][] _suggestedThreadsPerPrioPerCore;
|
||||
|
||||
private long[] ScheduledPrioritiesPerCore;
|
||||
private long[] SuggestedPrioritiesPerCore;
|
||||
private long[] _scheduledPrioritiesPerCore;
|
||||
private long[] _suggestedPrioritiesPerCore;
|
||||
|
||||
public KSchedulingData()
|
||||
{
|
||||
SuggestedThreadsPerPrioPerCore = new LinkedList<KThread>[KScheduler.PrioritiesCount][];
|
||||
ScheduledThreadsPerPrioPerCore = new LinkedList<KThread>[KScheduler.PrioritiesCount][];
|
||||
_suggestedThreadsPerPrioPerCore = new LinkedList<KThread>[KScheduler.PrioritiesCount][];
|
||||
_scheduledThreadsPerPrioPerCore = new LinkedList<KThread>[KScheduler.PrioritiesCount][];
|
||||
|
||||
for (int Prio = 0; Prio < KScheduler.PrioritiesCount; Prio++)
|
||||
for (int prio = 0; prio < KScheduler.PrioritiesCount; prio++)
|
||||
{
|
||||
SuggestedThreadsPerPrioPerCore[Prio] = new LinkedList<KThread>[KScheduler.CpuCoresCount];
|
||||
ScheduledThreadsPerPrioPerCore[Prio] = new LinkedList<KThread>[KScheduler.CpuCoresCount];
|
||||
_suggestedThreadsPerPrioPerCore[prio] = new LinkedList<KThread>[KScheduler.CpuCoresCount];
|
||||
_scheduledThreadsPerPrioPerCore[prio] = new LinkedList<KThread>[KScheduler.CpuCoresCount];
|
||||
|
||||
for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
|
||||
for (int core = 0; core < KScheduler.CpuCoresCount; core++)
|
||||
{
|
||||
SuggestedThreadsPerPrioPerCore[Prio][Core] = new LinkedList<KThread>();
|
||||
ScheduledThreadsPerPrioPerCore[Prio][Core] = new LinkedList<KThread>();
|
||||
_suggestedThreadsPerPrioPerCore[prio][core] = new LinkedList<KThread>();
|
||||
_scheduledThreadsPerPrioPerCore[prio][core] = new LinkedList<KThread>();
|
||||
}
|
||||
}
|
||||
|
||||
ScheduledPrioritiesPerCore = new long[KScheduler.CpuCoresCount];
|
||||
SuggestedPrioritiesPerCore = new long[KScheduler.CpuCoresCount];
|
||||
_scheduledPrioritiesPerCore = new long[KScheduler.CpuCoresCount];
|
||||
_suggestedPrioritiesPerCore = new long[KScheduler.CpuCoresCount];
|
||||
}
|
||||
|
||||
public IEnumerable<KThread> SuggestedThreads(int Core)
|
||||
public IEnumerable<KThread> SuggestedThreads(int core)
|
||||
{
|
||||
return Iterate(SuggestedThreadsPerPrioPerCore, SuggestedPrioritiesPerCore, Core);
|
||||
return Iterate(_suggestedThreadsPerPrioPerCore, _suggestedPrioritiesPerCore, core);
|
||||
}
|
||||
|
||||
public IEnumerable<KThread> ScheduledThreads(int Core)
|
||||
public IEnumerable<KThread> ScheduledThreads(int core)
|
||||
{
|
||||
return Iterate(ScheduledThreadsPerPrioPerCore, ScheduledPrioritiesPerCore, Core);
|
||||
return Iterate(_scheduledThreadsPerPrioPerCore, _scheduledPrioritiesPerCore, core);
|
||||
}
|
||||
|
||||
private IEnumerable<KThread> Iterate(LinkedList<KThread>[][] ListPerPrioPerCore, long[] Prios, int Core)
|
||||
private IEnumerable<KThread> Iterate(LinkedList<KThread>[][] listPerPrioPerCore, long[] prios, int core)
|
||||
{
|
||||
long PrioMask = Prios[Core];
|
||||
long prioMask = prios[core];
|
||||
|
||||
int Prio = CountTrailingZeros(PrioMask);
|
||||
int prio = CountTrailingZeros(prioMask);
|
||||
|
||||
PrioMask &= ~(1L << Prio);
|
||||
prioMask &= ~(1L << prio);
|
||||
|
||||
while (Prio < KScheduler.PrioritiesCount)
|
||||
while (prio < KScheduler.PrioritiesCount)
|
||||
{
|
||||
LinkedList<KThread> List = ListPerPrioPerCore[Prio][Core];
|
||||
LinkedList<KThread> list = listPerPrioPerCore[prio][core];
|
||||
|
||||
LinkedListNode<KThread> Node = List.First;
|
||||
LinkedListNode<KThread> node = list.First;
|
||||
|
||||
while (Node != null)
|
||||
while (node != null)
|
||||
{
|
||||
yield return Node.Value;
|
||||
yield return node.Value;
|
||||
|
||||
Node = Node.Next;
|
||||
node = node.Next;
|
||||
}
|
||||
|
||||
Prio = CountTrailingZeros(PrioMask);
|
||||
prio = CountTrailingZeros(prioMask);
|
||||
|
||||
PrioMask &= ~(1L << Prio);
|
||||
prioMask &= ~(1L << prio);
|
||||
}
|
||||
}
|
||||
|
||||
private int CountTrailingZeros(long Value)
|
||||
private int CountTrailingZeros(long value)
|
||||
{
|
||||
int Count = 0;
|
||||
int count = 0;
|
||||
|
||||
while (((Value >> Count) & 0xf) == 0 && Count < 64)
|
||||
while (((value >> count) & 0xf) == 0 && count < 64)
|
||||
{
|
||||
Count += 4;
|
||||
count += 4;
|
||||
}
|
||||
|
||||
while (((Value >> Count) & 1) == 0 && Count < 64)
|
||||
while (((value >> count) & 1) == 0 && count < 64)
|
||||
{
|
||||
Count++;
|
||||
count++;
|
||||
}
|
||||
|
||||
return Count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public void TransferToCore(int Prio, int DstCore, KThread Thread)
|
||||
public void TransferToCore(int prio, int dstCore, KThread thread)
|
||||
{
|
||||
bool Schedulable = Thread.DynamicPriority < KScheduler.PrioritiesCount;
|
||||
bool schedulable = thread.DynamicPriority < KScheduler.PrioritiesCount;
|
||||
|
||||
int SrcCore = Thread.CurrentCore;
|
||||
int srcCore = thread.CurrentCore;
|
||||
|
||||
Thread.CurrentCore = DstCore;
|
||||
thread.CurrentCore = dstCore;
|
||||
|
||||
if (SrcCore == DstCore || !Schedulable)
|
||||
if (srcCore == dstCore || !schedulable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SrcCore >= 0)
|
||||
if (srcCore >= 0)
|
||||
{
|
||||
Unschedule(Prio, SrcCore, Thread);
|
||||
Unschedule(prio, srcCore, thread);
|
||||
}
|
||||
|
||||
if (DstCore >= 0)
|
||||
if (dstCore >= 0)
|
||||
{
|
||||
Unsuggest(Prio, DstCore, Thread);
|
||||
Schedule(Prio, DstCore, Thread);
|
||||
Unsuggest(prio, dstCore, thread);
|
||||
Schedule(prio, dstCore, thread);
|
||||
}
|
||||
|
||||
if (SrcCore >= 0)
|
||||
if (srcCore >= 0)
|
||||
{
|
||||
Suggest(Prio, SrcCore, Thread);
|
||||
Suggest(prio, srcCore, thread);
|
||||
}
|
||||
}
|
||||
|
||||
public void Suggest(int Prio, int Core, KThread Thread)
|
||||
public void Suggest(int prio, int core, KThread thread)
|
||||
{
|
||||
if (Prio >= KScheduler.PrioritiesCount)
|
||||
if (prio >= KScheduler.PrioritiesCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.SiblingsPerCore[Core] = SuggestedQueue(Prio, Core).AddFirst(Thread);
|
||||
thread.SiblingsPerCore[core] = SuggestedQueue(prio, core).AddFirst(thread);
|
||||
|
||||
SuggestedPrioritiesPerCore[Core] |= 1L << Prio;
|
||||
_suggestedPrioritiesPerCore[core] |= 1L << prio;
|
||||
}
|
||||
|
||||
public void Unsuggest(int Prio, int Core, KThread Thread)
|
||||
public void Unsuggest(int prio, int core, KThread thread)
|
||||
{
|
||||
if (Prio >= KScheduler.PrioritiesCount)
|
||||
if (prio >= KScheduler.PrioritiesCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedList<KThread> Queue = SuggestedQueue(Prio, Core);
|
||||
LinkedList<KThread> queue = SuggestedQueue(prio, core);
|
||||
|
||||
Queue.Remove(Thread.SiblingsPerCore[Core]);
|
||||
queue.Remove(thread.SiblingsPerCore[core]);
|
||||
|
||||
if (Queue.First == null)
|
||||
if (queue.First == null)
|
||||
{
|
||||
SuggestedPrioritiesPerCore[Core] &= ~(1L << Prio);
|
||||
_suggestedPrioritiesPerCore[core] &= ~(1L << prio);
|
||||
}
|
||||
}
|
||||
|
||||
public void Schedule(int Prio, int Core, KThread Thread)
|
||||
public void Schedule(int prio, int core, KThread thread)
|
||||
{
|
||||
if (Prio >= KScheduler.PrioritiesCount)
|
||||
if (prio >= KScheduler.PrioritiesCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.SiblingsPerCore[Core] = ScheduledQueue(Prio, Core).AddLast(Thread);
|
||||
thread.SiblingsPerCore[core] = ScheduledQueue(prio, core).AddLast(thread);
|
||||
|
||||
ScheduledPrioritiesPerCore[Core] |= 1L << Prio;
|
||||
_scheduledPrioritiesPerCore[core] |= 1L << prio;
|
||||
}
|
||||
|
||||
public void SchedulePrepend(int Prio, int Core, KThread Thread)
|
||||
public void SchedulePrepend(int prio, int core, KThread thread)
|
||||
{
|
||||
if (Prio >= KScheduler.PrioritiesCount)
|
||||
if (prio >= KScheduler.PrioritiesCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.SiblingsPerCore[Core] = ScheduledQueue(Prio, Core).AddFirst(Thread);
|
||||
thread.SiblingsPerCore[core] = ScheduledQueue(prio, core).AddFirst(thread);
|
||||
|
||||
ScheduledPrioritiesPerCore[Core] |= 1L << Prio;
|
||||
_scheduledPrioritiesPerCore[core] |= 1L << prio;
|
||||
}
|
||||
|
||||
public void Reschedule(int Prio, int Core, KThread Thread)
|
||||
public void Reschedule(int prio, int core, KThread thread)
|
||||
{
|
||||
LinkedList<KThread> Queue = ScheduledQueue(Prio, Core);
|
||||
LinkedList<KThread> queue = ScheduledQueue(prio, core);
|
||||
|
||||
Queue.Remove(Thread.SiblingsPerCore[Core]);
|
||||
queue.Remove(thread.SiblingsPerCore[core]);
|
||||
|
||||
Thread.SiblingsPerCore[Core] = Queue.AddLast(Thread);
|
||||
thread.SiblingsPerCore[core] = queue.AddLast(thread);
|
||||
}
|
||||
|
||||
public void Unschedule(int Prio, int Core, KThread Thread)
|
||||
public void Unschedule(int prio, int core, KThread thread)
|
||||
{
|
||||
if (Prio >= KScheduler.PrioritiesCount)
|
||||
if (prio >= KScheduler.PrioritiesCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedList<KThread> Queue = ScheduledQueue(Prio, Core);
|
||||
LinkedList<KThread> queue = ScheduledQueue(prio, core);
|
||||
|
||||
Queue.Remove(Thread.SiblingsPerCore[Core]);
|
||||
queue.Remove(thread.SiblingsPerCore[core]);
|
||||
|
||||
if (Queue.First == null)
|
||||
if (queue.First == null)
|
||||
{
|
||||
ScheduledPrioritiesPerCore[Core] &= ~(1L << Prio);
|
||||
_scheduledPrioritiesPerCore[core] &= ~(1L << prio);
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedList<KThread> SuggestedQueue(int Prio, int Core)
|
||||
private LinkedList<KThread> SuggestedQueue(int prio, int core)
|
||||
{
|
||||
return SuggestedThreadsPerPrioPerCore[Prio][Core];
|
||||
return _suggestedThreadsPerPrioPerCore[prio][core];
|
||||
}
|
||||
|
||||
private LinkedList<KThread> ScheduledQueue(int Prio, int Core)
|
||||
private LinkedList<KThread> ScheduledQueue(int prio, int core)
|
||||
{
|
||||
return ScheduledThreadsPerPrioPerCore[Prio][Core];
|
||||
return _scheduledThreadsPerPrioPerCore[prio][core];
|
||||
}
|
||||
}
|
||||
}
|
@ -2,13 +2,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KServerPort : KSynchronizationObject
|
||||
{
|
||||
private KPort Parent;
|
||||
private KPort _parent;
|
||||
|
||||
public KServerPort(Horizon System) : base(System) { }
|
||||
public KServerPort(Horizon system) : base(system) { }
|
||||
|
||||
public void Initialize(KPort Parent)
|
||||
public void Initialize(KPort parent)
|
||||
{
|
||||
this.Parent = Parent;
|
||||
_parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,14 +5,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KSession : IDisposable
|
||||
{
|
||||
public IpcService Service { get; private set; }
|
||||
public IpcService Service { get; }
|
||||
|
||||
public string ServiceName { get; private set; }
|
||||
public string ServiceName { get; }
|
||||
|
||||
public KSession(IpcService Service, string ServiceName)
|
||||
public KSession(IpcService service, string serviceName)
|
||||
{
|
||||
this.Service = Service;
|
||||
this.ServiceName = ServiceName;
|
||||
Service = service;
|
||||
ServiceName = serviceName;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@ -20,11 +20,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposing && Service is IDisposable DisposableService)
|
||||
if (disposing && Service is IDisposable disposableService)
|
||||
{
|
||||
DisposableService.Dispose();
|
||||
disposableService.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,65 +4,65 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KSharedMemory
|
||||
{
|
||||
private KPageList PageList;
|
||||
private KPageList _pageList;
|
||||
|
||||
private long OwnerPid;
|
||||
private long _ownerPid;
|
||||
|
||||
private MemoryPermission OwnerPermission;
|
||||
private MemoryPermission UserPermission;
|
||||
private MemoryPermission _ownerPermission;
|
||||
private MemoryPermission _userPermission;
|
||||
|
||||
public KSharedMemory(
|
||||
KPageList PageList,
|
||||
long OwnerPid,
|
||||
MemoryPermission OwnerPermission,
|
||||
MemoryPermission UserPermission)
|
||||
KPageList pageList,
|
||||
long ownerPid,
|
||||
MemoryPermission ownerPermission,
|
||||
MemoryPermission userPermission)
|
||||
{
|
||||
this.PageList = PageList;
|
||||
this.OwnerPid = OwnerPid;
|
||||
this.OwnerPermission = OwnerPermission;
|
||||
this.UserPermission = UserPermission;
|
||||
_pageList = pageList;
|
||||
_ownerPid = ownerPid;
|
||||
_ownerPermission = ownerPermission;
|
||||
_userPermission = userPermission;
|
||||
}
|
||||
|
||||
public KernelResult MapIntoProcess(
|
||||
KMemoryManager MemoryManager,
|
||||
ulong Address,
|
||||
ulong Size,
|
||||
KProcess Process,
|
||||
MemoryPermission Permission)
|
||||
KMemoryManager memoryManager,
|
||||
ulong address,
|
||||
ulong size,
|
||||
KProcess process,
|
||||
MemoryPermission permission)
|
||||
{
|
||||
ulong PagesCountRounded = BitUtils.DivRoundUp(Size, KMemoryManager.PageSize);
|
||||
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
|
||||
|
||||
if (PageList.GetPagesCount() != PagesCountRounded)
|
||||
if (_pageList.GetPagesCount() != pagesCountRounded)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
MemoryPermission ExpectedPermission = Process.Pid == OwnerPid
|
||||
? OwnerPermission
|
||||
: UserPermission;
|
||||
MemoryPermission expectedPermission = process.Pid == _ownerPid
|
||||
? _ownerPermission
|
||||
: _userPermission;
|
||||
|
||||
if (Permission != ExpectedPermission)
|
||||
if (permission != expectedPermission)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
||||
return MemoryManager.MapPages(Address, PageList, MemoryState.SharedMemory, Permission);
|
||||
return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission);
|
||||
}
|
||||
|
||||
public KernelResult UnmapFromProcess(
|
||||
KMemoryManager MemoryManager,
|
||||
ulong Address,
|
||||
ulong Size,
|
||||
KProcess Process)
|
||||
KMemoryManager memoryManager,
|
||||
ulong address,
|
||||
ulong size,
|
||||
KProcess process)
|
||||
{
|
||||
ulong PagesCountRounded = BitUtils.DivRoundUp(Size, KMemoryManager.PageSize);
|
||||
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
|
||||
|
||||
if (PageList.GetPagesCount() != PagesCountRounded)
|
||||
if (_pageList.GetPagesCount() != pagesCountRounded)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
return MemoryManager.UnmapPages(Address, PageList, MemoryState.SharedMemory);
|
||||
return memoryManager.UnmapPages(address, _pageList, MemoryState.SharedMemory);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,46 +4,46 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KSlabHeap
|
||||
{
|
||||
private LinkedList<ulong> Items;
|
||||
private LinkedList<ulong> _items;
|
||||
|
||||
public KSlabHeap(ulong Pa, ulong ItemSize, ulong Size)
|
||||
public KSlabHeap(ulong pa, ulong itemSize, ulong size)
|
||||
{
|
||||
Items = new LinkedList<ulong>();
|
||||
_items = new LinkedList<ulong>();
|
||||
|
||||
int ItemsCount = (int)(Size / ItemSize);
|
||||
int itemsCount = (int)(size / itemSize);
|
||||
|
||||
for (int Index = 0; Index < ItemsCount; Index++)
|
||||
for (int index = 0; index < itemsCount; index++)
|
||||
{
|
||||
Items.AddLast(Pa);
|
||||
_items.AddLast(pa);
|
||||
|
||||
Pa += ItemSize;
|
||||
pa += itemSize;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetItem(out ulong Pa)
|
||||
public bool TryGetItem(out ulong pa)
|
||||
{
|
||||
lock (Items)
|
||||
lock (_items)
|
||||
{
|
||||
if (Items.First != null)
|
||||
if (_items.First != null)
|
||||
{
|
||||
Pa = Items.First.Value;
|
||||
pa = _items.First.Value;
|
||||
|
||||
Items.RemoveFirst();
|
||||
_items.RemoveFirst();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Pa = 0;
|
||||
pa = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Free(ulong Pa)
|
||||
public void Free(ulong pa)
|
||||
{
|
||||
lock (Items)
|
||||
lock (_items)
|
||||
{
|
||||
Items.AddFirst(Pa);
|
||||
_items.AddFirst(pa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,130 +6,130 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KSynchronization
|
||||
{
|
||||
private Horizon System;
|
||||
private Horizon _system;
|
||||
|
||||
public KSynchronization(Horizon System)
|
||||
public KSynchronization(Horizon system)
|
||||
{
|
||||
this.System = System;
|
||||
_system = system;
|
||||
}
|
||||
|
||||
public long WaitFor(KSynchronizationObject[] SyncObjs, long Timeout, ref int HndIndex)
|
||||
public long WaitFor(KSynchronizationObject[] syncObjs, long timeout, ref int hndIndex)
|
||||
{
|
||||
long Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
long result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
//Check if objects are already signaled before waiting.
|
||||
for (int Index = 0; Index < SyncObjs.Length; Index++)
|
||||
for (int index = 0; index < syncObjs.Length; index++)
|
||||
{
|
||||
if (!SyncObjs[Index].IsSignaled())
|
||||
if (!syncObjs[index].IsSignaled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HndIndex = Index;
|
||||
hndIndex = index;
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Timeout == 0)
|
||||
if (timeout == 0)
|
||||
{
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
if (CurrentThread.ShallBeTerminated ||
|
||||
CurrentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
if (currentThread.ShallBeTerminated ||
|
||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
||||
{
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
|
||||
result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
|
||||
}
|
||||
else if (CurrentThread.SyncCancelled)
|
||||
else if (currentThread.SyncCancelled)
|
||||
{
|
||||
CurrentThread.SyncCancelled = false;
|
||||
currentThread.SyncCancelled = false;
|
||||
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled);
|
||||
result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled);
|
||||
}
|
||||
else
|
||||
{
|
||||
LinkedListNode<KThread>[] SyncNodes = new LinkedListNode<KThread>[SyncObjs.Length];
|
||||
LinkedListNode<KThread>[] syncNodes = new LinkedListNode<KThread>[syncObjs.Length];
|
||||
|
||||
for (int Index = 0; Index < SyncObjs.Length; Index++)
|
||||
for (int index = 0; index < syncObjs.Length; index++)
|
||||
{
|
||||
SyncNodes[Index] = SyncObjs[Index].AddWaitingThread(CurrentThread);
|
||||
syncNodes[index] = syncObjs[index].AddWaitingThread(currentThread);
|
||||
}
|
||||
|
||||
CurrentThread.WaitingSync = true;
|
||||
CurrentThread.SignaledObj = null;
|
||||
CurrentThread.ObjSyncResult = (int)Result;
|
||||
currentThread.WaitingSync = true;
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = (int)result;
|
||||
|
||||
CurrentThread.Reschedule(ThreadSchedState.Paused);
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout);
|
||||
_system.TimeManager.ScheduleFutureInvocation(currentThread, timeout);
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
CurrentThread.WaitingSync = false;
|
||||
currentThread.WaitingSync = false;
|
||||
|
||||
if (Timeout > 0)
|
||||
if (timeout > 0)
|
||||
{
|
||||
System.TimeManager.UnscheduleFutureInvocation(CurrentThread);
|
||||
_system.TimeManager.UnscheduleFutureInvocation(currentThread);
|
||||
}
|
||||
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
Result = (uint)CurrentThread.ObjSyncResult;
|
||||
result = (uint)currentThread.ObjSyncResult;
|
||||
|
||||
HndIndex = -1;
|
||||
hndIndex = -1;
|
||||
|
||||
for (int Index = 0; Index < SyncObjs.Length; Index++)
|
||||
for (int index = 0; index < syncObjs.Length; index++)
|
||||
{
|
||||
SyncObjs[Index].RemoveWaitingThread(SyncNodes[Index]);
|
||||
syncObjs[index].RemoveWaitingThread(syncNodes[index]);
|
||||
|
||||
if (SyncObjs[Index] == CurrentThread.SignaledObj)
|
||||
if (syncObjs[index] == currentThread.SignaledObj)
|
||||
{
|
||||
HndIndex = Index;
|
||||
hndIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SignalObject(KSynchronizationObject SyncObj)
|
||||
public void SignalObject(KSynchronizationObject syncObj)
|
||||
{
|
||||
System.CriticalSection.Enter();
|
||||
_system.CriticalSection.Enter();
|
||||
|
||||
if (SyncObj.IsSignaled())
|
||||
if (syncObj.IsSignaled())
|
||||
{
|
||||
LinkedListNode<KThread> Node = SyncObj.WaitingThreads.First;
|
||||
LinkedListNode<KThread> node = syncObj.WaitingThreads.First;
|
||||
|
||||
while (Node != null)
|
||||
while (node != null)
|
||||
{
|
||||
KThread Thread = Node.Value;
|
||||
KThread thread = node.Value;
|
||||
|
||||
if ((Thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
|
||||
if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
|
||||
{
|
||||
Thread.SignaledObj = SyncObj;
|
||||
Thread.ObjSyncResult = 0;
|
||||
thread.SignaledObj = syncObj;
|
||||
thread.ObjSyncResult = 0;
|
||||
|
||||
Thread.Reschedule(ThreadSchedState.Running);
|
||||
thread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
Node = Node.Next;
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
|
||||
System.CriticalSection.Leave();
|
||||
_system.CriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
}
|
@ -6,19 +6,19 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
public LinkedList<KThread> WaitingThreads;
|
||||
|
||||
public KSynchronizationObject(Horizon System) : base(System)
|
||||
public KSynchronizationObject(Horizon system) : base(system)
|
||||
{
|
||||
WaitingThreads = new LinkedList<KThread>();
|
||||
}
|
||||
|
||||
public LinkedListNode<KThread> AddWaitingThread(KThread Thread)
|
||||
public LinkedListNode<KThread> AddWaitingThread(KThread thread)
|
||||
{
|
||||
return WaitingThreads.AddLast(Thread);
|
||||
return WaitingThreads.AddLast(thread);
|
||||
}
|
||||
|
||||
public void RemoveWaitingThread(LinkedListNode<KThread> Node)
|
||||
public void RemoveWaitingThread(LinkedListNode<KThread> node)
|
||||
{
|
||||
WaitingThreads.Remove(Node);
|
||||
WaitingThreads.Remove(node);
|
||||
}
|
||||
|
||||
public virtual void Signal()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,116 +10,116 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private class WaitingObject
|
||||
{
|
||||
public IKFutureSchedulerObject Object { get; private set; }
|
||||
public IKFutureSchedulerObject Object { get; }
|
||||
|
||||
public long TimePoint { get; private set; }
|
||||
public long TimePoint { get; }
|
||||
|
||||
public WaitingObject(IKFutureSchedulerObject Object, long TimePoint)
|
||||
public WaitingObject(IKFutureSchedulerObject schedulerObj, long timePoint)
|
||||
{
|
||||
this.Object = Object;
|
||||
this.TimePoint = TimePoint;
|
||||
Object = schedulerObj;
|
||||
TimePoint = timePoint;
|
||||
}
|
||||
}
|
||||
|
||||
private List<WaitingObject> WaitingObjects;
|
||||
private List<WaitingObject> _waitingObjects;
|
||||
|
||||
private AutoResetEvent WaitEvent;
|
||||
private AutoResetEvent _waitEvent;
|
||||
|
||||
private bool KeepRunning;
|
||||
private bool _keepRunning;
|
||||
|
||||
public KTimeManager()
|
||||
{
|
||||
WaitingObjects = new List<WaitingObject>();
|
||||
_waitingObjects = new List<WaitingObject>();
|
||||
|
||||
KeepRunning = true;
|
||||
_keepRunning = true;
|
||||
|
||||
Thread Work = new Thread(WaitAndCheckScheduledObjects);
|
||||
Thread work = new Thread(WaitAndCheckScheduledObjects);
|
||||
|
||||
Work.Start();
|
||||
work.Start();
|
||||
}
|
||||
|
||||
public void ScheduleFutureInvocation(IKFutureSchedulerObject Object, long Timeout)
|
||||
public void ScheduleFutureInvocation(IKFutureSchedulerObject schedulerObj, long timeout)
|
||||
{
|
||||
long TimePoint = PerformanceCounter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(Timeout);
|
||||
long timePoint = PerformanceCounter.ElapsedMilliseconds + ConvertNanosecondsToMilliseconds(timeout);
|
||||
|
||||
lock (WaitingObjects)
|
||||
lock (_waitingObjects)
|
||||
{
|
||||
WaitingObjects.Add(new WaitingObject(Object, TimePoint));
|
||||
_waitingObjects.Add(new WaitingObject(schedulerObj, timePoint));
|
||||
}
|
||||
|
||||
WaitEvent.Set();
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public static long ConvertNanosecondsToMilliseconds(long Time)
|
||||
public static long ConvertNanosecondsToMilliseconds(long time)
|
||||
{
|
||||
Time /= 1000000;
|
||||
time /= 1000000;
|
||||
|
||||
if ((ulong)Time > int.MaxValue)
|
||||
if ((ulong)time > int.MaxValue)
|
||||
{
|
||||
return int.MaxValue;
|
||||
}
|
||||
|
||||
return Time;
|
||||
return time;
|
||||
}
|
||||
|
||||
public static long ConvertMillisecondsToNanoseconds(long Time)
|
||||
public static long ConvertMillisecondsToNanoseconds(long time)
|
||||
{
|
||||
return Time * 1000000;
|
||||
return time * 1000000;
|
||||
}
|
||||
|
||||
public static long ConvertMillisecondsToTicks(long Time)
|
||||
public static long ConvertMillisecondsToTicks(long time)
|
||||
{
|
||||
return Time * 19200;
|
||||
return time * 19200;
|
||||
}
|
||||
|
||||
public void UnscheduleFutureInvocation(IKFutureSchedulerObject Object)
|
||||
{
|
||||
lock (WaitingObjects)
|
||||
lock (_waitingObjects)
|
||||
{
|
||||
WaitingObjects.RemoveAll(x => x.Object == Object);
|
||||
_waitingObjects.RemoveAll(x => x.Object == Object);
|
||||
}
|
||||
}
|
||||
|
||||
private void WaitAndCheckScheduledObjects()
|
||||
{
|
||||
using (WaitEvent = new AutoResetEvent(false))
|
||||
using (_waitEvent = new AutoResetEvent(false))
|
||||
{
|
||||
while (KeepRunning)
|
||||
while (_keepRunning)
|
||||
{
|
||||
WaitingObject Next;
|
||||
WaitingObject next;
|
||||
|
||||
lock (WaitingObjects)
|
||||
lock (_waitingObjects)
|
||||
{
|
||||
Next = WaitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
|
||||
next = _waitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (Next != null)
|
||||
if (next != null)
|
||||
{
|
||||
long TimePoint = PerformanceCounter.ElapsedMilliseconds;
|
||||
long timePoint = PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
if (Next.TimePoint > TimePoint)
|
||||
if (next.TimePoint > timePoint)
|
||||
{
|
||||
WaitEvent.WaitOne((int)(Next.TimePoint - TimePoint));
|
||||
_waitEvent.WaitOne((int)(next.TimePoint - timePoint));
|
||||
}
|
||||
|
||||
bool TimeUp = PerformanceCounter.ElapsedMilliseconds >= Next.TimePoint;
|
||||
bool timeUp = PerformanceCounter.ElapsedMilliseconds >= next.TimePoint;
|
||||
|
||||
if (TimeUp)
|
||||
if (timeUp)
|
||||
{
|
||||
lock (WaitingObjects)
|
||||
lock (_waitingObjects)
|
||||
{
|
||||
TimeUp = WaitingObjects.Remove(Next);
|
||||
timeUp = _waitingObjects.Remove(next);
|
||||
}
|
||||
}
|
||||
|
||||
if (TimeUp)
|
||||
if (timeUp)
|
||||
{
|
||||
Next.Object.TimeUp();
|
||||
next.Object.TimeUp();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitEvent.WaitOne();
|
||||
_waitEvent.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,13 +130,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposing)
|
||||
if (disposing)
|
||||
{
|
||||
KeepRunning = false;
|
||||
_keepRunning = false;
|
||||
|
||||
WaitEvent?.Set();
|
||||
_waitEvent?.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,70 +4,70 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
public const int TlsEntrySize = 0x200;
|
||||
|
||||
public ulong PageAddr { get; private set; }
|
||||
public ulong PageAddr { get; }
|
||||
|
||||
private bool[] IsSlotFree;
|
||||
private bool[] _isSlotFree;
|
||||
|
||||
public KTlsPageInfo(ulong PageAddress)
|
||||
public KTlsPageInfo(ulong pageAddress)
|
||||
{
|
||||
this.PageAddr = PageAddress;
|
||||
PageAddr = pageAddress;
|
||||
|
||||
IsSlotFree = new bool[KMemoryManager.PageSize / TlsEntrySize];
|
||||
_isSlotFree = new bool[KMemoryManager.PageSize / TlsEntrySize];
|
||||
|
||||
for (int Index = 0; Index < IsSlotFree.Length; Index++)
|
||||
for (int index = 0; index < _isSlotFree.Length; index++)
|
||||
{
|
||||
IsSlotFree[Index] = true;
|
||||
_isSlotFree[index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetFreePage(out ulong Address)
|
||||
public bool TryGetFreePage(out ulong address)
|
||||
{
|
||||
Address = PageAddr;
|
||||
address = PageAddr;
|
||||
|
||||
for (int Index = 0; Index < IsSlotFree.Length; Index++)
|
||||
for (int index = 0; index < _isSlotFree.Length; index++)
|
||||
{
|
||||
if (IsSlotFree[Index])
|
||||
if (_isSlotFree[index])
|
||||
{
|
||||
IsSlotFree[Index] = false;
|
||||
_isSlotFree[index] = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Address += TlsEntrySize;
|
||||
address += TlsEntrySize;
|
||||
}
|
||||
|
||||
Address = 0;
|
||||
address = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsFull()
|
||||
{
|
||||
bool HasFree = false;
|
||||
bool hasFree = false;
|
||||
|
||||
for (int Index = 0; Index < IsSlotFree.Length; Index++)
|
||||
for (int index = 0; index < _isSlotFree.Length; index++)
|
||||
{
|
||||
HasFree |= IsSlotFree[Index];
|
||||
hasFree |= _isSlotFree[index];
|
||||
}
|
||||
|
||||
return !HasFree;
|
||||
return !hasFree;
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
bool AllFree = true;
|
||||
bool allFree = true;
|
||||
|
||||
for (int Index = 0; Index < IsSlotFree.Length; Index++)
|
||||
for (int index = 0; index < _isSlotFree.Length; index++)
|
||||
{
|
||||
AllFree &= IsSlotFree[Index];
|
||||
allFree &= _isSlotFree[index];
|
||||
}
|
||||
|
||||
return AllFree;
|
||||
return allFree;
|
||||
}
|
||||
|
||||
public void FreeTlsSlot(ulong Address)
|
||||
public void FreeTlsSlot(ulong address)
|
||||
{
|
||||
IsSlotFree[(Address - PageAddr) / TlsEntrySize] = true;
|
||||
_isSlotFree[(address - PageAddr) / TlsEntrySize] = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -6,55 +6,55 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
private const int TlsEntrySize = 0x200;
|
||||
|
||||
private long PagePosition;
|
||||
private long _pagePosition;
|
||||
|
||||
private int UsedSlots;
|
||||
private int _usedSlots;
|
||||
|
||||
private bool[] Slots;
|
||||
private bool[] _slots;
|
||||
|
||||
public bool IsEmpty => UsedSlots == 0;
|
||||
public bool IsFull => UsedSlots == Slots.Length;
|
||||
public bool IsEmpty => _usedSlots == 0;
|
||||
public bool IsFull => _usedSlots == _slots.Length;
|
||||
|
||||
public KTlsPageManager(long PagePosition)
|
||||
public KTlsPageManager(long pagePosition)
|
||||
{
|
||||
this.PagePosition = PagePosition;
|
||||
_pagePosition = pagePosition;
|
||||
|
||||
Slots = new bool[KMemoryManager.PageSize / TlsEntrySize];
|
||||
_slots = new bool[KMemoryManager.PageSize / TlsEntrySize];
|
||||
}
|
||||
|
||||
public bool TryGetFreeTlsAddr(out long Position)
|
||||
public bool TryGetFreeTlsAddr(out long position)
|
||||
{
|
||||
Position = PagePosition;
|
||||
position = _pagePosition;
|
||||
|
||||
for (int Index = 0; Index < Slots.Length; Index++)
|
||||
for (int index = 0; index < _slots.Length; index++)
|
||||
{
|
||||
if (!Slots[Index])
|
||||
if (!_slots[index])
|
||||
{
|
||||
Slots[Index] = true;
|
||||
_slots[index] = true;
|
||||
|
||||
UsedSlots++;
|
||||
_usedSlots++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Position += TlsEntrySize;
|
||||
position += TlsEntrySize;
|
||||
}
|
||||
|
||||
Position = 0;
|
||||
position = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void FreeTlsSlot(int Slot)
|
||||
public void FreeTlsSlot(int slot)
|
||||
{
|
||||
if ((uint)Slot > Slots.Length)
|
||||
if ((uint)slot > _slots.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Slot));
|
||||
throw new ArgumentOutOfRangeException(nameof(slot));
|
||||
}
|
||||
|
||||
Slots[Slot] = false;
|
||||
_slots[slot] = false;
|
||||
|
||||
UsedSlots--;
|
||||
_usedSlots--;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,13 +2,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KTransferMemory
|
||||
{
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
public KTransferMemory(ulong Address, ulong Size)
|
||||
public KTransferMemory(ulong address, ulong size)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
Address = address;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,21 +2,21 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KWritableEvent
|
||||
{
|
||||
private KEvent Parent;
|
||||
private KEvent _parent;
|
||||
|
||||
public KWritableEvent(KEvent Parent)
|
||||
public KWritableEvent(KEvent parent)
|
||||
{
|
||||
this.Parent = Parent;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public void Signal()
|
||||
{
|
||||
Parent.ReadableEvent.Signal();
|
||||
_parent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
public KernelResult Clear()
|
||||
{
|
||||
return Parent.ReadableEvent.Clear();
|
||||
return _parent.ReadableEvent.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,28 +4,28 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
static class KernelInit
|
||||
{
|
||||
public static void InitializeResourceLimit(KResourceLimit ResourceLimit)
|
||||
public static void InitializeResourceLimit(KResourceLimit resourceLimit)
|
||||
{
|
||||
void EnsureSuccess(KernelResult Result)
|
||||
void EnsureSuccess(KernelResult result)
|
||||
{
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected result \"{Result}\".");
|
||||
throw new InvalidOperationException($"Unexpected result \"{result}\".");
|
||||
}
|
||||
}
|
||||
|
||||
int KernelMemoryCfg = 0;
|
||||
int kernelMemoryCfg = 0;
|
||||
|
||||
long RamSize = GetRamSize(KernelMemoryCfg);
|
||||
long ramSize = GetRamSize(kernelMemoryCfg);
|
||||
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Memory, RamSize));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Thread, 800));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Event, 700));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.TransferMemory, 200));
|
||||
EnsureSuccess(ResourceLimit.SetLimitValue(LimitableResource.Session, 900));
|
||||
EnsureSuccess(resourceLimit.SetLimitValue(LimitableResource.Memory, ramSize));
|
||||
EnsureSuccess(resourceLimit.SetLimitValue(LimitableResource.Thread, 800));
|
||||
EnsureSuccess(resourceLimit.SetLimitValue(LimitableResource.Event, 700));
|
||||
EnsureSuccess(resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 200));
|
||||
EnsureSuccess(resourceLimit.SetLimitValue(LimitableResource.Session, 900));
|
||||
|
||||
if (!ResourceLimit.Reserve(LimitableResource.Memory, 0) ||
|
||||
!ResourceLimit.Reserve(LimitableResource.Memory, 0x60000))
|
||||
if (!resourceLimit.Reserve(LimitableResource.Memory, 0) ||
|
||||
!resourceLimit.Reserve(LimitableResource.Memory, 0x60000))
|
||||
{
|
||||
throw new InvalidOperationException("Unexpected failure reserving memory on resource limit.");
|
||||
}
|
||||
@ -33,99 +33,99 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
public static KMemoryRegionManager[] GetMemoryRegions()
|
||||
{
|
||||
KMemoryArrange Arrange = GetMemoryArrange();
|
||||
KMemoryArrange arrange = GetMemoryArrange();
|
||||
|
||||
return new KMemoryRegionManager[]
|
||||
{
|
||||
GetMemoryRegion(Arrange.Application),
|
||||
GetMemoryRegion(Arrange.Applet),
|
||||
GetMemoryRegion(Arrange.Service),
|
||||
GetMemoryRegion(Arrange.NvServices)
|
||||
GetMemoryRegion(arrange.Application),
|
||||
GetMemoryRegion(arrange.Applet),
|
||||
GetMemoryRegion(arrange.Service),
|
||||
GetMemoryRegion(arrange.NvServices)
|
||||
};
|
||||
}
|
||||
|
||||
private static KMemoryRegionManager GetMemoryRegion(KMemoryArrangeRegion Region)
|
||||
private static KMemoryRegionManager GetMemoryRegion(KMemoryArrangeRegion region)
|
||||
{
|
||||
return new KMemoryRegionManager(Region.Address, Region.Size, Region.EndAddr);
|
||||
return new KMemoryRegionManager(region.Address, region.Size, region.EndAddr);
|
||||
}
|
||||
|
||||
private static KMemoryArrange GetMemoryArrange()
|
||||
{
|
||||
int McEmemCfg = 0x1000;
|
||||
int mcEmemCfg = 0x1000;
|
||||
|
||||
ulong EmemApertureSize = (ulong)(McEmemCfg & 0x3fff) << 20;
|
||||
ulong ememApertureSize = (ulong)(mcEmemCfg & 0x3fff) << 20;
|
||||
|
||||
int KernelMemoryCfg = 0;
|
||||
int kernelMemoryCfg = 0;
|
||||
|
||||
ulong RamSize = (ulong)GetRamSize(KernelMemoryCfg);
|
||||
ulong ramSize = (ulong)GetRamSize(kernelMemoryCfg);
|
||||
|
||||
ulong RamPart0;
|
||||
ulong RamPart1;
|
||||
ulong ramPart0;
|
||||
ulong ramPart1;
|
||||
|
||||
if (RamSize * 2 > EmemApertureSize)
|
||||
if (ramSize * 2 > ememApertureSize)
|
||||
{
|
||||
RamPart0 = EmemApertureSize / 2;
|
||||
RamPart1 = EmemApertureSize / 2;
|
||||
ramPart0 = ememApertureSize / 2;
|
||||
ramPart1 = ememApertureSize / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
RamPart0 = EmemApertureSize;
|
||||
RamPart1 = 0;
|
||||
ramPart0 = ememApertureSize;
|
||||
ramPart1 = 0;
|
||||
}
|
||||
|
||||
int MemoryArrange = 1;
|
||||
int memoryArrange = 1;
|
||||
|
||||
ulong ApplicationRgSize;
|
||||
ulong applicationRgSize;
|
||||
|
||||
switch (MemoryArrange)
|
||||
switch (memoryArrange)
|
||||
{
|
||||
case 2: ApplicationRgSize = 0x80000000; break;
|
||||
case 2: applicationRgSize = 0x80000000; break;
|
||||
case 0x11:
|
||||
case 0x21: ApplicationRgSize = 0x133400000; break;
|
||||
default: ApplicationRgSize = 0xcd500000; break;
|
||||
case 0x21: applicationRgSize = 0x133400000; break;
|
||||
default: applicationRgSize = 0xcd500000; break;
|
||||
}
|
||||
|
||||
ulong AppletRgSize;
|
||||
ulong appletRgSize;
|
||||
|
||||
switch (MemoryArrange)
|
||||
switch (memoryArrange)
|
||||
{
|
||||
case 2: AppletRgSize = 0x61200000; break;
|
||||
case 3: AppletRgSize = 0x1c000000; break;
|
||||
case 0x11: AppletRgSize = 0x23200000; break;
|
||||
case 2: appletRgSize = 0x61200000; break;
|
||||
case 3: appletRgSize = 0x1c000000; break;
|
||||
case 0x11: appletRgSize = 0x23200000; break;
|
||||
case 0x12:
|
||||
case 0x21: AppletRgSize = 0x89100000; break;
|
||||
default: AppletRgSize = 0x1fb00000; break;
|
||||
case 0x21: appletRgSize = 0x89100000; break;
|
||||
default: appletRgSize = 0x1fb00000; break;
|
||||
}
|
||||
|
||||
KMemoryArrangeRegion ServiceRg;
|
||||
KMemoryArrangeRegion NvServicesRg;
|
||||
KMemoryArrangeRegion AppletRg;
|
||||
KMemoryArrangeRegion ApplicationRg;
|
||||
KMemoryArrangeRegion serviceRg;
|
||||
KMemoryArrangeRegion nvServicesRg;
|
||||
KMemoryArrangeRegion appletRg;
|
||||
KMemoryArrangeRegion applicationRg;
|
||||
|
||||
const ulong NvServicesRgSize = 0x29ba000;
|
||||
const ulong nvServicesRgSize = 0x29ba000;
|
||||
|
||||
ulong ApplicationRgEnd = DramMemoryMap.DramEnd; //- RamPart0;
|
||||
ulong applicationRgEnd = DramMemoryMap.DramEnd; //- RamPart0;
|
||||
|
||||
ApplicationRg = new KMemoryArrangeRegion(ApplicationRgEnd - ApplicationRgSize, ApplicationRgSize);
|
||||
applicationRg = new KMemoryArrangeRegion(applicationRgEnd - applicationRgSize, applicationRgSize);
|
||||
|
||||
ulong NvServicesRgEnd = ApplicationRg.Address - AppletRgSize;
|
||||
ulong nvServicesRgEnd = applicationRg.Address - appletRgSize;
|
||||
|
||||
NvServicesRg = new KMemoryArrangeRegion(NvServicesRgEnd - NvServicesRgSize, NvServicesRgSize);
|
||||
AppletRg = new KMemoryArrangeRegion(NvServicesRgEnd, AppletRgSize);
|
||||
nvServicesRg = new KMemoryArrangeRegion(nvServicesRgEnd - nvServicesRgSize, nvServicesRgSize);
|
||||
appletRg = new KMemoryArrangeRegion(nvServicesRgEnd, appletRgSize);
|
||||
|
||||
//Note: There is an extra region used by the kernel, however
|
||||
//since we are doing HLE we are not going to use that memory, so give all
|
||||
//the remaining memory space to services.
|
||||
ulong ServiceRgSize = NvServicesRg.Address - DramMemoryMap.SlabHeapEnd;
|
||||
ulong serviceRgSize = nvServicesRg.Address - DramMemoryMap.SlabHeapEnd;
|
||||
|
||||
ServiceRg = new KMemoryArrangeRegion(DramMemoryMap.SlabHeapEnd, ServiceRgSize);
|
||||
serviceRg = new KMemoryArrangeRegion(DramMemoryMap.SlabHeapEnd, serviceRgSize);
|
||||
|
||||
return new KMemoryArrange(ServiceRg, NvServicesRg, AppletRg, ApplicationRg);
|
||||
return new KMemoryArrange(serviceRg, nvServicesRg, appletRg, applicationRg);
|
||||
}
|
||||
|
||||
private static long GetRamSize(int KernelMemoryCfg)
|
||||
private static long GetRamSize(int kernelMemoryCfg)
|
||||
{
|
||||
switch ((KernelMemoryCfg >> 16) & 3)
|
||||
switch ((kernelMemoryCfg >> 16) & 3)
|
||||
{
|
||||
case 1: return 0x180000000;
|
||||
case 2: return 0x200000000;
|
||||
|
@ -4,48 +4,48 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
static class KernelTransfer
|
||||
{
|
||||
public static bool UserToKernelInt32(Horizon System, long Address, out int Value)
|
||||
public static bool UserToKernelInt32(Horizon system, long address, out int value)
|
||||
{
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (CurrentProcess.CpuMemory.IsMapped(Address) &&
|
||||
CurrentProcess.CpuMemory.IsMapped(Address + 3))
|
||||
if (currentProcess.CpuMemory.IsMapped(address) &&
|
||||
currentProcess.CpuMemory.IsMapped(address + 3))
|
||||
{
|
||||
Value = CurrentProcess.CpuMemory.ReadInt32(Address);
|
||||
value = currentProcess.CpuMemory.ReadInt32(address);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Value = 0;
|
||||
value = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool UserToKernelString(Horizon System, long Address, int Size, out string Value)
|
||||
public static bool UserToKernelString(Horizon system, long address, int size, out string value)
|
||||
{
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (CurrentProcess.CpuMemory.IsMapped(Address) &&
|
||||
CurrentProcess.CpuMemory.IsMapped(Address + Size - 1))
|
||||
if (currentProcess.CpuMemory.IsMapped(address) &&
|
||||
currentProcess.CpuMemory.IsMapped(address + size - 1))
|
||||
{
|
||||
Value = MemoryHelper.ReadAsciiString(CurrentProcess.CpuMemory, Address, Size);
|
||||
value = MemoryHelper.ReadAsciiString(currentProcess.CpuMemory, address, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Value = null;
|
||||
value = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool KernelToUserInt32(Horizon System, long Address, int Value)
|
||||
public static bool KernelToUserInt32(Horizon system, long address, int value)
|
||||
{
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (CurrentProcess.CpuMemory.IsMapped(Address) &&
|
||||
CurrentProcess.CpuMemory.IsMapped(Address + 3))
|
||||
if (currentProcess.CpuMemory.IsMapped(address) &&
|
||||
currentProcess.CpuMemory.IsMapped(address + 3))
|
||||
{
|
||||
CurrentProcess.CpuMemory.WriteInt32ToSharedAddr(Address, Value);
|
||||
currentProcess.CpuMemory.WriteInt32ToSharedAddr(address, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -53,14 +53,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool KernelToUserInt64(Horizon System, long Address, long Value)
|
||||
public static bool KernelToUserInt64(Horizon system, long address, long value)
|
||||
{
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (CurrentProcess.CpuMemory.IsMapped(Address) &&
|
||||
CurrentProcess.CpuMemory.IsMapped(Address + 7))
|
||||
if (currentProcess.CpuMemory.IsMapped(address) &&
|
||||
currentProcess.CpuMemory.IsMapped(address + 7))
|
||||
{
|
||||
CurrentProcess.CpuMemory.WriteInt64(Address, Value);
|
||||
currentProcess.CpuMemory.WriteInt64(address, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4,125 +4,125 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class MersenneTwister
|
||||
{
|
||||
private int Index;
|
||||
private uint[] Mt;
|
||||
private int _index;
|
||||
private uint[] _mt;
|
||||
|
||||
public MersenneTwister(uint Seed)
|
||||
public MersenneTwister(uint seed)
|
||||
{
|
||||
Mt = new uint[624];
|
||||
_mt = new uint[624];
|
||||
|
||||
Mt[0] = Seed;
|
||||
_mt[0] = seed;
|
||||
|
||||
for (int MtIdx = 1; MtIdx < Mt.Length; MtIdx++)
|
||||
for (int mtIdx = 1; mtIdx < _mt.Length; mtIdx++)
|
||||
{
|
||||
uint Prev = Mt[MtIdx - 1];
|
||||
uint prev = _mt[mtIdx - 1];
|
||||
|
||||
Mt[MtIdx] = (uint)(0x6c078965 * (Prev ^ (Prev >> 30)) + MtIdx);
|
||||
_mt[mtIdx] = (uint)(0x6c078965 * (prev ^ (prev >> 30)) + mtIdx);
|
||||
}
|
||||
|
||||
Index = Mt.Length;
|
||||
_index = _mt.Length;
|
||||
}
|
||||
|
||||
public long GenRandomNumber(long Min, long Max)
|
||||
public long GenRandomNumber(long min, long max)
|
||||
{
|
||||
long Range = Max - Min;
|
||||
long range = max - min;
|
||||
|
||||
if (Min == Max)
|
||||
if (min == max)
|
||||
{
|
||||
return Min;
|
||||
return min;
|
||||
}
|
||||
|
||||
if (Range == -1)
|
||||
if (range == -1)
|
||||
{
|
||||
//Increment would cause a overflow, special case.
|
||||
return GenRandomNumber(2, 2, 32, 0xffffffffu, 0xffffffffu);
|
||||
}
|
||||
|
||||
Range++;
|
||||
range++;
|
||||
|
||||
//This is log2(Range) plus one.
|
||||
int NextRangeLog2 = 64 - BitUtils.CountLeadingZeros64(Range);
|
||||
int nextRangeLog2 = 64 - BitUtils.CountLeadingZeros64(range);
|
||||
|
||||
//If Range is already power of 2, subtract one to use log2(Range) directly.
|
||||
int RangeLog2 = NextRangeLog2 - (BitUtils.IsPowerOfTwo64(Range) ? 1 : 0);
|
||||
int rangeLog2 = nextRangeLog2 - (BitUtils.IsPowerOfTwo64(range) ? 1 : 0);
|
||||
|
||||
int Parts = RangeLog2 > 32 ? 2 : 1;
|
||||
int BitsPerPart = RangeLog2 / Parts;
|
||||
int parts = rangeLog2 > 32 ? 2 : 1;
|
||||
int bitsPerPart = rangeLog2 / parts;
|
||||
|
||||
int FullParts = Parts - (RangeLog2 - Parts * BitsPerPart);
|
||||
int fullParts = parts - (rangeLog2 - parts * bitsPerPart);
|
||||
|
||||
uint Mask = 0xffffffffu >> (32 - BitsPerPart);
|
||||
uint MaskPlus1 = 0xffffffffu >> (31 - BitsPerPart);
|
||||
uint mask = 0xffffffffu >> (32 - bitsPerPart);
|
||||
uint maskPlus1 = 0xffffffffu >> (31 - bitsPerPart);
|
||||
|
||||
long RandomNumber;
|
||||
long randomNumber;
|
||||
|
||||
do
|
||||
{
|
||||
RandomNumber = GenRandomNumber(Parts, FullParts, BitsPerPart, Mask, MaskPlus1);
|
||||
randomNumber = GenRandomNumber(parts, fullParts, bitsPerPart, mask, maskPlus1);
|
||||
}
|
||||
while ((ulong)RandomNumber >= (ulong)Range);
|
||||
while ((ulong)randomNumber >= (ulong)range);
|
||||
|
||||
return Min + RandomNumber;
|
||||
return min + randomNumber;
|
||||
}
|
||||
|
||||
private long GenRandomNumber(
|
||||
int Parts,
|
||||
int FullParts,
|
||||
int BitsPerPart,
|
||||
uint Mask,
|
||||
uint MaskPlus1)
|
||||
int parts,
|
||||
int fullParts,
|
||||
int bitsPerPart,
|
||||
uint mask,
|
||||
uint maskPlus1)
|
||||
{
|
||||
long RandomNumber = 0;
|
||||
long randomNumber = 0;
|
||||
|
||||
int Part = 0;
|
||||
int part = 0;
|
||||
|
||||
for (; Part < FullParts; Part++)
|
||||
for (; part < fullParts; part++)
|
||||
{
|
||||
RandomNumber <<= BitsPerPart;
|
||||
RandomNumber |= GenRandomNumber() & Mask;
|
||||
randomNumber <<= bitsPerPart;
|
||||
randomNumber |= GenRandomNumber() & mask;
|
||||
}
|
||||
|
||||
for (; Part < Parts; Part++)
|
||||
for (; part < parts; part++)
|
||||
{
|
||||
RandomNumber <<= BitsPerPart + 1;
|
||||
RandomNumber |= GenRandomNumber() & MaskPlus1;
|
||||
randomNumber <<= bitsPerPart + 1;
|
||||
randomNumber |= GenRandomNumber() & maskPlus1;
|
||||
}
|
||||
|
||||
return RandomNumber;
|
||||
return randomNumber;
|
||||
}
|
||||
|
||||
private uint GenRandomNumber()
|
||||
{
|
||||
if (Index >= Mt.Length)
|
||||
if (_index >= _mt.Length)
|
||||
{
|
||||
Twist();
|
||||
}
|
||||
|
||||
uint Value = Mt[Index++];
|
||||
uint value = _mt[_index++];
|
||||
|
||||
Value ^= Value >> 11;
|
||||
Value ^= (Value << 7) & 0x9d2c5680;
|
||||
Value ^= (Value << 15) & 0xefc60000;
|
||||
Value ^= Value >> 18;
|
||||
value ^= value >> 11;
|
||||
value ^= (value << 7) & 0x9d2c5680;
|
||||
value ^= (value << 15) & 0xefc60000;
|
||||
value ^= value >> 18;
|
||||
|
||||
return Value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private void Twist()
|
||||
{
|
||||
for (int MtIdx = 0; MtIdx < Mt.Length; MtIdx++)
|
||||
for (int mtIdx = 0; mtIdx < _mt.Length; mtIdx++)
|
||||
{
|
||||
uint Value = (Mt[MtIdx] & 0x80000000) + (Mt[(MtIdx + 1) % Mt.Length] & 0x7fffffff);
|
||||
uint value = (_mt[mtIdx] & 0x80000000) + (_mt[(mtIdx + 1) % _mt.Length] & 0x7fffffff);
|
||||
|
||||
Mt[MtIdx] = Mt[(MtIdx + 397) % Mt.Length] ^ (Value >> 1);
|
||||
_mt[mtIdx] = _mt[(mtIdx + 397) % _mt.Length] ^ (value >> 1);
|
||||
|
||||
if ((Value & 1) != 0)
|
||||
if ((value & 1) != 0)
|
||||
{
|
||||
Mt[MtIdx] ^= 0x9908b0df;
|
||||
_mt[mtIdx] ^= 0x9908b0df;
|
||||
}
|
||||
}
|
||||
|
||||
Index = 0;
|
||||
_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,36 +2,36 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
struct ProcessCreationInfo
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public string Name { get; }
|
||||
|
||||
public int Category { get; private set; }
|
||||
public long TitleId { get; private set; }
|
||||
public int Category { get; }
|
||||
public long TitleId { get; }
|
||||
|
||||
public ulong CodeAddress { get; private set; }
|
||||
public int CodePagesCount { get; private set; }
|
||||
public ulong CodeAddress { get; }
|
||||
public int CodePagesCount { get; }
|
||||
|
||||
public int MmuFlags { get; private set; }
|
||||
public int ResourceLimitHandle { get; private set; }
|
||||
public int PersonalMmHeapPagesCount { get; private set; }
|
||||
public int MmuFlags { get; }
|
||||
public int ResourceLimitHandle { get; }
|
||||
public int PersonalMmHeapPagesCount { get; }
|
||||
|
||||
public ProcessCreationInfo(
|
||||
string Name,
|
||||
int Category,
|
||||
long TitleId,
|
||||
ulong CodeAddress,
|
||||
int CodePagesCount,
|
||||
int MmuFlags,
|
||||
int ResourceLimitHandle,
|
||||
int PersonalMmHeapPagesCount)
|
||||
string name,
|
||||
int category,
|
||||
long titleId,
|
||||
ulong codeAddress,
|
||||
int codePagesCount,
|
||||
int mmuFlags,
|
||||
int resourceLimitHandle,
|
||||
int personalMmHeapPagesCount)
|
||||
{
|
||||
this.Name = Name;
|
||||
this.Category = Category;
|
||||
this.TitleId = TitleId;
|
||||
this.CodeAddress = CodeAddress;
|
||||
this.CodePagesCount = CodePagesCount;
|
||||
this.MmuFlags = MmuFlags;
|
||||
this.ResourceLimitHandle = ResourceLimitHandle;
|
||||
this.PersonalMmHeapPagesCount = PersonalMmHeapPagesCount;
|
||||
Name = name;
|
||||
Category = category;
|
||||
TitleId = titleId;
|
||||
CodeAddress = codeAddress;
|
||||
CodePagesCount = codePagesCount;
|
||||
MmuFlags = mmuFlags;
|
||||
ResourceLimitHandle = resourceLimitHandle;
|
||||
PersonalMmHeapPagesCount = personalMmHeapPagesCount;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,38 +10,38 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private delegate void SvcFunc(CpuThreadState ThreadState);
|
||||
private delegate void SvcFunc(CpuThreadState threadState);
|
||||
|
||||
private Dictionary<int, SvcFunc> SvcFuncs;
|
||||
private Dictionary<int, SvcFunc> _svcFuncs;
|
||||
|
||||
private Switch Device;
|
||||
private KProcess Process;
|
||||
private Horizon System;
|
||||
private MemoryManager Memory;
|
||||
private Switch _device;
|
||||
private KProcess _process;
|
||||
private Horizon _system;
|
||||
private MemoryManager _memory;
|
||||
|
||||
private struct HleIpcMessage
|
||||
{
|
||||
public KThread Thread { get; private set; }
|
||||
public KSession Session { get; private set; }
|
||||
public IpcMessage Message { get; private set; }
|
||||
public long MessagePtr { get; private set; }
|
||||
public KThread Thread { get; }
|
||||
public KSession Session { get; }
|
||||
public IpcMessage Message { get; }
|
||||
public long MessagePtr { get; }
|
||||
|
||||
public HleIpcMessage(
|
||||
KThread Thread,
|
||||
KSession Session,
|
||||
IpcMessage Message,
|
||||
long MessagePtr)
|
||||
KThread thread,
|
||||
KSession session,
|
||||
IpcMessage message,
|
||||
long messagePtr)
|
||||
{
|
||||
this.Thread = Thread;
|
||||
this.Session = Session;
|
||||
this.Message = Message;
|
||||
this.MessagePtr = MessagePtr;
|
||||
Thread = thread;
|
||||
Session = session;
|
||||
Message = message;
|
||||
MessagePtr = messagePtr;
|
||||
}
|
||||
}
|
||||
|
||||
public SvcHandler(Switch Device, KProcess Process)
|
||||
public SvcHandler(Switch device, KProcess process)
|
||||
{
|
||||
SvcFuncs = new Dictionary<int, SvcFunc>()
|
||||
_svcFuncs = new Dictionary<int, SvcFunc>
|
||||
{
|
||||
{ 0x01, SvcSetHeapSize },
|
||||
{ 0x03, SvcSetMemoryAttribute },
|
||||
@ -93,23 +93,23 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{ 0x71, ManageNamedPort64 }
|
||||
};
|
||||
|
||||
this.Device = Device;
|
||||
this.Process = Process;
|
||||
this.System = Device.System;
|
||||
this.Memory = Process.CpuMemory;
|
||||
_device = device;
|
||||
_process = process;
|
||||
_system = device.System;
|
||||
_memory = process.CpuMemory;
|
||||
}
|
||||
|
||||
public void SvcCall(object sender, InstExceptionEventArgs e)
|
||||
{
|
||||
CpuThreadState ThreadState = (CpuThreadState)sender;
|
||||
CpuThreadState threadState = (CpuThreadState)sender;
|
||||
|
||||
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
||||
if (_svcFuncs.TryGetValue(e.Id, out SvcFunc func))
|
||||
{
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{func.Method.Name} called.");
|
||||
|
||||
Func(ThreadState);
|
||||
func(threadState);
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended.");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{func.Method.Name} ended.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7,575 +7,575 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private void SvcSetHeapSize(CpuThreadState ThreadState)
|
||||
private void SvcSetHeapSize(CpuThreadState threadState)
|
||||
{
|
||||
ulong Size = ThreadState.X1;
|
||||
ulong size = threadState.X1;
|
||||
|
||||
if ((Size & 0xfffffffe001fffff) != 0)
|
||||
if ((size & 0xfffffffe001fffff) != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{size:x16} is not aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = Process.MemoryManager.SetHeapSize(Size, out ulong Position);
|
||||
KernelResult result = _process.MemoryManager.SetHeapSize(size, out ulong position);
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
|
||||
if (Result == KernelResult.Success)
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
ThreadState.X1 = Position;
|
||||
threadState.X1 = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcSetMemoryAttribute(CpuThreadState ThreadState)
|
||||
private void SvcSetMemoryAttribute(CpuThreadState threadState)
|
||||
{
|
||||
ulong Position = ThreadState.X0;
|
||||
ulong Size = ThreadState.X1;
|
||||
ulong position = threadState.X0;
|
||||
ulong size = threadState.X1;
|
||||
|
||||
if (!PageAligned(Position))
|
||||
if (!PageAligned(position))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryAttribute AttributeMask = (MemoryAttribute)ThreadState.X2;
|
||||
MemoryAttribute AttributeValue = (MemoryAttribute)ThreadState.X3;
|
||||
MemoryAttribute attributeMask = (MemoryAttribute)threadState.X2;
|
||||
MemoryAttribute attributeValue = (MemoryAttribute)threadState.X3;
|
||||
|
||||
MemoryAttribute Attributes = AttributeMask | AttributeValue;
|
||||
MemoryAttribute attributes = attributeMask | attributeValue;
|
||||
|
||||
if (Attributes != AttributeMask ||
|
||||
(Attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
|
||||
if (attributes != attributeMask ||
|
||||
(attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = Process.MemoryManager.SetMemoryAttribute(
|
||||
Position,
|
||||
Size,
|
||||
AttributeMask,
|
||||
AttributeValue);
|
||||
KernelResult result = _process.MemoryManager.SetMemoryAttribute(
|
||||
position,
|
||||
size,
|
||||
attributeMask,
|
||||
attributeValue);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory.StopObservingRegion((long)Position, (long)Size);
|
||||
_memory.StopObservingRegion((long)position, (long)size);
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcMapMemory(CpuThreadState ThreadState)
|
||||
private void SvcMapMemory(CpuThreadState threadState)
|
||||
{
|
||||
ulong Dst = ThreadState.X0;
|
||||
ulong Src = ThreadState.X1;
|
||||
ulong Size = ThreadState.X2;
|
||||
ulong dst = threadState.X0;
|
||||
ulong src = threadState.X1;
|
||||
ulong size = threadState.X2;
|
||||
|
||||
if (!PageAligned(Src | Dst))
|
||||
if (!PageAligned(src | dst))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Src + Size <= Src || Dst + Size <= Dst)
|
||||
if (src + size <= src || dst + size <= dst)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (!CurrentProcess.MemoryManager.InsideAddrSpace(Src, Size))
|
||||
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{src:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentProcess.MemoryManager.OutsideStackRegion(Dst, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideHeapRegion (Dst, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideAliasRegion (Dst, Size))
|
||||
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
|
||||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
|
||||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{dst:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = Process.MemoryManager.Map(Dst, Src, Size);
|
||||
KernelResult result = _process.MemoryManager.Map(dst, src, size);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcUnmapMemory(CpuThreadState ThreadState)
|
||||
private void SvcUnmapMemory(CpuThreadState threadState)
|
||||
{
|
||||
ulong Dst = ThreadState.X0;
|
||||
ulong Src = ThreadState.X1;
|
||||
ulong Size = ThreadState.X2;
|
||||
ulong dst = threadState.X0;
|
||||
ulong src = threadState.X1;
|
||||
ulong size = threadState.X2;
|
||||
|
||||
if (!PageAligned(Src | Dst))
|
||||
if (!PageAligned(src | dst))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Src + Size <= Src || Dst + Size <= Dst)
|
||||
if (src + size <= src || dst + size <= dst)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (!CurrentProcess.MemoryManager.InsideAddrSpace(Src, Size))
|
||||
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{src:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentProcess.MemoryManager.OutsideStackRegion(Dst, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideHeapRegion (Dst, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideAliasRegion (Dst, Size))
|
||||
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
|
||||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
|
||||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{dst:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = Process.MemoryManager.Unmap(Dst, Src, Size);
|
||||
KernelResult result = _process.MemoryManager.Unmap(dst, src, size);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcQueryMemory(CpuThreadState ThreadState)
|
||||
private void SvcQueryMemory(CpuThreadState threadState)
|
||||
{
|
||||
long InfoPtr = (long)ThreadState.X0;
|
||||
ulong Position = ThreadState.X2;
|
||||
long infoPtr = (long)threadState.X0;
|
||||
ulong position = threadState.X2;
|
||||
|
||||
KMemoryInfo BlkInfo = Process.MemoryManager.QueryMemory(Position);
|
||||
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
|
||||
|
||||
Memory.WriteUInt64(InfoPtr + 0x00, BlkInfo.Address);
|
||||
Memory.WriteUInt64(InfoPtr + 0x08, BlkInfo.Size);
|
||||
Memory.WriteInt32 (InfoPtr + 0x10, (int)BlkInfo.State & 0xff);
|
||||
Memory.WriteInt32 (InfoPtr + 0x14, (int)BlkInfo.Attribute);
|
||||
Memory.WriteInt32 (InfoPtr + 0x18, (int)BlkInfo.Permission);
|
||||
Memory.WriteInt32 (InfoPtr + 0x1c, BlkInfo.IpcRefCount);
|
||||
Memory.WriteInt32 (InfoPtr + 0x20, BlkInfo.DeviceRefCount);
|
||||
Memory.WriteInt32 (InfoPtr + 0x24, 0);
|
||||
_memory.WriteUInt64(infoPtr + 0x00, blkInfo.Address);
|
||||
_memory.WriteUInt64(infoPtr + 0x08, blkInfo.Size);
|
||||
_memory.WriteInt32 (infoPtr + 0x10, (int)blkInfo.State & 0xff);
|
||||
_memory.WriteInt32 (infoPtr + 0x14, (int)blkInfo.Attribute);
|
||||
_memory.WriteInt32 (infoPtr + 0x18, (int)blkInfo.Permission);
|
||||
_memory.WriteInt32 (infoPtr + 0x1c, blkInfo.IpcRefCount);
|
||||
_memory.WriteInt32 (infoPtr + 0x20, blkInfo.DeviceRefCount);
|
||||
_memory.WriteInt32 (infoPtr + 0x24, 0);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = 0;
|
||||
threadState.X0 = 0;
|
||||
threadState.X1 = 0;
|
||||
}
|
||||
|
||||
private void SvcMapSharedMemory(CpuThreadState ThreadState)
|
||||
private void SvcMapSharedMemory(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
ulong Address = ThreadState.X1;
|
||||
ulong Size = ThreadState.X2;
|
||||
int handle = (int)threadState.X0;
|
||||
ulong address = threadState.X1;
|
||||
ulong size = threadState.X2;
|
||||
|
||||
if (!PageAligned(Address))
|
||||
if (!PageAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Address + Size <= Address)
|
||||
if (address + size <= address)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Address:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryPermission Permission = (MemoryPermission)ThreadState.X3;
|
||||
MemoryPermission permission = (MemoryPermission)threadState.X3;
|
||||
|
||||
if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
|
||||
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {permission}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KSharedMemory SharedMemory = CurrentProcess.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
|
||||
|
||||
if (SharedMemory == null)
|
||||
if (sharedMemory == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentProcess.MemoryManager.IsInvalidRegion (Address, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideHeapRegion (Address, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideAliasRegion(Address, Size))
|
||||
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
|
||||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
|
||||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = SharedMemory.MapIntoProcess(
|
||||
CurrentProcess.MemoryManager,
|
||||
Address,
|
||||
Size,
|
||||
CurrentProcess,
|
||||
Permission);
|
||||
KernelResult result = sharedMemory.MapIntoProcess(
|
||||
currentProcess.MemoryManager,
|
||||
address,
|
||||
size,
|
||||
currentProcess,
|
||||
permission);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcUnmapSharedMemory(CpuThreadState ThreadState)
|
||||
private void SvcUnmapSharedMemory(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
ulong Address = ThreadState.X1;
|
||||
ulong Size = ThreadState.X2;
|
||||
int handle = (int)threadState.X0;
|
||||
ulong address = threadState.X1;
|
||||
ulong size = threadState.X2;
|
||||
|
||||
if (!PageAligned(Address))
|
||||
if (!PageAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Address + Size <= Address)
|
||||
if (address + size <= address)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Address:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KSharedMemory SharedMemory = CurrentProcess.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
|
||||
|
||||
if (SharedMemory == null)
|
||||
if (sharedMemory == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentProcess.MemoryManager.IsInvalidRegion (Address, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideHeapRegion (Address, Size) ||
|
||||
CurrentProcess.MemoryManager.InsideAliasRegion(Address, Size))
|
||||
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
|
||||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
|
||||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = SharedMemory.UnmapFromProcess(
|
||||
CurrentProcess.MemoryManager,
|
||||
Address,
|
||||
Size,
|
||||
CurrentProcess);
|
||||
KernelResult result = sharedMemory.UnmapFromProcess(
|
||||
currentProcess.MemoryManager,
|
||||
address,
|
||||
size,
|
||||
currentProcess);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcCreateTransferMemory(CpuThreadState ThreadState)
|
||||
private void SvcCreateTransferMemory(CpuThreadState threadState)
|
||||
{
|
||||
ulong Address = ThreadState.X1;
|
||||
ulong Size = ThreadState.X2;
|
||||
ulong address = threadState.X1;
|
||||
ulong size = threadState.X2;
|
||||
|
||||
if (!PageAligned(Address))
|
||||
if (!PageAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Address + Size <= Address)
|
||||
if (address + size <= address)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Address:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryPermission Permission = (MemoryPermission)ThreadState.X3;
|
||||
MemoryPermission permission = (MemoryPermission)threadState.X3;
|
||||
|
||||
if (Permission > MemoryPermission.ReadAndWrite || Permission == MemoryPermission.Write)
|
||||
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {permission}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Process.MemoryManager.ReserveTransferMemory(Address, Size, Permission);
|
||||
_process.MemoryManager.ReserveTransferMemory(address, size, permission);
|
||||
|
||||
KTransferMemory TransferMemory = new KTransferMemory(Address, Size);
|
||||
KTransferMemory transferMemory = new KTransferMemory(address, size);
|
||||
|
||||
KernelResult Result = Process.HandleTable.GenerateHandle(TransferMemory, out int Handle);
|
||||
KernelResult result = _process.HandleTable.GenerateHandle(transferMemory, out int handle);
|
||||
|
||||
ThreadState.X0 = (uint)Result;
|
||||
ThreadState.X1 = (ulong)Handle;
|
||||
threadState.X0 = (uint)result;
|
||||
threadState.X1 = (ulong)handle;
|
||||
}
|
||||
|
||||
private void SvcMapPhysicalMemory(CpuThreadState ThreadState)
|
||||
private void SvcMapPhysicalMemory(CpuThreadState threadState)
|
||||
{
|
||||
ulong Address = ThreadState.X0;
|
||||
ulong Size = ThreadState.X1;
|
||||
ulong address = threadState.X0;
|
||||
ulong size = threadState.X1;
|
||||
|
||||
if (!PageAligned(Address))
|
||||
if (!PageAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Address + Size <= Address)
|
||||
if (address + size <= address)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Address:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if ((CurrentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
|
||||
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"System resource size is zero.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CurrentProcess.MemoryManager.InsideAddrSpace (Address, Size) ||
|
||||
CurrentProcess.MemoryManager.OutsideAliasRegion(Address, Size))
|
||||
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
|
||||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {Address:x16}.");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {address:x16}.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = Process.MemoryManager.MapPhysicalMemory(Address, Size);
|
||||
KernelResult result = _process.MemoryManager.MapPhysicalMemory(address, size);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcUnmapPhysicalMemory(CpuThreadState ThreadState)
|
||||
private void SvcUnmapPhysicalMemory(CpuThreadState threadState)
|
||||
{
|
||||
ulong Address = ThreadState.X0;
|
||||
ulong Size = ThreadState.X1;
|
||||
ulong address = threadState.X0;
|
||||
ulong size = threadState.X1;
|
||||
|
||||
if (!PageAligned(Address))
|
||||
if (!PageAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Address:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Address + Size <= Address)
|
||||
if (address + size <= address)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Address:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if ((CurrentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
|
||||
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"System resource size is zero.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CurrentProcess.MemoryManager.InsideAddrSpace (Address, Size) ||
|
||||
CurrentProcess.MemoryManager.OutsideAliasRegion(Address, Size))
|
||||
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
|
||||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {Address:x16}.");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {address:x16}.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KernelResult Result = Process.MemoryManager.UnmapPhysicalMemory(Address, Size);
|
||||
KernelResult result = _process.MemoryManager.UnmapPhysicalMemory(address, size);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private static bool PageAligned(ulong Position)
|
||||
private static bool PageAligned(ulong position)
|
||||
{
|
||||
return (Position & (KMemoryManager.PageSize - 1)) == 0;
|
||||
return (position & (KMemoryManager.PageSize - 1)) == 0;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -7,458 +7,458 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private void CreateThread64(CpuThreadState ThreadState)
|
||||
private void CreateThread64(CpuThreadState threadState)
|
||||
{
|
||||
ulong Entrypoint = ThreadState.X1;
|
||||
ulong ArgsPtr = ThreadState.X2;
|
||||
ulong StackTop = ThreadState.X3;
|
||||
int Priority = (int)ThreadState.X4;
|
||||
int CpuCore = (int)ThreadState.X5;
|
||||
ulong entrypoint = threadState.X1;
|
||||
ulong argsPtr = threadState.X2;
|
||||
ulong stackTop = threadState.X3;
|
||||
int priority = (int)threadState.X4;
|
||||
int cpuCore = (int)threadState.X5;
|
||||
|
||||
KernelResult Result = CreateThread(Entrypoint, ArgsPtr, StackTop, Priority, CpuCore, out int Handle);
|
||||
KernelResult result = CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out int handle);
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
ThreadState.X1 = (ulong)Handle;
|
||||
threadState.X0 = (ulong)result;
|
||||
threadState.X1 = (ulong)handle;
|
||||
}
|
||||
|
||||
private KernelResult CreateThread(
|
||||
ulong Entrypoint,
|
||||
ulong ArgsPtr,
|
||||
ulong StackTop,
|
||||
int Priority,
|
||||
int CpuCore,
|
||||
out int Handle)
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int cpuCore,
|
||||
out int handle)
|
||||
{
|
||||
Handle = 0;
|
||||
handle = 0;
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (CpuCore == -2)
|
||||
if (cpuCore == -2)
|
||||
{
|
||||
CpuCore = CurrentProcess.DefaultCpuCore;
|
||||
cpuCore = currentProcess.DefaultCpuCore;
|
||||
}
|
||||
|
||||
if ((uint)CpuCore >= KScheduler.CpuCoresCount || !CurrentProcess.IsCpuCoreAllowed(CpuCore))
|
||||
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore))
|
||||
{
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
|
||||
if ((uint)Priority >= KScheduler.PrioritiesCount || !CurrentProcess.IsPriorityAllowed(Priority))
|
||||
if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority))
|
||||
{
|
||||
return KernelResult.InvalidPriority;
|
||||
}
|
||||
|
||||
long Timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
|
||||
long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
|
||||
|
||||
if (CurrentProcess.ResourceLimit != null &&
|
||||
!CurrentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, Timeout))
|
||||
if (currentProcess.ResourceLimit != null &&
|
||||
!currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout))
|
||||
{
|
||||
return KernelResult.ResLimitExceeded;
|
||||
}
|
||||
|
||||
KThread Thread = new KThread(System);
|
||||
KThread thread = new KThread(_system);
|
||||
|
||||
KernelResult Result = CurrentProcess.InitializeThread(
|
||||
Thread,
|
||||
Entrypoint,
|
||||
ArgsPtr,
|
||||
StackTop,
|
||||
Priority,
|
||||
CpuCore);
|
||||
KernelResult result = currentProcess.InitializeThread(
|
||||
thread,
|
||||
entrypoint,
|
||||
argsPtr,
|
||||
stackTop,
|
||||
priority,
|
||||
cpuCore);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
CurrentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
Result = Process.HandleTable.GenerateHandle(Thread, out Handle);
|
||||
result = _process.HandleTable.GenerateHandle(thread, out handle);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Thread.Terminate();
|
||||
thread.Terminate();
|
||||
|
||||
CurrentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||
}
|
||||
|
||||
return Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SvcStartThread(CpuThreadState ThreadState)
|
||||
private void SvcStartThread(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
int handle = (int)threadState.X0;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
|
||||
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
|
||||
|
||||
if (Thread != null)
|
||||
if (thread != null)
|
||||
{
|
||||
KernelResult Result = Thread.Start();
|
||||
KernelResult result = thread.Start();
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcExitThread(CpuThreadState ThreadState)
|
||||
private void SvcExitThread(CpuThreadState threadState)
|
||||
{
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
System.Scheduler.ExitThread(CurrentThread);
|
||||
_system.Scheduler.ExitThread(currentThread);
|
||||
|
||||
CurrentThread.Exit();
|
||||
currentThread.Exit();
|
||||
}
|
||||
|
||||
private void SvcSleepThread(CpuThreadState ThreadState)
|
||||
private void SvcSleepThread(CpuThreadState threadState)
|
||||
{
|
||||
long Timeout = (long)ThreadState.X0;
|
||||
long timeout = (long)threadState.X0;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + Timeout.ToString("x16"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + timeout.ToString("x16"));
|
||||
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
if (Timeout < 1)
|
||||
if (timeout < 1)
|
||||
{
|
||||
switch (Timeout)
|
||||
switch (timeout)
|
||||
{
|
||||
case 0: CurrentThread.Yield(); break;
|
||||
case -1: CurrentThread.YieldWithLoadBalancing(); break;
|
||||
case -2: CurrentThread.YieldAndWaitForLoadBalancing(); break;
|
||||
case 0: currentThread.Yield(); break;
|
||||
case -1: currentThread.YieldWithLoadBalancing(); break;
|
||||
case -2: currentThread.YieldAndWaitForLoadBalancing(); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentThread.Sleep(Timeout);
|
||||
currentThread.Sleep(timeout);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
threadState.X0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcGetThreadPriority(CpuThreadState ThreadState)
|
||||
private void SvcGetThreadPriority(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X1;
|
||||
int handle = (int)threadState.X1;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
KThread thread = _process.HandleTable.GetKThread(handle);
|
||||
|
||||
if (Thread != null)
|
||||
if (thread != null)
|
||||
{
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = (ulong)Thread.DynamicPriority;
|
||||
threadState.X0 = 0;
|
||||
threadState.X1 = (ulong)thread.DynamicPriority;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcSetThreadPriority(CpuThreadState ThreadState)
|
||||
private void SvcSetThreadPriority(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
int Priority = (int)ThreadState.X1;
|
||||
int handle = (int)threadState.X0;
|
||||
int priority = (int)threadState.X1;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Handle = 0x" + Handle .ToString("x8") + ", " +
|
||||
"Priority = 0x" + Priority.ToString("x8"));
|
||||
"Handle = 0x" + handle .ToString("x8") + ", " +
|
||||
"Priority = 0x" + priority.ToString("x8"));
|
||||
|
||||
//TODO: NPDM check.
|
||||
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
KThread thread = _process.HandleTable.GetKThread(handle);
|
||||
|
||||
if (Thread == null)
|
||||
if (thread == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.SetPriority(Priority);
|
||||
thread.SetPriority(priority);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
threadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void SvcGetThreadCoreMask(CpuThreadState ThreadState)
|
||||
private void SvcGetThreadCoreMask(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X2;
|
||||
int handle = (int)threadState.X2;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle.ToString("x8"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + handle.ToString("x8"));
|
||||
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
KThread thread = _process.HandleTable.GetKThread(handle);
|
||||
|
||||
if (Thread != null)
|
||||
if (thread != null)
|
||||
{
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = (ulong)Thread.PreferredCore;
|
||||
ThreadState.X2 = (ulong)Thread.AffinityMask;
|
||||
threadState.X0 = 0;
|
||||
threadState.X1 = (ulong)thread.PreferredCore;
|
||||
threadState.X2 = (ulong)thread.AffinityMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetThreadCoreMask64(CpuThreadState ThreadState)
|
||||
private void SetThreadCoreMask64(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
int PreferredCore = (int)ThreadState.X1;
|
||||
long AffinityMask = (long)ThreadState.X2;
|
||||
int handle = (int)threadState.X0;
|
||||
int preferredCore = (int)threadState.X1;
|
||||
long affinityMask = (long)threadState.X2;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Handle = 0x" + Handle .ToString("x8") + ", " +
|
||||
"PreferredCore = 0x" + PreferredCore.ToString("x8") + ", " +
|
||||
"AffinityMask = 0x" + AffinityMask .ToString("x16"));
|
||||
"Handle = 0x" + handle .ToString("x8") + ", " +
|
||||
"PreferredCore = 0x" + preferredCore.ToString("x8") + ", " +
|
||||
"AffinityMask = 0x" + affinityMask .ToString("x16"));
|
||||
|
||||
KernelResult Result = SetThreadCoreMask(Handle, PreferredCore, AffinityMask);
|
||||
KernelResult result = SetThreadCoreMask(handle, preferredCore, affinityMask);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{Result}\".");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private KernelResult SetThreadCoreMask(int Handle, int PreferredCore, long AffinityMask)
|
||||
private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
|
||||
{
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if (PreferredCore == -2)
|
||||
if (preferredCore == -2)
|
||||
{
|
||||
PreferredCore = CurrentProcess.DefaultCpuCore;
|
||||
preferredCore = currentProcess.DefaultCpuCore;
|
||||
|
||||
AffinityMask = 1 << PreferredCore;
|
||||
affinityMask = 1 << preferredCore;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((CurrentProcess.Capabilities.AllowedCpuCoresMask | AffinityMask) !=
|
||||
CurrentProcess.Capabilities.AllowedCpuCoresMask)
|
||||
if ((currentProcess.Capabilities.AllowedCpuCoresMask | affinityMask) !=
|
||||
currentProcess.Capabilities.AllowedCpuCoresMask)
|
||||
{
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
|
||||
if (AffinityMask == 0)
|
||||
if (affinityMask == 0)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if ((uint)PreferredCore > 3)
|
||||
if ((uint)preferredCore > 3)
|
||||
{
|
||||
if ((PreferredCore | 2) != -1)
|
||||
if ((preferredCore | 2) != -1)
|
||||
{
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
}
|
||||
else if ((AffinityMask & (1 << PreferredCore)) == 0)
|
||||
else if ((affinityMask & (1 << preferredCore)) == 0)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
}
|
||||
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
KThread thread = _process.HandleTable.GetKThread(handle);
|
||||
|
||||
if (Thread == null)
|
||||
if (thread == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
return Thread.SetCoreAndAffinityMask(PreferredCore, AffinityMask);
|
||||
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
|
||||
}
|
||||
|
||||
private void SvcGetCurrentProcessorNumber(CpuThreadState ThreadState)
|
||||
private void SvcGetCurrentProcessorNumber(CpuThreadState threadState)
|
||||
{
|
||||
ThreadState.X0 = (ulong)System.Scheduler.GetCurrentThread().CurrentCore;
|
||||
threadState.X0 = (ulong)_system.Scheduler.GetCurrentThread().CurrentCore;
|
||||
}
|
||||
|
||||
private void SvcGetThreadId(CpuThreadState ThreadState)
|
||||
private void SvcGetThreadId(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X1;
|
||||
int handle = (int)threadState.X1;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
KThread thread = _process.HandleTable.GetKThread(handle);
|
||||
|
||||
if (Thread != null)
|
||||
if (thread != null)
|
||||
{
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = (ulong)Thread.ThreadUid;
|
||||
threadState.X0 = 0;
|
||||
threadState.X1 = (ulong)thread.ThreadUid;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcSetThreadActivity(CpuThreadState ThreadState)
|
||||
private void SvcSetThreadActivity(CpuThreadState threadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
bool Pause = (int)ThreadState.X1 == 1;
|
||||
int handle = (int)threadState.X0;
|
||||
bool pause = (int)threadState.X1 == 1;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
|
||||
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
|
||||
|
||||
if (Thread == null)
|
||||
if (thread == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Thread.Owner != System.Scheduler.GetCurrentProcess())
|
||||
if (thread.Owner != _system.Scheduler.GetCurrentProcess())
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Thread == System.Scheduler.GetCurrentThread())
|
||||
if (thread == _system.Scheduler.GetCurrentThread())
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted.");
|
||||
|
||||
ThreadState.X0 = (ulong)KernelResult.InvalidThread;
|
||||
threadState.X0 = (ulong)KernelResult.InvalidThread;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long Result = Thread.SetActivity(Pause);
|
||||
long result = thread.SetActivity(pause);
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcGetThreadContext3(CpuThreadState ThreadState)
|
||||
private void SvcGetThreadContext3(CpuThreadState threadState)
|
||||
{
|
||||
long Position = (long)ThreadState.X0;
|
||||
int Handle = (int)ThreadState.X1;
|
||||
long position = (long)threadState.X0;
|
||||
int handle = (int)threadState.X1;
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
KThread currentThread = _system.Scheduler.GetCurrentThread();
|
||||
|
||||
KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
|
||||
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
|
||||
|
||||
if (Thread == null)
|
||||
if (thread == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Thread.Owner != CurrentProcess)
|
||||
if (thread.Owner != currentProcess)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentThread == Thread)
|
||||
if (currentThread == thread)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted.");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Memory.WriteUInt64(Position + 0x0, Thread.Context.ThreadState.X0);
|
||||
Memory.WriteUInt64(Position + 0x8, Thread.Context.ThreadState.X1);
|
||||
Memory.WriteUInt64(Position + 0x10, Thread.Context.ThreadState.X2);
|
||||
Memory.WriteUInt64(Position + 0x18, Thread.Context.ThreadState.X3);
|
||||
Memory.WriteUInt64(Position + 0x20, Thread.Context.ThreadState.X4);
|
||||
Memory.WriteUInt64(Position + 0x28, Thread.Context.ThreadState.X5);
|
||||
Memory.WriteUInt64(Position + 0x30, Thread.Context.ThreadState.X6);
|
||||
Memory.WriteUInt64(Position + 0x38, Thread.Context.ThreadState.X7);
|
||||
Memory.WriteUInt64(Position + 0x40, Thread.Context.ThreadState.X8);
|
||||
Memory.WriteUInt64(Position + 0x48, Thread.Context.ThreadState.X9);
|
||||
Memory.WriteUInt64(Position + 0x50, Thread.Context.ThreadState.X10);
|
||||
Memory.WriteUInt64(Position + 0x58, Thread.Context.ThreadState.X11);
|
||||
Memory.WriteUInt64(Position + 0x60, Thread.Context.ThreadState.X12);
|
||||
Memory.WriteUInt64(Position + 0x68, Thread.Context.ThreadState.X13);
|
||||
Memory.WriteUInt64(Position + 0x70, Thread.Context.ThreadState.X14);
|
||||
Memory.WriteUInt64(Position + 0x78, Thread.Context.ThreadState.X15);
|
||||
Memory.WriteUInt64(Position + 0x80, Thread.Context.ThreadState.X16);
|
||||
Memory.WriteUInt64(Position + 0x88, Thread.Context.ThreadState.X17);
|
||||
Memory.WriteUInt64(Position + 0x90, Thread.Context.ThreadState.X18);
|
||||
Memory.WriteUInt64(Position + 0x98, Thread.Context.ThreadState.X19);
|
||||
Memory.WriteUInt64(Position + 0xa0, Thread.Context.ThreadState.X20);
|
||||
Memory.WriteUInt64(Position + 0xa8, Thread.Context.ThreadState.X21);
|
||||
Memory.WriteUInt64(Position + 0xb0, Thread.Context.ThreadState.X22);
|
||||
Memory.WriteUInt64(Position + 0xb8, Thread.Context.ThreadState.X23);
|
||||
Memory.WriteUInt64(Position + 0xc0, Thread.Context.ThreadState.X24);
|
||||
Memory.WriteUInt64(Position + 0xc8, Thread.Context.ThreadState.X25);
|
||||
Memory.WriteUInt64(Position + 0xd0, Thread.Context.ThreadState.X26);
|
||||
Memory.WriteUInt64(Position + 0xd8, Thread.Context.ThreadState.X27);
|
||||
Memory.WriteUInt64(Position + 0xe0, Thread.Context.ThreadState.X28);
|
||||
Memory.WriteUInt64(Position + 0xe8, Thread.Context.ThreadState.X29);
|
||||
Memory.WriteUInt64(Position + 0xf0, Thread.Context.ThreadState.X30);
|
||||
Memory.WriteUInt64(Position + 0xf8, Thread.Context.ThreadState.X31);
|
||||
_memory.WriteUInt64(position + 0x0, thread.Context.ThreadState.X0);
|
||||
_memory.WriteUInt64(position + 0x8, thread.Context.ThreadState.X1);
|
||||
_memory.WriteUInt64(position + 0x10, thread.Context.ThreadState.X2);
|
||||
_memory.WriteUInt64(position + 0x18, thread.Context.ThreadState.X3);
|
||||
_memory.WriteUInt64(position + 0x20, thread.Context.ThreadState.X4);
|
||||
_memory.WriteUInt64(position + 0x28, thread.Context.ThreadState.X5);
|
||||
_memory.WriteUInt64(position + 0x30, thread.Context.ThreadState.X6);
|
||||
_memory.WriteUInt64(position + 0x38, thread.Context.ThreadState.X7);
|
||||
_memory.WriteUInt64(position + 0x40, thread.Context.ThreadState.X8);
|
||||
_memory.WriteUInt64(position + 0x48, thread.Context.ThreadState.X9);
|
||||
_memory.WriteUInt64(position + 0x50, thread.Context.ThreadState.X10);
|
||||
_memory.WriteUInt64(position + 0x58, thread.Context.ThreadState.X11);
|
||||
_memory.WriteUInt64(position + 0x60, thread.Context.ThreadState.X12);
|
||||
_memory.WriteUInt64(position + 0x68, thread.Context.ThreadState.X13);
|
||||
_memory.WriteUInt64(position + 0x70, thread.Context.ThreadState.X14);
|
||||
_memory.WriteUInt64(position + 0x78, thread.Context.ThreadState.X15);
|
||||
_memory.WriteUInt64(position + 0x80, thread.Context.ThreadState.X16);
|
||||
_memory.WriteUInt64(position + 0x88, thread.Context.ThreadState.X17);
|
||||
_memory.WriteUInt64(position + 0x90, thread.Context.ThreadState.X18);
|
||||
_memory.WriteUInt64(position + 0x98, thread.Context.ThreadState.X19);
|
||||
_memory.WriteUInt64(position + 0xa0, thread.Context.ThreadState.X20);
|
||||
_memory.WriteUInt64(position + 0xa8, thread.Context.ThreadState.X21);
|
||||
_memory.WriteUInt64(position + 0xb0, thread.Context.ThreadState.X22);
|
||||
_memory.WriteUInt64(position + 0xb8, thread.Context.ThreadState.X23);
|
||||
_memory.WriteUInt64(position + 0xc0, thread.Context.ThreadState.X24);
|
||||
_memory.WriteUInt64(position + 0xc8, thread.Context.ThreadState.X25);
|
||||
_memory.WriteUInt64(position + 0xd0, thread.Context.ThreadState.X26);
|
||||
_memory.WriteUInt64(position + 0xd8, thread.Context.ThreadState.X27);
|
||||
_memory.WriteUInt64(position + 0xe0, thread.Context.ThreadState.X28);
|
||||
_memory.WriteUInt64(position + 0xe8, thread.Context.ThreadState.X29);
|
||||
_memory.WriteUInt64(position + 0xf0, thread.Context.ThreadState.X30);
|
||||
_memory.WriteUInt64(position + 0xf8, thread.Context.ThreadState.X31);
|
||||
|
||||
Memory.WriteInt64(Position + 0x100, Thread.LastPc);
|
||||
_memory.WriteInt64(position + 0x100, thread.LastPc);
|
||||
|
||||
Memory.WriteUInt64(Position + 0x108, (ulong)Thread.Context.ThreadState.Psr);
|
||||
_memory.WriteUInt64(position + 0x108, (ulong)thread.Context.ThreadState.Psr);
|
||||
|
||||
Memory.WriteVector128(Position + 0x110, Thread.Context.ThreadState.V0);
|
||||
Memory.WriteVector128(Position + 0x120, Thread.Context.ThreadState.V1);
|
||||
Memory.WriteVector128(Position + 0x130, Thread.Context.ThreadState.V2);
|
||||
Memory.WriteVector128(Position + 0x140, Thread.Context.ThreadState.V3);
|
||||
Memory.WriteVector128(Position + 0x150, Thread.Context.ThreadState.V4);
|
||||
Memory.WriteVector128(Position + 0x160, Thread.Context.ThreadState.V5);
|
||||
Memory.WriteVector128(Position + 0x170, Thread.Context.ThreadState.V6);
|
||||
Memory.WriteVector128(Position + 0x180, Thread.Context.ThreadState.V7);
|
||||
Memory.WriteVector128(Position + 0x190, Thread.Context.ThreadState.V8);
|
||||
Memory.WriteVector128(Position + 0x1a0, Thread.Context.ThreadState.V9);
|
||||
Memory.WriteVector128(Position + 0x1b0, Thread.Context.ThreadState.V10);
|
||||
Memory.WriteVector128(Position + 0x1c0, Thread.Context.ThreadState.V11);
|
||||
Memory.WriteVector128(Position + 0x1d0, Thread.Context.ThreadState.V12);
|
||||
Memory.WriteVector128(Position + 0x1e0, Thread.Context.ThreadState.V13);
|
||||
Memory.WriteVector128(Position + 0x1f0, Thread.Context.ThreadState.V14);
|
||||
Memory.WriteVector128(Position + 0x200, Thread.Context.ThreadState.V15);
|
||||
Memory.WriteVector128(Position + 0x210, Thread.Context.ThreadState.V16);
|
||||
Memory.WriteVector128(Position + 0x220, Thread.Context.ThreadState.V17);
|
||||
Memory.WriteVector128(Position + 0x230, Thread.Context.ThreadState.V18);
|
||||
Memory.WriteVector128(Position + 0x240, Thread.Context.ThreadState.V19);
|
||||
Memory.WriteVector128(Position + 0x250, Thread.Context.ThreadState.V20);
|
||||
Memory.WriteVector128(Position + 0x260, Thread.Context.ThreadState.V21);
|
||||
Memory.WriteVector128(Position + 0x270, Thread.Context.ThreadState.V22);
|
||||
Memory.WriteVector128(Position + 0x280, Thread.Context.ThreadState.V23);
|
||||
Memory.WriteVector128(Position + 0x290, Thread.Context.ThreadState.V24);
|
||||
Memory.WriteVector128(Position + 0x2a0, Thread.Context.ThreadState.V25);
|
||||
Memory.WriteVector128(Position + 0x2b0, Thread.Context.ThreadState.V26);
|
||||
Memory.WriteVector128(Position + 0x2c0, Thread.Context.ThreadState.V27);
|
||||
Memory.WriteVector128(Position + 0x2d0, Thread.Context.ThreadState.V28);
|
||||
Memory.WriteVector128(Position + 0x2e0, Thread.Context.ThreadState.V29);
|
||||
Memory.WriteVector128(Position + 0x2f0, Thread.Context.ThreadState.V30);
|
||||
Memory.WriteVector128(Position + 0x300, Thread.Context.ThreadState.V31);
|
||||
_memory.WriteVector128(position + 0x110, thread.Context.ThreadState.V0);
|
||||
_memory.WriteVector128(position + 0x120, thread.Context.ThreadState.V1);
|
||||
_memory.WriteVector128(position + 0x130, thread.Context.ThreadState.V2);
|
||||
_memory.WriteVector128(position + 0x140, thread.Context.ThreadState.V3);
|
||||
_memory.WriteVector128(position + 0x150, thread.Context.ThreadState.V4);
|
||||
_memory.WriteVector128(position + 0x160, thread.Context.ThreadState.V5);
|
||||
_memory.WriteVector128(position + 0x170, thread.Context.ThreadState.V6);
|
||||
_memory.WriteVector128(position + 0x180, thread.Context.ThreadState.V7);
|
||||
_memory.WriteVector128(position + 0x190, thread.Context.ThreadState.V8);
|
||||
_memory.WriteVector128(position + 0x1a0, thread.Context.ThreadState.V9);
|
||||
_memory.WriteVector128(position + 0x1b0, thread.Context.ThreadState.V10);
|
||||
_memory.WriteVector128(position + 0x1c0, thread.Context.ThreadState.V11);
|
||||
_memory.WriteVector128(position + 0x1d0, thread.Context.ThreadState.V12);
|
||||
_memory.WriteVector128(position + 0x1e0, thread.Context.ThreadState.V13);
|
||||
_memory.WriteVector128(position + 0x1f0, thread.Context.ThreadState.V14);
|
||||
_memory.WriteVector128(position + 0x200, thread.Context.ThreadState.V15);
|
||||
_memory.WriteVector128(position + 0x210, thread.Context.ThreadState.V16);
|
||||
_memory.WriteVector128(position + 0x220, thread.Context.ThreadState.V17);
|
||||
_memory.WriteVector128(position + 0x230, thread.Context.ThreadState.V18);
|
||||
_memory.WriteVector128(position + 0x240, thread.Context.ThreadState.V19);
|
||||
_memory.WriteVector128(position + 0x250, thread.Context.ThreadState.V20);
|
||||
_memory.WriteVector128(position + 0x260, thread.Context.ThreadState.V21);
|
||||
_memory.WriteVector128(position + 0x270, thread.Context.ThreadState.V22);
|
||||
_memory.WriteVector128(position + 0x280, thread.Context.ThreadState.V23);
|
||||
_memory.WriteVector128(position + 0x290, thread.Context.ThreadState.V24);
|
||||
_memory.WriteVector128(position + 0x2a0, thread.Context.ThreadState.V25);
|
||||
_memory.WriteVector128(position + 0x2b0, thread.Context.ThreadState.V26);
|
||||
_memory.WriteVector128(position + 0x2c0, thread.Context.ThreadState.V27);
|
||||
_memory.WriteVector128(position + 0x2d0, thread.Context.ThreadState.V28);
|
||||
_memory.WriteVector128(position + 0x2e0, thread.Context.ThreadState.V29);
|
||||
_memory.WriteVector128(position + 0x2f0, thread.Context.ThreadState.V30);
|
||||
_memory.WriteVector128(position + 0x300, thread.Context.ThreadState.V31);
|
||||
|
||||
Memory.WriteInt32(Position + 0x310, Thread.Context.ThreadState.Fpcr);
|
||||
Memory.WriteInt32(Position + 0x314, Thread.Context.ThreadState.Fpsr);
|
||||
Memory.WriteInt64(Position + 0x318, Thread.Context.ThreadState.Tpidr);
|
||||
_memory.WriteInt32(position + 0x310, thread.Context.ThreadState.Fpcr);
|
||||
_memory.WriteInt32(position + 0x314, thread.Context.ThreadState.Fpsr);
|
||||
_memory.WriteInt64(position + 0x318, thread.Context.ThreadState.Tpidr);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
threadState.X0 = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,366 +8,366 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
private void SvcWaitSynchronization(CpuThreadState ThreadState)
|
||||
private void SvcWaitSynchronization(CpuThreadState threadState)
|
||||
{
|
||||
long HandlesPtr = (long)ThreadState.X1;
|
||||
int HandlesCount = (int)ThreadState.X2;
|
||||
long Timeout = (long)ThreadState.X3;
|
||||
long handlesPtr = (long)threadState.X1;
|
||||
int handlesCount = (int)threadState.X2;
|
||||
long timeout = (long)threadState.X3;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"HandlesPtr = 0x" + HandlesPtr .ToString("x16") + ", " +
|
||||
"HandlesCount = 0x" + HandlesCount.ToString("x8") + ", " +
|
||||
"Timeout = 0x" + Timeout .ToString("x16"));
|
||||
"HandlesPtr = 0x" + handlesPtr .ToString("x16") + ", " +
|
||||
"HandlesCount = 0x" + handlesCount.ToString("x8") + ", " +
|
||||
"Timeout = 0x" + timeout .ToString("x16"));
|
||||
|
||||
if ((uint)HandlesCount > 0x40)
|
||||
if ((uint)handlesCount > 0x40)
|
||||
{
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
List<KSynchronizationObject> SyncObjs = new List<KSynchronizationObject>();
|
||||
List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
|
||||
|
||||
for (int Index = 0; Index < HandlesCount; Index++)
|
||||
for (int index = 0; index < handlesCount; index++)
|
||||
{
|
||||
int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
|
||||
int handle = _memory.ReadInt32(handlesPtr + index * 4);
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Sync handle 0x{Handle:x8}");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Sync handle 0x{handle:x8}");
|
||||
|
||||
KSynchronizationObject SyncObj = Process.HandleTable.GetObject<KSynchronizationObject>(Handle);
|
||||
KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
|
||||
|
||||
if (SyncObj == null)
|
||||
if (syncObj == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
SyncObjs.Add(SyncObj);
|
||||
syncObjs.Add(syncObj);
|
||||
}
|
||||
|
||||
int HndIndex = (int)ThreadState.X1;
|
||||
int hndIndex = (int)threadState.X1;
|
||||
|
||||
ulong High = ThreadState.X1 & (0xffffffffUL << 32);
|
||||
ulong high = threadState.X1 & (0xffffffffUL << 32);
|
||||
|
||||
long Result = System.Synchronization.WaitFor(SyncObjs.ToArray(), Timeout, ref HndIndex);
|
||||
long result = _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, ref hndIndex);
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
if (Result == MakeError(ErrorModule.Kernel, KernelErr.Timeout) ||
|
||||
Result == MakeError(ErrorModule.Kernel, KernelErr.Cancelled))
|
||||
if (result == MakeError(ErrorModule.Kernel, KernelErr.Timeout) ||
|
||||
result == MakeError(ErrorModule.Kernel, KernelErr.Cancelled))
|
||||
{
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
ThreadState.X1 = (uint)HndIndex | High;
|
||||
threadState.X0 = (ulong)result;
|
||||
threadState.X1 = (uint)hndIndex | high;
|
||||
}
|
||||
|
||||
private void SvcCancelSynchronization(CpuThreadState ThreadState)
|
||||
private void SvcCancelSynchronization(CpuThreadState threadState)
|
||||
{
|
||||
int ThreadHandle = (int)ThreadState.X0;
|
||||
int threadHandle = (int)threadState.X0;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + ThreadHandle.ToString("x8"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + threadHandle.ToString("x8"));
|
||||
|
||||
KThread Thread = Process.HandleTable.GetKThread(ThreadHandle);
|
||||
KThread thread = _process.HandleTable.GetKThread(threadHandle);
|
||||
|
||||
if (Thread == null)
|
||||
if (thread == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{threadHandle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.CancelSynchronization();
|
||||
thread.CancelSynchronization();
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
threadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void SvcArbitrateLock(CpuThreadState ThreadState)
|
||||
private void SvcArbitrateLock(CpuThreadState threadState)
|
||||
{
|
||||
int OwnerHandle = (int)ThreadState.X0;
|
||||
long MutexAddress = (long)ThreadState.X1;
|
||||
int RequesterHandle = (int)ThreadState.X2;
|
||||
int ownerHandle = (int)threadState.X0;
|
||||
long mutexAddress = (long)threadState.X1;
|
||||
int requesterHandle = (int)threadState.X2;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"OwnerHandle = 0x" + OwnerHandle .ToString("x8") + ", " +
|
||||
"MutexAddress = 0x" + MutexAddress .ToString("x16") + ", " +
|
||||
"RequesterHandle = 0x" + RequesterHandle.ToString("x8"));
|
||||
"OwnerHandle = 0x" + ownerHandle .ToString("x8") + ", " +
|
||||
"MutexAddress = 0x" + mutexAddress .ToString("x16") + ", " +
|
||||
"RequesterHandle = 0x" + requesterHandle.ToString("x8"));
|
||||
|
||||
if (IsPointingInsideKernel(MutexAddress))
|
||||
if (IsPointingInsideKernel(mutexAddress))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAddressNotWordAligned(MutexAddress))
|
||||
if (IsAddressNotWordAligned(mutexAddress))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
long Result = CurrentProcess.AddressArbiter.ArbitrateLock(OwnerHandle, MutexAddress, RequesterHandle);
|
||||
long result = currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcArbitrateUnlock(CpuThreadState ThreadState)
|
||||
private void SvcArbitrateUnlock(CpuThreadState threadState)
|
||||
{
|
||||
long MutexAddress = (long)ThreadState.X0;
|
||||
long mutexAddress = (long)threadState.X0;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + MutexAddress.ToString("x16"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + mutexAddress.ToString("x16"));
|
||||
|
||||
if (IsPointingInsideKernel(MutexAddress))
|
||||
if (IsPointingInsideKernel(mutexAddress))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAddressNotWordAligned(MutexAddress))
|
||||
if (IsAddressNotWordAligned(mutexAddress))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
long Result = CurrentProcess.AddressArbiter.ArbitrateUnlock(MutexAddress);
|
||||
long result = currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcWaitProcessWideKeyAtomic(CpuThreadState ThreadState)
|
||||
private void SvcWaitProcessWideKeyAtomic(CpuThreadState threadState)
|
||||
{
|
||||
long MutexAddress = (long)ThreadState.X0;
|
||||
long CondVarAddress = (long)ThreadState.X1;
|
||||
int ThreadHandle = (int)ThreadState.X2;
|
||||
long Timeout = (long)ThreadState.X3;
|
||||
long mutexAddress = (long)threadState.X0;
|
||||
long condVarAddress = (long)threadState.X1;
|
||||
int threadHandle = (int)threadState.X2;
|
||||
long timeout = (long)threadState.X3;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"MutexAddress = 0x" + MutexAddress .ToString("x16") + ", " +
|
||||
"CondVarAddress = 0x" + CondVarAddress.ToString("x16") + ", " +
|
||||
"ThreadHandle = 0x" + ThreadHandle .ToString("x8") + ", " +
|
||||
"Timeout = 0x" + Timeout .ToString("x16"));
|
||||
"MutexAddress = 0x" + mutexAddress .ToString("x16") + ", " +
|
||||
"CondVarAddress = 0x" + condVarAddress.ToString("x16") + ", " +
|
||||
"ThreadHandle = 0x" + threadHandle .ToString("x8") + ", " +
|
||||
"Timeout = 0x" + timeout .ToString("x16"));
|
||||
|
||||
if (IsPointingInsideKernel(MutexAddress))
|
||||
if (IsPointingInsideKernel(mutexAddress))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAddressNotWordAligned(MutexAddress))
|
||||
if (IsAddressNotWordAligned(mutexAddress))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
long Result = CurrentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
|
||||
MutexAddress,
|
||||
CondVarAddress,
|
||||
ThreadHandle,
|
||||
Timeout);
|
||||
long result = currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
|
||||
mutexAddress,
|
||||
condVarAddress,
|
||||
threadHandle,
|
||||
timeout);
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
if (Result == MakeError(ErrorModule.Kernel, KernelErr.Timeout))
|
||||
if (result == MakeError(ErrorModule.Kernel, KernelErr.Timeout))
|
||||
{
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcSignalProcessWideKey(CpuThreadState ThreadState)
|
||||
private void SvcSignalProcessWideKey(CpuThreadState threadState)
|
||||
{
|
||||
long Address = (long)ThreadState.X0;
|
||||
int Count = (int)ThreadState.X1;
|
||||
long address = (long)threadState.X0;
|
||||
int count = (int)threadState.X1;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Address = 0x" + Address.ToString("x16") + ", " +
|
||||
"Count = 0x" + Count .ToString("x8"));
|
||||
"Address = 0x" + address.ToString("x16") + ", " +
|
||||
"Count = 0x" + count .ToString("x8"));
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
CurrentProcess.AddressArbiter.SignalProcessWideKey(Address, Count);
|
||||
currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
threadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void SvcWaitForAddress(CpuThreadState ThreadState)
|
||||
private void SvcWaitForAddress(CpuThreadState threadState)
|
||||
{
|
||||
long Address = (long)ThreadState.X0;
|
||||
ArbitrationType Type = (ArbitrationType)ThreadState.X1;
|
||||
int Value = (int)ThreadState.X2;
|
||||
long Timeout = (long)ThreadState.X3;
|
||||
long address = (long)threadState.X0;
|
||||
ArbitrationType type = (ArbitrationType)threadState.X1;
|
||||
int value = (int)threadState.X2;
|
||||
long timeout = (long)threadState.X3;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Address = 0x" + Address.ToString("x16") + ", " +
|
||||
"Type = " + Type .ToString() + ", " +
|
||||
"Value = 0x" + Value .ToString("x8") + ", " +
|
||||
"Timeout = 0x" + Timeout.ToString("x16"));
|
||||
"Address = 0x" + address.ToString("x16") + ", " +
|
||||
"Type = " + type .ToString() + ", " +
|
||||
"Value = 0x" + value .ToString("x8") + ", " +
|
||||
"Timeout = 0x" + timeout.ToString("x16"));
|
||||
|
||||
if (IsPointingInsideKernel(Address))
|
||||
if (IsPointingInsideKernel(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAddressNotWordAligned(Address))
|
||||
if (IsAddressNotWordAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
long Result;
|
||||
long result;
|
||||
|
||||
switch (Type)
|
||||
switch (type)
|
||||
{
|
||||
case ArbitrationType.WaitIfLessThan:
|
||||
Result = CurrentProcess.AddressArbiter.WaitForAddressIfLessThan(Address, Value, false, Timeout);
|
||||
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout);
|
||||
break;
|
||||
|
||||
case ArbitrationType.DecrementAndWaitIfLessThan:
|
||||
Result = CurrentProcess.AddressArbiter.WaitForAddressIfLessThan(Address, Value, true, Timeout);
|
||||
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout);
|
||||
break;
|
||||
|
||||
case ArbitrationType.WaitIfEqual:
|
||||
Result = CurrentProcess.AddressArbiter.WaitForAddressIfEqual(Address, Value, Timeout);
|
||||
result = currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout);
|
||||
break;
|
||||
|
||||
default:
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
||||
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private void SvcSignalToAddress(CpuThreadState ThreadState)
|
||||
private void SvcSignalToAddress(CpuThreadState threadState)
|
||||
{
|
||||
long Address = (long)ThreadState.X0;
|
||||
SignalType Type = (SignalType)ThreadState.X1;
|
||||
int Value = (int)ThreadState.X2;
|
||||
int Count = (int)ThreadState.X3;
|
||||
long address = (long)threadState.X0;
|
||||
SignalType type = (SignalType)threadState.X1;
|
||||
int value = (int)threadState.X2;
|
||||
int count = (int)threadState.X3;
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Address = 0x" + Address.ToString("x16") + ", " +
|
||||
"Type = " + Type .ToString() + ", " +
|
||||
"Value = 0x" + Value .ToString("x8") + ", " +
|
||||
"Count = 0x" + Count .ToString("x8"));
|
||||
"Address = 0x" + address.ToString("x16") + ", " +
|
||||
"Type = " + type .ToString() + ", " +
|
||||
"Value = 0x" + value .ToString("x8") + ", " +
|
||||
"Count = 0x" + count .ToString("x8"));
|
||||
|
||||
if (IsPointingInsideKernel(Address))
|
||||
if (IsPointingInsideKernel(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAddressNotWordAligned(Address))
|
||||
if (IsAddressNotWordAligned(address))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KProcess CurrentProcess = System.Scheduler.GetCurrentProcess();
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
long Result;
|
||||
long result;
|
||||
|
||||
switch (Type)
|
||||
switch (type)
|
||||
{
|
||||
case SignalType.Signal:
|
||||
Result = CurrentProcess.AddressArbiter.Signal(Address, Count);
|
||||
result = currentProcess.AddressArbiter.Signal(address, count);
|
||||
break;
|
||||
|
||||
case SignalType.SignalAndIncrementIfEqual:
|
||||
Result = CurrentProcess.AddressArbiter.SignalAndIncrementIfEqual(Address, Value, Count);
|
||||
result = currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count);
|
||||
break;
|
||||
|
||||
case SignalType.SignalAndModifyIfEqual:
|
||||
Result = CurrentProcess.AddressArbiter.SignalAndModifyIfEqual(Address, Value, Count);
|
||||
result = currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count);
|
||||
break;
|
||||
|
||||
default:
|
||||
Result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
||||
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Result != 0)
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
threadState.X0 = (ulong)result;
|
||||
}
|
||||
|
||||
private bool IsPointingInsideKernel(long Address)
|
||||
private bool IsPointingInsideKernel(long address)
|
||||
{
|
||||
return ((ulong)Address + 0x1000000000) < 0xffffff000;
|
||||
return ((ulong)address + 0x1000000000) < 0xffffff000;
|
||||
}
|
||||
|
||||
private bool IsAddressNotWordAligned(long Address)
|
||||
private bool IsAddressNotWordAligned(long address)
|
||||
{
|
||||
return (Address & 3) != 0;
|
||||
return (address & 3) != 0;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user