mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-11-25 03:25:13 +00:00
This reverts commit 85dbb9559a
.
This commit is contained in:
parent
85dbb9559a
commit
3615a70cae
299 changed files with 12276 additions and 12268 deletions
|
@ -7,109 +7,109 @@ namespace Ryujinx.HLE
|
|||
{
|
||||
public const long RamSize = 4L * 1024 * 1024 * 1024;
|
||||
|
||||
public IntPtr RamPointer { get; }
|
||||
public IntPtr RamPointer { get; private set; }
|
||||
|
||||
private unsafe byte* _ramPtr;
|
||||
private unsafe byte* RamPtr;
|
||||
|
||||
public unsafe DeviceMemory()
|
||||
{
|
||||
RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize));
|
||||
|
||||
_ramPtr = (byte*)RamPointer;
|
||||
RamPtr = (byte*)RamPointer;
|
||||
}
|
||||
|
||||
public sbyte ReadSByte(long position)
|
||||
public sbyte ReadSByte(long Position)
|
||||
{
|
||||
return (sbyte)ReadByte(position);
|
||||
return (sbyte)ReadByte(Position);
|
||||
}
|
||||
|
||||
public short ReadInt16(long position)
|
||||
public short ReadInt16(long Position)
|
||||
{
|
||||
return (short)ReadUInt16(position);
|
||||
return (short)ReadUInt16(Position);
|
||||
}
|
||||
|
||||
public int ReadInt32(long position)
|
||||
public int ReadInt32(long Position)
|
||||
{
|
||||
return (int)ReadUInt32(position);
|
||||
return (int)ReadUInt32(Position);
|
||||
}
|
||||
|
||||
public long ReadInt64(long position)
|
||||
public long ReadInt64(long Position)
|
||||
{
|
||||
return (long)ReadUInt64(position);
|
||||
return (long)ReadUInt64(Position);
|
||||
}
|
||||
|
||||
public unsafe byte ReadByte(long position)
|
||||
public unsafe byte ReadByte(long Position)
|
||||
{
|
||||
return *(_ramPtr + position);
|
||||
return *((byte*)(RamPtr + Position));
|
||||
}
|
||||
|
||||
public unsafe ushort ReadUInt16(long position)
|
||||
public unsafe ushort ReadUInt16(long Position)
|
||||
{
|
||||
return *((ushort*)(_ramPtr + position));
|
||||
return *((ushort*)(RamPtr + Position));
|
||||
}
|
||||
|
||||
public unsafe uint ReadUInt32(long position)
|
||||
public unsafe uint ReadUInt32(long Position)
|
||||
{
|
||||
return *((uint*)(_ramPtr + position));
|
||||
return *((uint*)(RamPtr + Position));
|
||||
}
|
||||
|
||||
public unsafe ulong ReadUInt64(long position)
|
||||
public unsafe ulong ReadUInt64(long Position)
|
||||
{
|
||||
return *((ulong*)(_ramPtr + position));
|
||||
return *((ulong*)(RamPtr + Position));
|
||||
}
|
||||
|
||||
public void WriteSByte(long position, sbyte value)
|
||||
public void WriteSByte(long Position, sbyte Value)
|
||||
{
|
||||
WriteByte(position, (byte)value);
|
||||
WriteByte(Position, (byte)Value);
|
||||
}
|
||||
|
||||
public void WriteInt16(long position, short value)
|
||||
public void WriteInt16(long Position, short Value)
|
||||
{
|
||||
WriteUInt16(position, (ushort)value);
|
||||
WriteUInt16(Position, (ushort)Value);
|
||||
}
|
||||
|
||||
public void WriteInt32(long position, int value)
|
||||
public void WriteInt32(long Position, int Value)
|
||||
{
|
||||
WriteUInt32(position, (uint)value);
|
||||
WriteUInt32(Position, (uint)Value);
|
||||
}
|
||||
|
||||
public void WriteInt64(long position, long value)
|
||||
public void WriteInt64(long Position, long Value)
|
||||
{
|
||||
WriteUInt64(position, (ulong)value);
|
||||
WriteUInt64(Position, (ulong)Value);
|
||||
}
|
||||
|
||||
public unsafe void WriteByte(long position, byte value)
|
||||
public unsafe void WriteByte(long Position, byte Value)
|
||||
{
|
||||
*(_ramPtr + position) = value;
|
||||
*((byte*)(RamPtr + Position)) = Value;
|
||||
}
|
||||
|
||||
public unsafe void WriteUInt16(long position, ushort value)
|
||||
public unsafe void WriteUInt16(long Position, ushort Value)
|
||||
{
|
||||
*((ushort*)(_ramPtr + position)) = value;
|
||||
*((ushort*)(RamPtr + Position)) = Value;
|
||||
}
|
||||
|
||||
public unsafe void WriteUInt32(long position, uint value)
|
||||
public unsafe void WriteUInt32(long Position, uint Value)
|
||||
{
|
||||
*((uint*)(_ramPtr + position)) = value;
|
||||
*((uint*)(RamPtr + Position)) = Value;
|
||||
}
|
||||
|
||||
public unsafe void WriteUInt64(long position, ulong value)
|
||||
public unsafe void WriteUInt64(long Position, ulong Value)
|
||||
{
|
||||
*((ulong*)(_ramPtr + position)) = value;
|
||||
*((ulong*)(RamPtr + Position)) = Value;
|
||||
}
|
||||
|
||||
public void FillWithZeros(long position, int size)
|
||||
public void FillWithZeros(long Position, int Size)
|
||||
{
|
||||
int size8 = size & ~(8 - 1);
|
||||
int Size8 = Size & ~(8 - 1);
|
||||
|
||||
for (int offs = 0; offs < size8; offs += 8)
|
||||
for (int Offs = 0; Offs < Size8; Offs += 8)
|
||||
{
|
||||
WriteInt64(position + offs, 0);
|
||||
WriteInt64(Position + Offs, 0);
|
||||
}
|
||||
|
||||
for (int offs = size8; offs < (size - size8); offs++)
|
||||
for (int Offs = Size8; Offs < (Size - Size8); Offs++)
|
||||
{
|
||||
WriteByte(position + offs, 0);
|
||||
WriteByte(Position + Offs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ namespace Ryujinx.HLE
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
Marshal.FreeHGlobal(RamPointer);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace Ryujinx.HLE.Exceptions
|
|||
{
|
||||
public class InvalidNpdmException : Exception
|
||||
{
|
||||
public InvalidNpdmException(string message) : base(message) { }
|
||||
public InvalidNpdmException(string ExMsg) : base(ExMsg) { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@ namespace Ryujinx.HLE.Exceptions
|
|||
|
||||
public UndefinedInstructionException() : base() { }
|
||||
|
||||
public UndefinedInstructionException(long position, int opCode) : base(string.Format(ExMsg, position, opCode)) { }
|
||||
public UndefinedInstructionException(long Position, int OpCode) : base(string.Format(ExMsg, Position, OpCode)) { }
|
||||
}
|
||||
}
|
|
@ -9,297 +9,297 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
{
|
||||
internal class ContentManager
|
||||
{
|
||||
private Dictionary<StorageId, LinkedList<LocationEntry>> _locationEntries;
|
||||
private Dictionary<StorageId, LinkedList<LocationEntry>> LocationEntries;
|
||||
|
||||
private Dictionary<string, long> _sharedFontTitleDictionary;
|
||||
private Dictionary<string, long> SharedFontTitleDictionary;
|
||||
|
||||
private SortedDictionary<(ulong, ContentType), string> _contentDictionary;
|
||||
private SortedDictionary<(ulong, ContentType), string> ContentDictionary;
|
||||
|
||||
private Switch _device;
|
||||
private Switch Device;
|
||||
|
||||
public ContentManager(Switch device)
|
||||
public ContentManager(Switch Device)
|
||||
{
|
||||
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
ContentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
||||
LocationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
|
||||
_sharedFontTitleDictionary = new Dictionary<string, long>
|
||||
SharedFontTitleDictionary = new Dictionary<string, long>()
|
||||
{
|
||||
{ "FontStandard", 0x0100000000000811 },
|
||||
{ "FontChineseSimplified", 0x0100000000000814 },
|
||||
{ "FontExtendedChineseSimplified", 0x0100000000000814 },
|
||||
{ "FontKorean", 0x0100000000000812 },
|
||||
{ "FontChineseTraditional", 0x0100000000000813 },
|
||||
{ "FontNintendoExtended", 0x0100000000000810 }
|
||||
{ "FontNintendoExtended" , 0x0100000000000810 },
|
||||
};
|
||||
|
||||
_device = device;
|
||||
this.Device = Device;
|
||||
}
|
||||
|
||||
public void LoadEntries()
|
||||
{
|
||||
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
||||
ContentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
||||
|
||||
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
|
||||
foreach (StorageId StorageId in Enum.GetValues(typeof(StorageId)))
|
||||
{
|
||||
string contentDirectory = null;
|
||||
string contentPathString = null;
|
||||
string registeredDirectory = null;
|
||||
string ContentDirectory = null;
|
||||
string ContentPathString = null;
|
||||
string RegisteredDirectory = null;
|
||||
|
||||
try
|
||||
{
|
||||
contentPathString = LocationHelper.GetContentRoot(storageId);
|
||||
contentDirectory = LocationHelper.GetRealPath(_device.FileSystem, contentPathString);
|
||||
registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||
ContentPathString = LocationHelper.GetContentRoot(StorageId);
|
||||
ContentDirectory = LocationHelper.GetRealPath(Device.FileSystem, ContentPathString);
|
||||
RegisteredDirectory = Path.Combine(ContentDirectory, "registered");
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
catch (NotSupportedException NEx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(registeredDirectory);
|
||||
Directory.CreateDirectory(RegisteredDirectory);
|
||||
|
||||
LinkedList<LocationEntry> locationList = new LinkedList<LocationEntry>();
|
||||
LinkedList<LocationEntry> LocationList = new LinkedList<LocationEntry>();
|
||||
|
||||
void AddEntry(LocationEntry entry)
|
||||
void AddEntry(LocationEntry Entry)
|
||||
{
|
||||
locationList.AddLast(entry);
|
||||
LocationList.AddLast(Entry);
|
||||
}
|
||||
|
||||
foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory))
|
||||
foreach (string DirectoryPath in Directory.EnumerateDirectories(RegisteredDirectory))
|
||||
{
|
||||
if (Directory.GetFiles(directoryPath).Length > 0)
|
||||
if (Directory.GetFiles(DirectoryPath).Length > 0)
|
||||
{
|
||||
string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);
|
||||
string NcaName = new DirectoryInfo(DirectoryPath).Name.Replace(".nca", string.Empty);
|
||||
|
||||
using (FileStream ncaFile = new FileStream(Directory.GetFiles(directoryPath)[0], FileMode.Open, FileAccess.Read))
|
||||
using (FileStream NcaFile = new FileStream(Directory.GetFiles(DirectoryPath)[0], FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFile, false);
|
||||
Nca Nca = new Nca(Device.System.KeySet, NcaFile, false);
|
||||
|
||||
string switchPath = Path.Combine(contentPathString + ":",
|
||||
ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart('\\'));
|
||||
string SwitchPath = Path.Combine(ContentPathString + ":",
|
||||
NcaFile.Name.Replace(ContentDirectory, string.Empty).TrimStart('\\'));
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
SwitchPath = SwitchPath.Replace('\\', '/');
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
LocationEntry Entry = new LocationEntry(SwitchPath,
|
||||
0,
|
||||
(long)nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
(long)Nca.Header.TitleId,
|
||||
Nca.Header.ContentType);
|
||||
|
||||
AddEntry(entry);
|
||||
AddEntry(Entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
ContentDictionary.Add((Nca.Header.TitleId, Nca.Header.ContentType), NcaName);
|
||||
|
||||
ncaFile.Close();
|
||||
nca.Dispose();
|
||||
ncaFile.Dispose();
|
||||
NcaFile.Close();
|
||||
Nca.Dispose();
|
||||
NcaFile.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string filePath in Directory.EnumerateFiles(contentDirectory))
|
||||
foreach (string FilePath in Directory.EnumerateFiles(ContentDirectory))
|
||||
{
|
||||
if (Path.GetExtension(filePath) == ".nca")
|
||||
if (Path.GetExtension(FilePath) == ".nca")
|
||||
{
|
||||
string ncaName = Path.GetFileNameWithoutExtension(filePath);
|
||||
string NcaName = Path.GetFileNameWithoutExtension(FilePath);
|
||||
|
||||
using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
using (FileStream NcaFile = new FileStream(FilePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFile, false);
|
||||
Nca Nca = new Nca(Device.System.KeySet, NcaFile, false);
|
||||
|
||||
string switchPath = Path.Combine(contentPathString + ":",
|
||||
filePath.Replace(contentDirectory, string.Empty).TrimStart('\\'));
|
||||
string SwitchPath = Path.Combine(ContentPathString + ":",
|
||||
FilePath.Replace(ContentDirectory, string.Empty).TrimStart('\\'));
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
SwitchPath = SwitchPath.Replace('\\', '/');
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
LocationEntry Entry = new LocationEntry(SwitchPath,
|
||||
0,
|
||||
(long)nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
(long)Nca.Header.TitleId,
|
||||
Nca.Header.ContentType);
|
||||
|
||||
AddEntry(entry);
|
||||
AddEntry(Entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
ContentDictionary.Add((Nca.Header.TitleId, Nca.Header.ContentType), NcaName);
|
||||
|
||||
ncaFile.Close();
|
||||
nca.Dispose();
|
||||
ncaFile.Dispose();
|
||||
NcaFile.Close();
|
||||
Nca.Dispose();
|
||||
NcaFile.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0)
|
||||
if(LocationEntries.ContainsKey(StorageId) && LocationEntries[StorageId]?.Count == 0)
|
||||
{
|
||||
_locationEntries.Remove(storageId);
|
||||
LocationEntries.Remove(StorageId);
|
||||
}
|
||||
|
||||
if (!_locationEntries.ContainsKey(storageId))
|
||||
if (!LocationEntries.ContainsKey(StorageId))
|
||||
{
|
||||
_locationEntries.Add(storageId, locationList);
|
||||
LocationEntries.Add(StorageId, LocationList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearEntry(long titleId, ContentType contentType,StorageId storageId)
|
||||
public void ClearEntry(long TitleId, ContentType ContentType,StorageId StorageId)
|
||||
{
|
||||
RemoveLocationEntry(titleId, contentType, storageId);
|
||||
RemoveLocationEntry(TitleId, ContentType, StorageId);
|
||||
}
|
||||
|
||||
public void RefreshEntries(StorageId storageId, int flag)
|
||||
public void RefreshEntries(StorageId StorageId, int Flag)
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
|
||||
LinkedListNode<LocationEntry> locationEntry = locationList.First;
|
||||
LinkedList<LocationEntry> LocationList = LocationEntries[StorageId];
|
||||
LinkedListNode<LocationEntry> LocationEntry = LocationList.First;
|
||||
|
||||
while (locationEntry != null)
|
||||
while (LocationEntry != null)
|
||||
{
|
||||
LinkedListNode<LocationEntry> nextLocationEntry = locationEntry.Next;
|
||||
LinkedListNode<LocationEntry> NextLocationEntry = LocationEntry.Next;
|
||||
|
||||
if (locationEntry.Value.Flag == flag)
|
||||
if (LocationEntry.Value.Flag == Flag)
|
||||
{
|
||||
locationList.Remove(locationEntry.Value);
|
||||
LocationList.Remove(LocationEntry.Value);
|
||||
}
|
||||
|
||||
locationEntry = nextLocationEntry;
|
||||
LocationEntry = NextLocationEntry;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasNca(string ncaId, StorageId storageId)
|
||||
public bool HasNca(string NcaId, StorageId StorageId)
|
||||
{
|
||||
if (_contentDictionary.ContainsValue(ncaId))
|
||||
if (ContentDictionary.ContainsValue(NcaId))
|
||||
{
|
||||
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
|
||||
long titleId = (long)content.Key.Item1;
|
||||
ContentType contentType = content.Key.Item2;
|
||||
StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
|
||||
var Content = ContentDictionary.FirstOrDefault(x => x.Value == NcaId);
|
||||
long TitleId = (long)Content.Key.Item1;
|
||||
ContentType ContentType = Content.Key.Item2;
|
||||
StorageId Storage = GetInstalledStorage(TitleId, ContentType, StorageId);
|
||||
|
||||
return storage == storageId;
|
||||
return Storage == StorageId;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public UInt128 GetInstalledNcaId(long titleId, ContentType contentType)
|
||||
public UInt128 GetInstalledNcaId(long TitleId, ContentType ContentType)
|
||||
{
|
||||
if (_contentDictionary.ContainsKey(((ulong)titleId,contentType)))
|
||||
if (ContentDictionary.ContainsKey(((ulong)TitleId,ContentType)))
|
||||
{
|
||||
return new UInt128(_contentDictionary[((ulong)titleId,contentType)]);
|
||||
return new UInt128(ContentDictionary[((ulong)TitleId,ContentType)]);
|
||||
}
|
||||
|
||||
return new UInt128();
|
||||
}
|
||||
|
||||
public StorageId GetInstalledStorage(long titleId, ContentType contentType, StorageId storageId)
|
||||
public StorageId GetInstalledStorage(long TitleId, ContentType ContentType, StorageId StorageId)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
|
||||
LocationEntry LocationEntry = GetLocation(TitleId, ContentType, StorageId);
|
||||
|
||||
return locationEntry.ContentPath != null ?
|
||||
LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None;
|
||||
return LocationEntry.ContentPath != null ?
|
||||
LocationHelper.GetStorageId(LocationEntry.ContentPath) : StorageId.None;
|
||||
}
|
||||
|
||||
public string GetInstalledContentPath(long titleId, StorageId storageId, ContentType contentType)
|
||||
public string GetInstalledContentPath(long TitleId, StorageId StorageId, ContentType ContentType)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
|
||||
LocationEntry LocationEntry = GetLocation(TitleId, ContentType, StorageId);
|
||||
|
||||
if (VerifyContentType(locationEntry, contentType))
|
||||
if (VerifyContentType(LocationEntry, ContentType))
|
||||
{
|
||||
return locationEntry.ContentPath;
|
||||
return LocationEntry.ContentPath;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public void RedirectLocation(LocationEntry newEntry, StorageId storageId)
|
||||
public void RedirectLocation(LocationEntry NewEntry, StorageId StorageId)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(newEntry.TitleId, newEntry.ContentType, storageId);
|
||||
LocationEntry LocationEntry = GetLocation(NewEntry.TitleId, NewEntry.ContentType, StorageId);
|
||||
|
||||
if (locationEntry.ContentPath != null)
|
||||
if (LocationEntry.ContentPath != null)
|
||||
{
|
||||
RemoveLocationEntry(newEntry.TitleId, newEntry.ContentType, storageId);
|
||||
RemoveLocationEntry(NewEntry.TitleId, NewEntry.ContentType, StorageId);
|
||||
}
|
||||
|
||||
AddLocationEntry(newEntry, storageId);
|
||||
AddLocationEntry(NewEntry, StorageId);
|
||||
}
|
||||
|
||||
private bool VerifyContentType(LocationEntry locationEntry, ContentType contentType)
|
||||
private bool VerifyContentType(LocationEntry LocationEntry, ContentType ContentType)
|
||||
{
|
||||
if (locationEntry.ContentPath == null)
|
||||
if (LocationEntry.ContentPath == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StorageId storageId = LocationHelper.GetStorageId(locationEntry.ContentPath);
|
||||
string installedPath = _device.FileSystem.SwitchPathToSystemPath(locationEntry.ContentPath);
|
||||
StorageId StorageId = LocationHelper.GetStorageId(LocationEntry.ContentPath);
|
||||
string InstalledPath = Device.FileSystem.SwitchPathToSystemPath(LocationEntry.ContentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(installedPath))
|
||||
if (!string.IsNullOrWhiteSpace(InstalledPath))
|
||||
{
|
||||
if (File.Exists(installedPath))
|
||||
if (File.Exists(InstalledPath))
|
||||
{
|
||||
FileStream file = new FileStream(installedPath, FileMode.Open, FileAccess.Read);
|
||||
Nca nca = new Nca(_device.System.KeySet, file, false);
|
||||
bool contentCheck = nca.Header.ContentType == contentType;
|
||||
FileStream File = new FileStream(InstalledPath, FileMode.Open, FileAccess.Read);
|
||||
Nca Nca = new Nca(Device.System.KeySet, File, false);
|
||||
bool ContentCheck = Nca.Header.ContentType == ContentType;
|
||||
|
||||
nca.Dispose();
|
||||
file.Dispose();
|
||||
Nca.Dispose();
|
||||
File.Dispose();
|
||||
|
||||
return contentCheck;
|
||||
return ContentCheck;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void AddLocationEntry(LocationEntry entry, StorageId storageId)
|
||||
private void AddLocationEntry(LocationEntry Entry, StorageId StorageId)
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = null;
|
||||
LinkedList<LocationEntry> LocationList = null;
|
||||
|
||||
if (_locationEntries.ContainsKey(storageId))
|
||||
if (LocationEntries.ContainsKey(StorageId))
|
||||
{
|
||||
locationList = _locationEntries[storageId];
|
||||
LocationList = LocationEntries[StorageId];
|
||||
}
|
||||
|
||||
if (locationList != null)
|
||||
if (LocationList != null)
|
||||
{
|
||||
if (locationList.Contains(entry))
|
||||
if (LocationList.Contains(Entry))
|
||||
{
|
||||
locationList.Remove(entry);
|
||||
LocationList.Remove(Entry);
|
||||
}
|
||||
|
||||
locationList.AddLast(entry);
|
||||
LocationList.AddLast(Entry);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveLocationEntry(long titleId, ContentType contentType, StorageId storageId)
|
||||
private void RemoveLocationEntry(long TitleId, ContentType ContentType, StorageId StorageId)
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = null;
|
||||
LinkedList<LocationEntry> LocationList = null;
|
||||
|
||||
if (_locationEntries.ContainsKey(storageId))
|
||||
if (LocationEntries.ContainsKey(StorageId))
|
||||
{
|
||||
locationList = _locationEntries[storageId];
|
||||
LocationList = LocationEntries[StorageId];
|
||||
}
|
||||
|
||||
if (locationList != null)
|
||||
if (LocationList != null)
|
||||
{
|
||||
LocationEntry entry =
|
||||
locationList.ToList().Find(x => x.TitleId == titleId && x.ContentType == contentType);
|
||||
LocationEntry Entry =
|
||||
LocationList.ToList().Find(x => x.TitleId == TitleId && x.ContentType == ContentType);
|
||||
|
||||
if (entry.ContentPath != null)
|
||||
if (Entry.ContentPath != null)
|
||||
{
|
||||
locationList.Remove(entry);
|
||||
LocationList.Remove(Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetFontTitle(string fontName, out long titleId)
|
||||
public bool TryGetFontTitle(string FontName, out long TitleId)
|
||||
{
|
||||
return _sharedFontTitleDictionary.TryGetValue(fontName, out titleId);
|
||||
return SharedFontTitleDictionary.TryGetValue(FontName, out TitleId);
|
||||
}
|
||||
|
||||
private LocationEntry GetLocation(long titleId, ContentType contentType,StorageId storageId)
|
||||
private LocationEntry GetLocation(long TitleId, ContentType ContentType,StorageId StorageId)
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
|
||||
LinkedList<LocationEntry> LocationList = LocationEntries[StorageId];
|
||||
|
||||
return locationList.ToList().Find(x => x.TitleId == titleId && x.ContentType == contentType);
|
||||
return LocationList.ToList().Find(x => x.TitleId == TitleId && x.ContentType == ContentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
using LibHac;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using LibHac;
|
||||
|
||||
namespace Ryujinx.HLE.FileSystem.Content
|
||||
{
|
||||
public struct LocationEntry
|
||||
{
|
||||
public string ContentPath { get; }
|
||||
public string ContentPath { get; private set; }
|
||||
public int Flag { get; private set; }
|
||||
public long TitleId { get; }
|
||||
public ContentType ContentType { get; }
|
||||
public long TitleId { get; private set; }
|
||||
public ContentType ContentType { get; private set; }
|
||||
|
||||
public LocationEntry(string contentPath, int flag, long titleId, ContentType contentType)
|
||||
public LocationEntry(string ContentPath, int Flag, long TitleId, ContentType ContentType)
|
||||
{
|
||||
ContentPath = contentPath;
|
||||
Flag = flag;
|
||||
TitleId = titleId;
|
||||
ContentType = contentType;
|
||||
this.ContentPath = ContentPath;
|
||||
this.Flag = Flag;
|
||||
this.TitleId = TitleId;
|
||||
this.ContentType = ContentType;
|
||||
}
|
||||
|
||||
public void SetFlag(int flag)
|
||||
public void SetFlag(int Flag)
|
||||
{
|
||||
Flag = flag;
|
||||
this.Flag = Flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,30 +7,30 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
{
|
||||
internal static class LocationHelper
|
||||
{
|
||||
public static string GetRealPath(VirtualFileSystem fileSystem, string switchContentPath)
|
||||
public static string GetRealPath(VirtualFileSystem FileSystem, string SwitchContentPath)
|
||||
{
|
||||
string basePath = fileSystem.GetBasePath();
|
||||
string BasePath = FileSystem.GetBasePath();
|
||||
|
||||
switch (switchContentPath)
|
||||
switch (SwitchContentPath)
|
||||
{
|
||||
case ContentPath.SystemContent:
|
||||
return Path.Combine(fileSystem.GetBasePath(), SystemNandPath, "Contents");
|
||||
return Path.Combine(FileSystem.GetBasePath(), SystemNandPath, "Contents");
|
||||
case ContentPath.UserContent:
|
||||
return Path.Combine(fileSystem.GetBasePath(), UserNandPath, "Contents");
|
||||
return Path.Combine(FileSystem.GetBasePath(), UserNandPath, "Contents");
|
||||
case ContentPath.SdCardContent:
|
||||
return Path.Combine(fileSystem.GetSdCardPath(), "Nintendo", "Contents");
|
||||
return Path.Combine(FileSystem.GetSdCardPath(), "Nintendo", "Contents");
|
||||
case ContentPath.System:
|
||||
return Path.Combine(basePath, SystemNandPath);
|
||||
return Path.Combine(BasePath, SystemNandPath);
|
||||
case ContentPath.User:
|
||||
return Path.Combine(basePath, UserNandPath);
|
||||
return Path.Combine(BasePath, UserNandPath);
|
||||
default:
|
||||
throw new NotSupportedException($"Content Path `{switchContentPath}` is not supported.");
|
||||
throw new NotSupportedException($"Content Path `{SwitchContentPath}` is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetContentPath(ContentStorageId contentStorageId)
|
||||
public static string GetContentPath(ContentStorageId ContentStorageId)
|
||||
{
|
||||
switch (contentStorageId)
|
||||
switch (ContentStorageId)
|
||||
{
|
||||
case ContentStorageId.NandSystem:
|
||||
return ContentPath.SystemContent;
|
||||
|
@ -39,13 +39,13 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
case ContentStorageId.SdCard:
|
||||
return ContentPath.SdCardContent;
|
||||
default:
|
||||
throw new NotSupportedException($"Content Storage `{contentStorageId}` is not supported.");
|
||||
throw new NotSupportedException($"Content Storage `{ContentStorageId}` is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetContentRoot(StorageId storageId)
|
||||
public static string GetContentRoot(StorageId StorageId)
|
||||
{
|
||||
switch (storageId)
|
||||
switch (StorageId)
|
||||
{
|
||||
case StorageId.NandSystem:
|
||||
return ContentPath.SystemContent;
|
||||
|
@ -54,15 +54,15 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
case StorageId.SdCard:
|
||||
return ContentPath.SdCardContent;
|
||||
default:
|
||||
throw new NotSupportedException($"Storage Id `{storageId}` is not supported.");
|
||||
throw new NotSupportedException($"Storage Id `{StorageId}` is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static StorageId GetStorageId(string contentPathString)
|
||||
public static StorageId GetStorageId(string ContentPathString)
|
||||
{
|
||||
string cleanedPath = contentPathString.Split(':')[0];
|
||||
string CleanedPath = ContentPathString.Split(':')[0];
|
||||
|
||||
switch (cleanedPath)
|
||||
switch (CleanedPath)
|
||||
{
|
||||
case ContentPath.SystemContent:
|
||||
case ContentPath.System:
|
||||
|
|
|
@ -10,228 +10,228 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
class FileSystemProvider : IFileSystemProvider
|
||||
{
|
||||
private readonly string _basePath;
|
||||
private readonly string _rootPath;
|
||||
private readonly string BasePath;
|
||||
private readonly string RootPath;
|
||||
|
||||
public FileSystemProvider(string basePath, string rootPath)
|
||||
public FileSystemProvider(string BasePath, string RootPath)
|
||||
{
|
||||
_basePath = basePath;
|
||||
_rootPath = rootPath;
|
||||
this.BasePath = BasePath;
|
||||
this.RootPath = RootPath;
|
||||
|
||||
CheckIfDescendentOfRootPath(basePath);
|
||||
CheckIfDescendentOfRootPath(BasePath);
|
||||
}
|
||||
|
||||
public long CreateDirectory(string name)
|
||||
public long CreateDirectory(string Name)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
if (Directory.Exists(name))
|
||||
if (Directory.Exists(Name))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(name);
|
||||
Directory.CreateDirectory(Name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateFile(string name, long size)
|
||||
public long CreateFile(string Name, long Size)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
if (File.Exists(name))
|
||||
if (File.Exists(Name))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
||||
}
|
||||
|
||||
using (FileStream newFile = File.Create(name))
|
||||
using (FileStream NewFile = File.Create(Name))
|
||||
{
|
||||
newFile.SetLength(size);
|
||||
NewFile.SetLength(Size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long DeleteDirectory(string name, bool recursive)
|
||||
public long DeleteDirectory(string Name, bool Recursive)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
string dirName = name;
|
||||
string DirName = Name;
|
||||
|
||||
if (!Directory.Exists(dirName))
|
||||
if (!Directory.Exists(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
Directory.Delete(dirName, recursive);
|
||||
Directory.Delete(DirName, Recursive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long DeleteFile(string name)
|
||||
public long DeleteFile(string Name)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
if (!File.Exists(name))
|
||||
if (!File.Exists(Name))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Delete(name);
|
||||
File.Delete(Name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetDirectories(string path)
|
||||
public DirectoryEntry[] GetDirectories(string Path)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(path);
|
||||
CheckIfDescendentOfRootPath(Path);
|
||||
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach(string directory in Directory.EnumerateDirectories(path))
|
||||
foreach(string Directory in Directory.EnumerateDirectories(Path))
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(directory, DirectoryEntryType.Directory);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory, DirectoryEntryType.Directory);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return entries.ToArray();
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetEntries(string path)
|
||||
public DirectoryEntry[] GetEntries(string Path)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(path);
|
||||
CheckIfDescendentOfRootPath(Path);
|
||||
|
||||
if (Directory.Exists(path))
|
||||
if (Directory.Exists(Path))
|
||||
{
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (string directory in Directory.EnumerateDirectories(path))
|
||||
foreach (string Directory in Directory.EnumerateDirectories(Path))
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(directory, DirectoryEntryType.Directory);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory, DirectoryEntryType.Directory);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
foreach (string file in Directory.EnumerateFiles(path))
|
||||
foreach (string File in Directory.EnumerateFiles(Path))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(file);
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(file, DirectoryEntryType.File, fileInfo.Length);
|
||||
FileInfo FileInfo = new FileInfo(File);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File, DirectoryEntryType.File, FileInfo.Length);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetFiles(string path)
|
||||
public DirectoryEntry[] GetFiles(string Path)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(path);
|
||||
CheckIfDescendentOfRootPath(Path);
|
||||
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (string file in Directory.EnumerateFiles(path))
|
||||
foreach (string File in Directory.EnumerateFiles(Path))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(file);
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(file, DirectoryEntryType.File, fileInfo.Length);
|
||||
FileInfo FileInfo = new FileInfo(File);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File, DirectoryEntryType.File, FileInfo.Length);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return entries.ToArray();
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public long GetFreeSpace(ServiceCtx context)
|
||||
public long GetFreeSpace(ServiceCtx Context)
|
||||
{
|
||||
return context.Device.FileSystem.GetDrive().AvailableFreeSpace;
|
||||
return Context.Device.FileSystem.GetDrive().AvailableFreeSpace;
|
||||
}
|
||||
|
||||
public string GetFullPath(string name)
|
||||
public string GetFullPath(string Name)
|
||||
{
|
||||
if (name.StartsWith("//"))
|
||||
if (Name.StartsWith("//"))
|
||||
{
|
||||
name = name.Substring(2);
|
||||
Name = Name.Substring(2);
|
||||
}
|
||||
else if (name.StartsWith('/'))
|
||||
else if (Name.StartsWith('/'))
|
||||
{
|
||||
name = name.Substring(1);
|
||||
Name = Name.Substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string fullPath = Path.Combine(_basePath, name);
|
||||
string FullPath = Path.Combine(BasePath, Name);
|
||||
|
||||
CheckIfDescendentOfRootPath(fullPath);
|
||||
CheckIfDescendentOfRootPath(FullPath);
|
||||
|
||||
return fullPath;
|
||||
return FullPath;
|
||||
}
|
||||
|
||||
public long GetTotalSpace(ServiceCtx context)
|
||||
public long GetTotalSpace(ServiceCtx Context)
|
||||
{
|
||||
return context.Device.FileSystem.GetDrive().TotalSize;
|
||||
return Context.Device.FileSystem.GetDrive().TotalSize;
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string name)
|
||||
public bool DirectoryExists(string Name)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
return Directory.Exists(name);
|
||||
return Directory.Exists(Name);
|
||||
}
|
||||
|
||||
public bool FileExists(string name)
|
||||
public bool FileExists(string Name)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
return File.Exists(name);
|
||||
return File.Exists(Name);
|
||||
}
|
||||
|
||||
public long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface)
|
||||
public long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
if (Directory.Exists(name))
|
||||
if (Directory.Exists(Name))
|
||||
{
|
||||
directoryInterface = new IDirectory(name, filterFlags, this);
|
||||
DirectoryInterface = new IDirectory(Name, FilterFlags, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
directoryInterface = null;
|
||||
DirectoryInterface = null;
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
public long OpenFile(string name, out IFile fileInterface)
|
||||
public long OpenFile(string Name, out IFile FileInterface)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
CheckIfDescendentOfRootPath(Name);
|
||||
|
||||
if (File.Exists(name))
|
||||
if (File.Exists(Name))
|
||||
{
|
||||
FileStream stream = new FileStream(name, FileMode.Open);
|
||||
FileStream Stream = new FileStream(Name, FileMode.Open);
|
||||
|
||||
fileInterface = new IFile(stream, name);
|
||||
FileInterface = new IFile(Stream, Name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fileInterface = null;
|
||||
FileInterface = null;
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
public long RenameDirectory(string oldName, string newName)
|
||||
public long RenameDirectory(string OldName, string NewName)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(oldName);
|
||||
CheckIfDescendentOfRootPath(newName);
|
||||
CheckIfDescendentOfRootPath(OldName);
|
||||
CheckIfDescendentOfRootPath(NewName);
|
||||
|
||||
if (Directory.Exists(oldName))
|
||||
if (Directory.Exists(OldName))
|
||||
{
|
||||
Directory.Move(oldName, newName);
|
||||
Directory.Move(OldName, NewName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -241,14 +241,14 @@ namespace Ryujinx.HLE.FileSystem
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long RenameFile(string oldName, string newName)
|
||||
public long RenameFile(string OldName, string NewName)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(oldName);
|
||||
CheckIfDescendentOfRootPath(newName);
|
||||
CheckIfDescendentOfRootPath(OldName);
|
||||
CheckIfDescendentOfRootPath(NewName);
|
||||
|
||||
if (File.Exists(oldName))
|
||||
if (File.Exists(OldName))
|
||||
{
|
||||
File.Move(oldName, newName);
|
||||
File.Move(OldName, NewName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -258,24 +258,24 @@ namespace Ryujinx.HLE.FileSystem
|
|||
return 0;
|
||||
}
|
||||
|
||||
public void CheckIfDescendentOfRootPath(string path)
|
||||
public void CheckIfDescendentOfRootPath(string Path)
|
||||
{
|
||||
DirectoryInfo pathInfo = new DirectoryInfo(path);
|
||||
DirectoryInfo rootInfo = new DirectoryInfo(_rootPath);
|
||||
DirectoryInfo PathInfo = new DirectoryInfo(Path);
|
||||
DirectoryInfo RootInfo = new DirectoryInfo(RootPath);
|
||||
|
||||
while (pathInfo.Parent != null)
|
||||
while (PathInfo.Parent != null)
|
||||
{
|
||||
if (pathInfo.Parent.FullName == rootInfo.FullName)
|
||||
if (PathInfo.Parent.FullName == RootInfo.FullName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pathInfo = pathInfo.Parent;
|
||||
PathInfo = PathInfo.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Path {path} is not a child directory of {_rootPath}");
|
||||
throw new InvalidOperationException($"Path {Path} is not a child directory of {RootPath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,41 @@
|
|||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.FspSrv;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
interface IFileSystemProvider
|
||||
{
|
||||
long CreateFile(string name, long size);
|
||||
long CreateFile(string Name, long Size);
|
||||
|
||||
long CreateDirectory(string name);
|
||||
long CreateDirectory(string Name);
|
||||
|
||||
long RenameFile(string oldName, string newName);
|
||||
long RenameFile(string OldName, string NewName);
|
||||
|
||||
long RenameDirectory(string oldName, string newName);
|
||||
long RenameDirectory(string OldName, string NewName);
|
||||
|
||||
DirectoryEntry[] GetEntries(string path);
|
||||
DirectoryEntry[] GetEntries(string Path);
|
||||
|
||||
DirectoryEntry[] GetDirectories(string path);
|
||||
DirectoryEntry[] GetDirectories(string Path);
|
||||
|
||||
DirectoryEntry[] GetFiles(string path);
|
||||
DirectoryEntry[] GetFiles(string Path);
|
||||
|
||||
long DeleteFile(string name);
|
||||
long DeleteFile(string Name);
|
||||
|
||||
long DeleteDirectory(string name, bool recursive);
|
||||
long DeleteDirectory(string Name, bool Recursive);
|
||||
|
||||
bool FileExists(string name);
|
||||
bool FileExists(string Name);
|
||||
|
||||
bool DirectoryExists(string name);
|
||||
bool DirectoryExists(string Name);
|
||||
|
||||
long OpenFile(string name, out IFile fileInterface);
|
||||
long OpenFile(string Name, out IFile FileInterface);
|
||||
|
||||
long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface);
|
||||
long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface);
|
||||
|
||||
string GetFullPath(string name);
|
||||
string GetFullPath(string Name);
|
||||
|
||||
long GetFreeSpace(ServiceCtx context);
|
||||
long GetFreeSpace(ServiceCtx Context);
|
||||
|
||||
long GetTotalSpace(ServiceCtx context);
|
||||
long GetTotalSpace(ServiceCtx Context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,98 +12,98 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
class PFsProvider : IFileSystemProvider
|
||||
{
|
||||
private Pfs _pfs;
|
||||
private Pfs Pfs;
|
||||
|
||||
public PFsProvider(Pfs pfs)
|
||||
public PFsProvider(Pfs Pfs)
|
||||
{
|
||||
_pfs = pfs;
|
||||
this.Pfs = Pfs;
|
||||
}
|
||||
|
||||
public long CreateDirectory(string name)
|
||||
public long CreateDirectory(string Name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long CreateFile(string name, long size)
|
||||
public long CreateFile(string Name, long Size)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long DeleteDirectory(string name, bool recursive)
|
||||
public long DeleteDirectory(string Name, bool Recursive)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long DeleteFile(string name)
|
||||
public long DeleteFile(string Name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetDirectories(string path)
|
||||
public DirectoryEntry[] GetDirectories(string Path)
|
||||
{
|
||||
return new DirectoryEntry[0];
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetEntries(string path)
|
||||
public DirectoryEntry[] GetEntries(string Path)
|
||||
{
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (PfsFileEntry file in _pfs.Files)
|
||||
foreach (PfsFileEntry File in Pfs.Files)
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(file.Name, DirectoryEntryType.File, file.Size);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.Size);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return entries.ToArray();
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetFiles(string path)
|
||||
public DirectoryEntry[] GetFiles(string Path)
|
||||
{
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (PfsFileEntry file in _pfs.Files)
|
||||
foreach (PfsFileEntry File in Pfs.Files)
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(file.Name, DirectoryEntryType.File, file.Size);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.Size);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return entries.ToArray();
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public long GetFreeSpace(ServiceCtx context)
|
||||
public long GetFreeSpace(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string GetFullPath(string name)
|
||||
public string GetFullPath(string Name)
|
||||
{
|
||||
return name;
|
||||
return Name;
|
||||
}
|
||||
|
||||
public long GetTotalSpace(ServiceCtx context)
|
||||
public long GetTotalSpace(ServiceCtx Context)
|
||||
{
|
||||
return _pfs.Files.Sum(x => x.Size);
|
||||
return Pfs.Files.Sum(x => x.Size);
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string name)
|
||||
public bool DirectoryExists(string Name)
|
||||
{
|
||||
return name == "/";
|
||||
return Name == "/" ? true : false;
|
||||
}
|
||||
|
||||
public bool FileExists(string name)
|
||||
public bool FileExists(string Name)
|
||||
{
|
||||
name = name.TrimStart('/');
|
||||
Name = Name.TrimStart('/');
|
||||
|
||||
return _pfs.FileExists(name);
|
||||
return Pfs.FileExists(Name);
|
||||
}
|
||||
|
||||
public long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface)
|
||||
public long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface)
|
||||
{
|
||||
if (name == "/")
|
||||
if (Name == "/")
|
||||
{
|
||||
directoryInterface = new IDirectory(name, filterFlags, this);
|
||||
DirectoryInterface = new IDirectory(Name, FilterFlags, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -111,34 +111,34 @@ namespace Ryujinx.HLE.FileSystem
|
|||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long OpenFile(string name, out IFile fileInterface)
|
||||
public long OpenFile(string Name, out IFile FileInterface)
|
||||
{
|
||||
name = name.TrimStart('/');
|
||||
Name = Name.TrimStart('/');
|
||||
|
||||
if (_pfs.FileExists(name))
|
||||
if (Pfs.FileExists(Name))
|
||||
{
|
||||
Stream stream = _pfs.OpenFile(name);
|
||||
fileInterface = new IFile(stream, name);
|
||||
Stream Stream = Pfs.OpenFile(Name);
|
||||
FileInterface = new IFile(Stream, Name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fileInterface = null;
|
||||
FileInterface = null;
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
public long RenameDirectory(string oldName, string newName)
|
||||
public long RenameDirectory(string OldName, string NewName)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long RenameFile(string oldName, string newName)
|
||||
public long RenameFile(string OldName, string NewName)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void CheckIfOutsideBasePath(string path)
|
||||
public void CheckIfOutsideBasePath(string Path)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
|
|
@ -12,150 +12,150 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
class RomFsProvider : IFileSystemProvider
|
||||
{
|
||||
private Romfs _romFs;
|
||||
private Romfs RomFs;
|
||||
|
||||
public RomFsProvider(Stream storageStream)
|
||||
public RomFsProvider(Stream StorageStream)
|
||||
{
|
||||
_romFs = new Romfs(storageStream);
|
||||
RomFs = new Romfs(StorageStream);
|
||||
}
|
||||
|
||||
public long CreateDirectory(string name)
|
||||
public long CreateDirectory(string Name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long CreateFile(string name, long size)
|
||||
public long CreateFile(string Name, long Size)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long DeleteDirectory(string name, bool recursive)
|
||||
public long DeleteDirectory(string Name, bool Recursive)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long DeleteFile(string name)
|
||||
public long DeleteFile(string Name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetDirectories(string path)
|
||||
public DirectoryEntry[] GetDirectories(string Path)
|
||||
{
|
||||
List<DirectoryEntry> directories = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Directories = new List<DirectoryEntry>();
|
||||
|
||||
foreach(RomfsDir directory in _romFs.Directories)
|
||||
foreach(RomfsDir Directory in RomFs.Directories)
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(directory.Name, DirectoryEntryType.Directory);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory.Name, DirectoryEntryType.Directory);
|
||||
|
||||
directories.Add(directoryEntry);
|
||||
Directories.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return directories.ToArray();
|
||||
return Directories.ToArray();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetEntries(string path)
|
||||
public DirectoryEntry[] GetEntries(string Path)
|
||||
{
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (RomfsDir directory in _romFs.Directories)
|
||||
foreach (RomfsDir Directory in RomFs.Directories)
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(directory.Name, DirectoryEntryType.Directory);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory.Name, DirectoryEntryType.Directory);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
foreach (RomfsFile file in _romFs.Files)
|
||||
foreach (RomfsFile File in RomFs.Files)
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(file.Name, DirectoryEntryType.File, file.DataLength);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.DataLength);
|
||||
|
||||
entries.Add(directoryEntry);
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return entries.ToArray();
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetFiles(string path)
|
||||
public DirectoryEntry[] GetFiles(string Path)
|
||||
{
|
||||
List<DirectoryEntry> files = new List<DirectoryEntry>();
|
||||
List<DirectoryEntry> Files = new List<DirectoryEntry>();
|
||||
|
||||
foreach (RomfsFile file in _romFs.Files)
|
||||
foreach (RomfsFile File in RomFs.Files)
|
||||
{
|
||||
DirectoryEntry directoryEntry = new DirectoryEntry(file.Name, DirectoryEntryType.File, file.DataLength);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.DataLength);
|
||||
|
||||
files.Add(directoryEntry);
|
||||
Files.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return files.ToArray();
|
||||
return Files.ToArray();
|
||||
}
|
||||
|
||||
public long GetFreeSpace(ServiceCtx context)
|
||||
public long GetFreeSpace(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string GetFullPath(string name)
|
||||
public string GetFullPath(string Name)
|
||||
{
|
||||
return name;
|
||||
return Name;
|
||||
}
|
||||
|
||||
public long GetTotalSpace(ServiceCtx context)
|
||||
public long GetTotalSpace(ServiceCtx Context)
|
||||
{
|
||||
return _romFs.Files.Sum(x => x.DataLength);
|
||||
return RomFs.Files.Sum(x => x.DataLength);
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string name)
|
||||
public bool DirectoryExists(string Name)
|
||||
{
|
||||
return _romFs.Directories.Exists(x=>x.Name == name);
|
||||
return RomFs.Directories.Exists(x=>x.Name == Name);
|
||||
}
|
||||
|
||||
public bool FileExists(string name)
|
||||
public bool FileExists(string Name)
|
||||
{
|
||||
return _romFs.FileExists(name);
|
||||
return RomFs.FileExists(Name);
|
||||
}
|
||||
|
||||
public long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface)
|
||||
public long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface)
|
||||
{
|
||||
RomfsDir directory = _romFs.Directories.Find(x => x.Name == name);
|
||||
RomfsDir Directory = RomFs.Directories.Find(x => x.Name == Name);
|
||||
|
||||
if (directory != null)
|
||||
if (Directory != null)
|
||||
{
|
||||
directoryInterface = new IDirectory(name, filterFlags, this);
|
||||
DirectoryInterface = new IDirectory(Name, FilterFlags, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
directoryInterface = null;
|
||||
DirectoryInterface = null;
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
public long OpenFile(string name, out IFile fileInterface)
|
||||
public long OpenFile(string Name, out IFile FileInterface)
|
||||
{
|
||||
if (_romFs.FileExists(name))
|
||||
if (RomFs.FileExists(Name))
|
||||
{
|
||||
Stream stream = _romFs.OpenFile(name);
|
||||
Stream Stream = RomFs.OpenFile(Name);
|
||||
|
||||
fileInterface = new IFile(stream, name);
|
||||
FileInterface = new IFile(Stream, Name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fileInterface = null;
|
||||
FileInterface = null;
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
public long RenameDirectory(string oldName, string newName)
|
||||
public long RenameDirectory(string OldName, string NewName)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long RenameFile(string oldName, string newName)
|
||||
public long RenameFile(string OldName, string NewName)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void CheckIfOutsideBasePath(string path)
|
||||
public void CheckIfOutsideBasePath(string Path)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
|
|
@ -7,39 +7,39 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
static class SaveHelper
|
||||
{
|
||||
public static string GetSavePath(SaveInfo saveMetaData, ServiceCtx context)
|
||||
public static string GetSavePath(SaveInfo SaveMetaData, ServiceCtx Context)
|
||||
{
|
||||
string baseSavePath = NandPath;
|
||||
long currentTitleId = saveMetaData.TitleId;
|
||||
string BaseSavePath = NandPath;
|
||||
long CurrentTitleId = SaveMetaData.TitleId;
|
||||
|
||||
switch (saveMetaData.SaveSpaceId)
|
||||
switch (SaveMetaData.SaveSpaceId)
|
||||
{
|
||||
case SaveSpaceId.NandUser:
|
||||
baseSavePath = UserNandPath;
|
||||
BaseSavePath = UserNandPath;
|
||||
break;
|
||||
case SaveSpaceId.NandSystem:
|
||||
baseSavePath = SystemNandPath;
|
||||
BaseSavePath = SystemNandPath;
|
||||
break;
|
||||
case SaveSpaceId.SdCard:
|
||||
baseSavePath = Path.Combine(SdCardPath, "Nintendo");
|
||||
BaseSavePath = Path.Combine(SdCardPath, "Nintendo");
|
||||
break;
|
||||
}
|
||||
|
||||
baseSavePath = Path.Combine(baseSavePath, "save");
|
||||
BaseSavePath = Path.Combine(BaseSavePath, "save");
|
||||
|
||||
if (saveMetaData.TitleId == 0 && saveMetaData.SaveDataType == SaveDataType.SaveData)
|
||||
if (SaveMetaData.TitleId == 0 && SaveMetaData.SaveDataType == SaveDataType.SaveData)
|
||||
{
|
||||
currentTitleId = context.Process.TitleId;
|
||||
CurrentTitleId = Context.Process.TitleId;
|
||||
}
|
||||
|
||||
string saveAccount = saveMetaData.UserId.IsZero() ? "savecommon" : saveMetaData.UserId.ToString();
|
||||
string SaveAccount = SaveMetaData.UserId.IsZero() ? "savecommon" : SaveMetaData.UserId.ToString();
|
||||
|
||||
string savePath = Path.Combine(baseSavePath,
|
||||
saveMetaData.SaveId.ToString("x16"),
|
||||
saveAccount,
|
||||
saveMetaData.SaveDataType == SaveDataType.SaveData ? currentTitleId.ToString("x16") : string.Empty);
|
||||
string SavePath = Path.Combine(BaseSavePath,
|
||||
SaveMetaData.SaveId.ToString("x16"),
|
||||
SaveAccount,
|
||||
SaveMetaData.SaveDataType == SaveDataType.SaveData ? CurrentTitleId.ToString("x16") : string.Empty);
|
||||
|
||||
return savePath;
|
||||
return SavePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,25 +4,25 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
struct SaveInfo
|
||||
{
|
||||
public long TitleId { get; }
|
||||
public long SaveId { get; }
|
||||
public UInt128 UserId { get; }
|
||||
public long TitleId { get; private set; }
|
||||
public long SaveId { get; private set; }
|
||||
public UInt128 UserId { get; private set; }
|
||||
|
||||
public SaveDataType SaveDataType { get; }
|
||||
public SaveSpaceId SaveSpaceId { get; }
|
||||
public SaveDataType SaveDataType { get; private set; }
|
||||
public SaveSpaceId SaveSpaceId { get; private set; }
|
||||
|
||||
public SaveInfo(
|
||||
long titleId,
|
||||
long saveId,
|
||||
SaveDataType saveDataType,
|
||||
UInt128 userId,
|
||||
SaveSpaceId saveSpaceId)
|
||||
long TitleId,
|
||||
long SaveId,
|
||||
SaveDataType SaveDataType,
|
||||
UInt128 UserId,
|
||||
SaveSpaceId SaveSpaceId)
|
||||
{
|
||||
TitleId = titleId;
|
||||
UserId = userId;
|
||||
SaveId = saveId;
|
||||
SaveDataType = saveDataType;
|
||||
SaveSpaceId = saveSpaceId;
|
||||
this.TitleId = TitleId;
|
||||
this.UserId = UserId;
|
||||
this.SaveId = SaveId;
|
||||
this.SaveDataType = SaveDataType;
|
||||
this.SaveSpaceId = SaveSpaceId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,40 +18,40 @@ namespace Ryujinx.HLE.FileSystem
|
|||
|
||||
public Stream RomFs { get; private set; }
|
||||
|
||||
public void LoadRomFs(string fileName)
|
||||
public void LoadRomFs(string FileName)
|
||||
{
|
||||
RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
|
||||
RomFs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public void SetRomFs(Stream romfsStream)
|
||||
public void SetRomFs(Stream RomfsStream)
|
||||
{
|
||||
RomFs?.Close();
|
||||
RomFs = romfsStream;
|
||||
RomFs = RomfsStream;
|
||||
}
|
||||
|
||||
public string GetFullPath(string basePath, string fileName)
|
||||
public string GetFullPath(string BasePath, string FileName)
|
||||
{
|
||||
if (fileName.StartsWith("//"))
|
||||
if (FileName.StartsWith("//"))
|
||||
{
|
||||
fileName = fileName.Substring(2);
|
||||
FileName = FileName.Substring(2);
|
||||
}
|
||||
else if (fileName.StartsWith('/'))
|
||||
else if (FileName.StartsWith('/'))
|
||||
{
|
||||
fileName = fileName.Substring(1);
|
||||
FileName = FileName.Substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName));
|
||||
string FullPath = Path.GetFullPath(Path.Combine(BasePath, FileName));
|
||||
|
||||
if (!fullPath.StartsWith(GetBasePath()))
|
||||
if (!FullPath.StartsWith(GetBasePath()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
return FullPath;
|
||||
}
|
||||
|
||||
public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath);
|
||||
|
@ -60,84 +60,84 @@ namespace Ryujinx.HLE.FileSystem
|
|||
|
||||
public string GetSystemPath() => MakeDirAndGetFullPath(SystemPath);
|
||||
|
||||
public string GetGameSavePath(SaveInfo save, ServiceCtx context)
|
||||
public string GetGameSavePath(SaveInfo Save, ServiceCtx Context)
|
||||
{
|
||||
return MakeDirAndGetFullPath(SaveHelper.GetSavePath(save, context));
|
||||
return MakeDirAndGetFullPath(SaveHelper.GetSavePath(Save, Context));
|
||||
}
|
||||
|
||||
public string GetFullPartitionPath(string partitionPath)
|
||||
public string GetFullPartitionPath(string PartitionPath)
|
||||
{
|
||||
return MakeDirAndGetFullPath(partitionPath);
|
||||
return MakeDirAndGetFullPath(PartitionPath);
|
||||
}
|
||||
|
||||
public string SwitchPathToSystemPath(string switchPath)
|
||||
public string SwitchPathToSystemPath(string SwitchPath)
|
||||
{
|
||||
string[] parts = switchPath.Split(":");
|
||||
string[] Parts = SwitchPath.Split(":");
|
||||
|
||||
if (parts.Length != 2)
|
||||
if (Parts.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetFullPath(MakeDirAndGetFullPath(parts[0]), parts[1]);
|
||||
return GetFullPath(MakeDirAndGetFullPath(Parts[0]), Parts[1]);
|
||||
}
|
||||
|
||||
public string SystemPathToSwitchPath(string systemPath)
|
||||
public string SystemPathToSwitchPath(string SystemPath)
|
||||
{
|
||||
string baseSystemPath = GetBasePath() + Path.DirectorySeparatorChar;
|
||||
string BaseSystemPath = GetBasePath() + Path.DirectorySeparatorChar;
|
||||
|
||||
if (systemPath.StartsWith(baseSystemPath))
|
||||
if (SystemPath.StartsWith(BaseSystemPath))
|
||||
{
|
||||
string rawPath = systemPath.Replace(baseSystemPath, "");
|
||||
int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar);
|
||||
string RawPath = SystemPath.Replace(BaseSystemPath, "");
|
||||
int FirstSeparatorOffset = RawPath.IndexOf(Path.DirectorySeparatorChar);
|
||||
|
||||
if (firstSeparatorOffset == -1)
|
||||
if (FirstSeparatorOffset == -1)
|
||||
{
|
||||
return $"{rawPath}:/";
|
||||
return $"{RawPath}:/";
|
||||
}
|
||||
|
||||
string basePath = rawPath.Substring(0, firstSeparatorOffset);
|
||||
string fileName = rawPath.Substring(firstSeparatorOffset + 1);
|
||||
string BasePath = RawPath.Substring(0, FirstSeparatorOffset);
|
||||
string FileName = RawPath.Substring(FirstSeparatorOffset + 1);
|
||||
|
||||
return $"{basePath}:/{fileName}";
|
||||
return $"{BasePath}:/{FileName}";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string MakeDirAndGetFullPath(string dir)
|
||||
private string MakeDirAndGetFullPath(string Dir)
|
||||
{
|
||||
// Handles Common Switch Content Paths
|
||||
switch (dir)
|
||||
switch (Dir)
|
||||
{
|
||||
case ContentPath.SdCard:
|
||||
case "@Sdcard":
|
||||
dir = SdCardPath;
|
||||
Dir = SdCardPath;
|
||||
break;
|
||||
case ContentPath.User:
|
||||
dir = UserNandPath;
|
||||
Dir = UserNandPath;
|
||||
break;
|
||||
case ContentPath.System:
|
||||
dir = SystemNandPath;
|
||||
Dir = SystemNandPath;
|
||||
break;
|
||||
case ContentPath.SdCardContent:
|
||||
dir = Path.Combine(SdCardPath, "Nintendo", "Contents");
|
||||
Dir = Path.Combine(SdCardPath, "Nintendo", "Contents");
|
||||
break;
|
||||
case ContentPath.UserContent:
|
||||
dir = Path.Combine(UserNandPath, "Contents");
|
||||
Dir = Path.Combine(UserNandPath, "Contents");
|
||||
break;
|
||||
case ContentPath.SystemContent:
|
||||
dir = Path.Combine(SystemNandPath, "Contents");
|
||||
Dir = Path.Combine(SystemNandPath, "Contents");
|
||||
break;
|
||||
}
|
||||
|
||||
string fullPath = Path.Combine(GetBasePath(), dir);
|
||||
string FullPath = Path.Combine(GetBasePath(), Dir);
|
||||
|
||||
if (!Directory.Exists(fullPath))
|
||||
if (!Directory.Exists(FullPath))
|
||||
{
|
||||
Directory.CreateDirectory(fullPath);
|
||||
Directory.CreateDirectory(FullPath);
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
return FullPath;
|
||||
}
|
||||
|
||||
public DriveInfo GetDrive()
|
||||
|
@ -147,9 +147,9 @@ namespace Ryujinx.HLE.FileSystem
|
|||
|
||||
public string GetBasePath()
|
||||
{
|
||||
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
string AppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
|
||||
return Path.Combine(appDataPath, BasePath);
|
||||
return Path.Combine(AppDataPath, BasePath);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -4,22 +4,22 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ArraySubscriptingExpression : BaseNode
|
||||
{
|
||||
private BaseNode _leftNode;
|
||||
private BaseNode _subscript;
|
||||
private BaseNode LeftNode;
|
||||
private BaseNode Subscript;
|
||||
|
||||
public ArraySubscriptingExpression(BaseNode leftNode, BaseNode subscript) : base(NodeType.ArraySubscriptingExpression)
|
||||
public ArraySubscriptingExpression(BaseNode LeftNode, BaseNode Subscript) : base(NodeType.ArraySubscriptingExpression)
|
||||
{
|
||||
_leftNode = leftNode;
|
||||
_subscript = subscript;
|
||||
this.LeftNode = LeftNode;
|
||||
this.Subscript = Subscript;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
_leftNode.Print(writer);
|
||||
writer.Write(")[");
|
||||
_subscript.Print(writer);
|
||||
writer.Write("]");
|
||||
Writer.Write("(");
|
||||
LeftNode.Print(Writer);
|
||||
Writer.Write(")[");
|
||||
Subscript.Print(Writer);
|
||||
Writer.Write("]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,20 +4,20 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ArrayType : BaseNode
|
||||
{
|
||||
private BaseNode _base;
|
||||
private BaseNode _dimensionExpression;
|
||||
private string _dimensionString;
|
||||
private BaseNode Base;
|
||||
private BaseNode DimensionExpression;
|
||||
private string DimensionString;
|
||||
|
||||
public ArrayType(BaseNode Base, BaseNode dimensionExpression = null) : base(NodeType.ArrayType)
|
||||
public ArrayType(BaseNode Base, BaseNode DimensionExpression = null) : base(NodeType.ArrayType)
|
||||
{
|
||||
_base = Base;
|
||||
_dimensionExpression = dimensionExpression;
|
||||
this.Base = Base;
|
||||
this.DimensionExpression = DimensionExpression;
|
||||
}
|
||||
|
||||
public ArrayType(BaseNode Base, string dimensionString) : base(NodeType.ArrayType)
|
||||
public ArrayType(BaseNode Base, string DimensionString) : base(NodeType.ArrayType)
|
||||
{
|
||||
_base = Base;
|
||||
_dimensionString = dimensionString;
|
||||
this.Base = Base;
|
||||
this.DimensionString = DimensionString;
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
|
@ -30,30 +30,30 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return true;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_base.PrintLeft(writer);
|
||||
Base.PrintLeft(Writer);
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
// FIXME: detect if previous char was a ].
|
||||
writer.Write(" ");
|
||||
Writer.Write(" ");
|
||||
|
||||
writer.Write("[");
|
||||
Writer.Write("[");
|
||||
|
||||
if (_dimensionString != null)
|
||||
if (DimensionString != null)
|
||||
{
|
||||
writer.Write(_dimensionString);
|
||||
Writer.Write(DimensionString);
|
||||
}
|
||||
else if (_dimensionExpression != null)
|
||||
else if (DimensionExpression != null)
|
||||
{
|
||||
_dimensionExpression.Print(writer);
|
||||
DimensionExpression.Print(Writer);
|
||||
}
|
||||
|
||||
writer.Write("]");
|
||||
Writer.Write("]");
|
||||
|
||||
_base.PrintRight(writer);
|
||||
Base.PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public enum NodeType
|
||||
{
|
||||
CvQualifierType,
|
||||
CVQualifierType,
|
||||
SimpleReferenceType,
|
||||
NameType,
|
||||
EncodedFunction,
|
||||
|
@ -62,22 +62,22 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public NodeType Type { get; protected set; }
|
||||
|
||||
public BaseNode(NodeType type)
|
||||
public BaseNode(NodeType Type)
|
||||
{
|
||||
Type = type;
|
||||
this.Type = Type;
|
||||
}
|
||||
|
||||
public virtual void Print(TextWriter writer)
|
||||
public virtual void Print(TextWriter Writer)
|
||||
{
|
||||
PrintLeft(writer);
|
||||
PrintLeft(Writer);
|
||||
|
||||
if (HasRightPart())
|
||||
{
|
||||
PrintRight(writer);
|
||||
PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void PrintLeft(TextWriter writer);
|
||||
public abstract void PrintLeft(TextWriter Writer);
|
||||
|
||||
public virtual bool HasRightPart()
|
||||
{
|
||||
|
@ -99,15 +99,15 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return null;
|
||||
}
|
||||
|
||||
public virtual void PrintRight(TextWriter writer) {}
|
||||
public virtual void PrintRight(TextWriter Writer) {}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
StringWriter Writer = new StringWriter();
|
||||
|
||||
Print(writer);
|
||||
Print(Writer);
|
||||
|
||||
return writer.ToString();
|
||||
return Writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,37 +4,37 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class BinaryExpression : BaseNode
|
||||
{
|
||||
private BaseNode _leftPart;
|
||||
private string _name;
|
||||
private BaseNode _rightPart;
|
||||
private BaseNode LeftPart;
|
||||
private string Name;
|
||||
private BaseNode RightPart;
|
||||
|
||||
public BinaryExpression(BaseNode leftPart, string name, BaseNode rightPart) : base(NodeType.BinaryExpression)
|
||||
public BinaryExpression(BaseNode LeftPart, string Name, BaseNode RightPart) : base(NodeType.BinaryExpression)
|
||||
{
|
||||
_leftPart = leftPart;
|
||||
_name = name;
|
||||
_rightPart = rightPart;
|
||||
this.LeftPart = LeftPart;
|
||||
this.Name = Name;
|
||||
this.RightPart = RightPart;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_name.Equals(">"))
|
||||
if (Name.Equals(">"))
|
||||
{
|
||||
writer.Write("(");
|
||||
Writer.Write("(");
|
||||
}
|
||||
|
||||
writer.Write("(");
|
||||
_leftPart.Print(writer);
|
||||
writer.Write(") ");
|
||||
Writer.Write("(");
|
||||
LeftPart.Print(Writer);
|
||||
Writer.Write(") ");
|
||||
|
||||
writer.Write(_name);
|
||||
Writer.Write(Name);
|
||||
|
||||
writer.Write(" (");
|
||||
_rightPart.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write(" (");
|
||||
RightPart.Print(Writer);
|
||||
Writer.Write(")");
|
||||
|
||||
if (_name.Equals(">"))
|
||||
if (Name.Equals(">"))
|
||||
{
|
||||
writer.Write(")");
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,37 +4,37 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class BracedExpression : BaseNode
|
||||
{
|
||||
private BaseNode _element;
|
||||
private BaseNode _expression;
|
||||
private bool _isArrayExpression;
|
||||
private BaseNode Element;
|
||||
private BaseNode Expression;
|
||||
private bool IsArrayExpression;
|
||||
|
||||
public BracedExpression(BaseNode element, BaseNode expression, bool isArrayExpression) : base(NodeType.BracedExpression)
|
||||
public BracedExpression(BaseNode Element, BaseNode Expression, bool IsArrayExpression) : base(NodeType.BracedExpression)
|
||||
{
|
||||
_element = element;
|
||||
_expression = expression;
|
||||
_isArrayExpression = isArrayExpression;
|
||||
this.Element = Element;
|
||||
this.Expression = Expression;
|
||||
this.IsArrayExpression = IsArrayExpression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_isArrayExpression)
|
||||
if (IsArrayExpression)
|
||||
{
|
||||
writer.Write("[");
|
||||
_element.Print(writer);
|
||||
writer.Write("]");
|
||||
Writer.Write("[");
|
||||
Element.Print(Writer);
|
||||
Writer.Write("]");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(".");
|
||||
_element.Print(writer);
|
||||
Writer.Write(".");
|
||||
Element.Print(Writer);
|
||||
}
|
||||
|
||||
if (!_expression.GetType().Equals(NodeType.BracedExpression) || !_expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
if (!Expression.GetType().Equals(NodeType.BracedExpression) || !Expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
{
|
||||
writer.Write(" = ");
|
||||
Writer.Write(" = ");
|
||||
}
|
||||
|
||||
_expression.Print(writer);
|
||||
Expression.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,31 +4,31 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class BracedRangeExpression : BaseNode
|
||||
{
|
||||
private BaseNode _firstNode;
|
||||
private BaseNode _lastNode;
|
||||
private BaseNode _expression;
|
||||
private BaseNode FirstNode;
|
||||
private BaseNode LastNode;
|
||||
private BaseNode Expression;
|
||||
|
||||
public BracedRangeExpression(BaseNode firstNode, BaseNode lastNode, BaseNode expression) : base(NodeType.BracedRangeExpression)
|
||||
public BracedRangeExpression(BaseNode FirstNode, BaseNode LastNode, BaseNode Expression) : base(NodeType.BracedRangeExpression)
|
||||
{
|
||||
_firstNode = firstNode;
|
||||
_lastNode = lastNode;
|
||||
_expression = expression;
|
||||
this.FirstNode = FirstNode;
|
||||
this.LastNode = LastNode;
|
||||
this.Expression = Expression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("[");
|
||||
_firstNode.Print(writer);
|
||||
writer.Write(" ... ");
|
||||
_lastNode.Print(writer);
|
||||
writer.Write("]");
|
||||
Writer.Write("[");
|
||||
FirstNode.Print(Writer);
|
||||
Writer.Write(" ... ");
|
||||
LastNode.Print(Writer);
|
||||
Writer.Write("]");
|
||||
|
||||
if (!_expression.GetType().Equals(NodeType.BracedExpression) || !_expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
if (!Expression.GetType().Equals(NodeType.BracedExpression) || !Expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
{
|
||||
writer.Write(" = ");
|
||||
Writer.Write(" = ");
|
||||
}
|
||||
|
||||
_expression.Print(writer);
|
||||
Expression.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,20 +5,20 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class CallExpression : NodeArray
|
||||
{
|
||||
private BaseNode _callee;
|
||||
private BaseNode Callee;
|
||||
|
||||
public CallExpression(BaseNode callee, List<BaseNode> nodes) : base(nodes, NodeType.CallExpression)
|
||||
public CallExpression(BaseNode Callee, List<BaseNode> Nodes) : base(Nodes, NodeType.CallExpression)
|
||||
{
|
||||
_callee = callee;
|
||||
this.Callee = Callee;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_callee.Print(writer);
|
||||
Callee.Print(Writer);
|
||||
|
||||
writer.Write("(");
|
||||
writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
writer.Write(")");
|
||||
Writer.Write("(");
|
||||
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,25 +4,25 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class CastExpression : BaseNode
|
||||
{
|
||||
private string _kind;
|
||||
private BaseNode _to;
|
||||
private BaseNode _from;
|
||||
private string Kind;
|
||||
private BaseNode To;
|
||||
private BaseNode From;
|
||||
|
||||
public CastExpression(string kind, BaseNode to, BaseNode from) : base(NodeType.CastExpression)
|
||||
public CastExpression(string Kind, BaseNode To, BaseNode From) : base(NodeType.CastExpression)
|
||||
{
|
||||
_kind = kind;
|
||||
_to = to;
|
||||
_from = from;
|
||||
this.Kind = Kind;
|
||||
this.To = To;
|
||||
this.From = From;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(_kind);
|
||||
writer.Write("<");
|
||||
_to.PrintLeft(writer);
|
||||
writer.Write(">(");
|
||||
_from.PrintLeft(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write(Kind);
|
||||
Writer.Write("<");
|
||||
To.PrintLeft(Writer);
|
||||
Writer.Write(">(");
|
||||
From.PrintLeft(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,26 +4,26 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ConditionalExpression : BaseNode
|
||||
{
|
||||
private BaseNode _thenNode;
|
||||
private BaseNode _elseNode;
|
||||
private BaseNode _conditionNode;
|
||||
private BaseNode ThenNode;
|
||||
private BaseNode ElseNode;
|
||||
private BaseNode ConditionNode;
|
||||
|
||||
public ConditionalExpression(BaseNode conditionNode, BaseNode thenNode, BaseNode elseNode) : base(NodeType.ConditionalExpression)
|
||||
public ConditionalExpression(BaseNode ConditionNode, BaseNode ThenNode, BaseNode ElseNode) : base(NodeType.ConditionalExpression)
|
||||
{
|
||||
_thenNode = thenNode;
|
||||
_conditionNode = conditionNode;
|
||||
_elseNode = elseNode;
|
||||
this.ThenNode = ThenNode;
|
||||
this.ConditionNode = ConditionNode;
|
||||
this.ElseNode = ElseNode;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
_conditionNode.Print(writer);
|
||||
writer.Write(") ? (");
|
||||
_thenNode.Print(writer);
|
||||
writer.Write(") : (");
|
||||
_elseNode.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write("(");
|
||||
ConditionNode.Print(Writer);
|
||||
Writer.Write(") ? (");
|
||||
ThenNode.Print(Writer);
|
||||
Writer.Write(") : (");
|
||||
ElseNode.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,21 +4,21 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ConversionExpression : BaseNode
|
||||
{
|
||||
private BaseNode _typeNode;
|
||||
private BaseNode _expressions;
|
||||
private BaseNode TypeNode;
|
||||
private BaseNode Expressions;
|
||||
|
||||
public ConversionExpression(BaseNode typeNode, BaseNode expressions) : base(NodeType.ConversionExpression)
|
||||
public ConversionExpression(BaseNode TypeNode, BaseNode Expressions) : base(NodeType.ConversionExpression)
|
||||
{
|
||||
_typeNode = typeNode;
|
||||
_expressions = expressions;
|
||||
this.TypeNode = TypeNode;
|
||||
this.Expressions = Expressions;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
_typeNode.Print(writer);
|
||||
writer.Write(")(");
|
||||
_expressions.Print(writer);
|
||||
Writer.Write("(");
|
||||
TypeNode.Print(Writer);
|
||||
Writer.Write(")(");
|
||||
Expressions.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,12 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ConversionOperatorType : ParentNode
|
||||
{
|
||||
public ConversionOperatorType(BaseNode child) : base(NodeType.ConversionOperatorType, child) { }
|
||||
public ConversionOperatorType(BaseNode Child) : base(NodeType.ConversionOperatorType, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("operator ");
|
||||
Child.Print(writer);
|
||||
Writer.Write("operator ");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,21 +4,21 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class CtorDtorNameType : ParentNode
|
||||
{
|
||||
private bool _isDestructor;
|
||||
private bool IsDestructor;
|
||||
|
||||
public CtorDtorNameType(BaseNode name, bool isDestructor) : base(NodeType.CtorDtorNameType, name)
|
||||
public CtorDtorNameType(BaseNode Name, bool IsDestructor) : base(NodeType.CtorDtorNameType, Name)
|
||||
{
|
||||
_isDestructor = isDestructor;
|
||||
this.IsDestructor = IsDestructor;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_isDestructor)
|
||||
if (IsDestructor)
|
||||
{
|
||||
writer.Write("~");
|
||||
Writer.Write("~");
|
||||
}
|
||||
|
||||
writer.Write(Child.GetName());
|
||||
Writer.Write(Child.GetName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,21 +4,21 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class CtorVtableSpecialName : BaseNode
|
||||
{
|
||||
private BaseNode _firstType;
|
||||
private BaseNode _secondType;
|
||||
private BaseNode FirstType;
|
||||
private BaseNode SecondType;
|
||||
|
||||
public CtorVtableSpecialName(BaseNode firstType, BaseNode secondType) : base(NodeType.CtorVtableSpecialName)
|
||||
public CtorVtableSpecialName(BaseNode FirstType, BaseNode SecondType) : base(NodeType.CtorVtableSpecialName)
|
||||
{
|
||||
_firstType = firstType;
|
||||
_secondType = secondType;
|
||||
this.FirstType = FirstType;
|
||||
this.SecondType = SecondType;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("construction vtable for ");
|
||||
_firstType.Print(writer);
|
||||
writer.Write("-in-");
|
||||
_secondType.Print(writer);
|
||||
Writer.Write("construction vtable for ");
|
||||
FirstType.Print(Writer);
|
||||
Writer.Write("-in-");
|
||||
SecondType.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,30 +4,30 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class DeleteExpression : ParentNode
|
||||
{
|
||||
private bool _isGlobal;
|
||||
private bool _isArrayExpression;
|
||||
private bool IsGlobal;
|
||||
private bool IsArrayExpression;
|
||||
|
||||
public DeleteExpression(BaseNode child, bool isGlobal, bool isArrayExpression) : base(NodeType.DeleteExpression, child)
|
||||
public DeleteExpression(BaseNode Child, bool IsGlobal, bool IsArrayExpression) : base(NodeType.DeleteExpression, Child)
|
||||
{
|
||||
_isGlobal = isGlobal;
|
||||
_isArrayExpression = isArrayExpression;
|
||||
this.IsGlobal = IsGlobal;
|
||||
this.IsArrayExpression = IsArrayExpression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_isGlobal)
|
||||
if (IsGlobal)
|
||||
{
|
||||
writer.Write("::");
|
||||
Writer.Write("::");
|
||||
}
|
||||
|
||||
writer.Write("delete");
|
||||
Writer.Write("delete");
|
||||
|
||||
if (_isArrayExpression)
|
||||
if (IsArrayExpression)
|
||||
{
|
||||
writer.Write("[] ");
|
||||
Writer.Write("[] ");
|
||||
}
|
||||
|
||||
Child.Print(writer);
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,12 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class DtorName : ParentNode
|
||||
{
|
||||
public DtorName(BaseNode name) : base(NodeType.DtOrName, name) { }
|
||||
public DtorName(BaseNode Name) : base(NodeType.DtOrName, Name) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("~");
|
||||
Child.PrintLeft(writer);
|
||||
Writer.Write("~");
|
||||
Child.PrintLeft(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,13 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class DynamicExceptionSpec : ParentNode
|
||||
{
|
||||
public DynamicExceptionSpec(BaseNode child) : base(NodeType.DynamicExceptionSpec, child) { }
|
||||
public DynamicExceptionSpec(BaseNode Child) : base(NodeType.DynamicExceptionSpec, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("throw(");
|
||||
Child.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write("throw(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,18 +4,18 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ElaboratedType : ParentNode
|
||||
{
|
||||
private string _elaborated;
|
||||
private string Elaborated;
|
||||
|
||||
public ElaboratedType(string elaborated, BaseNode type) : base(NodeType.ElaboratedType, type)
|
||||
public ElaboratedType(string Elaborated, BaseNode Type) : base(NodeType.ElaboratedType, Type)
|
||||
{
|
||||
_elaborated = elaborated;
|
||||
this.Elaborated = Elaborated;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(_elaborated);
|
||||
writer.Write(" ");
|
||||
Child.Print(writer);
|
||||
Writer.Write(Elaborated);
|
||||
Writer.Write(" ");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,22 +4,22 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class EnclosedExpression : BaseNode
|
||||
{
|
||||
private string _prefix;
|
||||
private BaseNode _expression;
|
||||
private string _postfix;
|
||||
private string Prefix;
|
||||
private BaseNode Expression;
|
||||
private string Postfix;
|
||||
|
||||
public EnclosedExpression(string prefix, BaseNode expression, string postfix) : base(NodeType.EnclosedExpression)
|
||||
public EnclosedExpression(string Prefix, BaseNode Expression, string Postfix) : base(NodeType.EnclosedExpression)
|
||||
{
|
||||
_prefix = prefix;
|
||||
_expression = expression;
|
||||
_postfix = postfix;
|
||||
this.Prefix = Prefix;
|
||||
this.Expression = Expression;
|
||||
this.Postfix = Postfix;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(_prefix);
|
||||
_expression.Print(writer);
|
||||
writer.Write(_postfix);
|
||||
Writer.Write(Prefix);
|
||||
Expression.Print(Writer);
|
||||
Writer.Write(Postfix);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,36 +4,36 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class EncodedFunction : BaseNode
|
||||
{
|
||||
private BaseNode _name;
|
||||
private BaseNode _params;
|
||||
private BaseNode _cv;
|
||||
private BaseNode _ref;
|
||||
private BaseNode _attrs;
|
||||
private BaseNode _ret;
|
||||
private BaseNode Name;
|
||||
private BaseNode Params;
|
||||
private BaseNode CV;
|
||||
private BaseNode Ref;
|
||||
private BaseNode Attrs;
|
||||
private BaseNode Ret;
|
||||
|
||||
public EncodedFunction(BaseNode name, BaseNode Params, BaseNode cv, BaseNode Ref, BaseNode attrs, BaseNode ret) : base(NodeType.NameType)
|
||||
public EncodedFunction(BaseNode Name, BaseNode Params, BaseNode CV, BaseNode Ref, BaseNode Attrs, BaseNode Ret) : base(NodeType.NameType)
|
||||
{
|
||||
_name = name;
|
||||
_params = Params;
|
||||
_cv = cv;
|
||||
_ref = Ref;
|
||||
_attrs = attrs;
|
||||
_ret = ret;
|
||||
this.Name = Name;
|
||||
this.Params = Params;
|
||||
this.CV = CV;
|
||||
this.Ref = Ref;
|
||||
this.Attrs = Attrs;
|
||||
this.Ret = Ret;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_ret != null)
|
||||
if (Ret != null)
|
||||
{
|
||||
_ret.PrintLeft(writer);
|
||||
Ret.PrintLeft(Writer);
|
||||
|
||||
if (!_ret.HasRightPart())
|
||||
if (!Ret.HasRightPart())
|
||||
{
|
||||
writer.Write(" ");
|
||||
Writer.Write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
_name.Print(writer);
|
||||
Name.Print(Writer);
|
||||
|
||||
}
|
||||
|
||||
|
@ -42,35 +42,35 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return true;
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
Writer.Write("(");
|
||||
|
||||
if (_params != null)
|
||||
if (Params != null)
|
||||
{
|
||||
_params.Print(writer);
|
||||
Params.Print(Writer);
|
||||
}
|
||||
|
||||
writer.Write(")");
|
||||
Writer.Write(")");
|
||||
|
||||
if (_ret != null)
|
||||
if (Ret != null)
|
||||
{
|
||||
_ret.PrintRight(writer);
|
||||
Ret.PrintRight(Writer);
|
||||
}
|
||||
|
||||
if (_cv != null)
|
||||
if (CV != null)
|
||||
{
|
||||
_cv.Print(writer);
|
||||
CV.Print(Writer);
|
||||
}
|
||||
|
||||
if (_ref != null)
|
||||
if (Ref != null)
|
||||
{
|
||||
_ref.Print(writer);
|
||||
Ref.Print(Writer);
|
||||
}
|
||||
|
||||
if (_attrs != null)
|
||||
if (Attrs != null)
|
||||
{
|
||||
_attrs.Print(writer);
|
||||
Attrs.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,45 +4,45 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class FoldExpression : BaseNode
|
||||
{
|
||||
private bool _isLeftFold;
|
||||
private string _operatorName;
|
||||
private BaseNode _expression;
|
||||
private BaseNode _initializer;
|
||||
private bool IsLeftFold;
|
||||
private string OperatorName;
|
||||
private BaseNode Expression;
|
||||
private BaseNode Initializer;
|
||||
|
||||
public FoldExpression(bool isLeftFold, string operatorName, BaseNode expression, BaseNode initializer) : base(NodeType.FunctionParameter)
|
||||
public FoldExpression(bool IsLeftFold, string OperatorName, BaseNode Expression, BaseNode Initializer) : base(NodeType.FunctionParameter)
|
||||
{
|
||||
_isLeftFold = isLeftFold;
|
||||
_operatorName = operatorName;
|
||||
_expression = expression;
|
||||
_initializer = initializer;
|
||||
this.IsLeftFold = IsLeftFold;
|
||||
this.OperatorName = OperatorName;
|
||||
this.Expression = Expression;
|
||||
this.Initializer = Initializer;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
Writer.Write("(");
|
||||
|
||||
if (_isLeftFold && _initializer != null)
|
||||
if (IsLeftFold && Initializer != null)
|
||||
{
|
||||
_initializer.Print(writer);
|
||||
writer.Write(" ");
|
||||
writer.Write(_operatorName);
|
||||
writer.Write(" ");
|
||||
Initializer.Print(Writer);
|
||||
Writer.Write(" ");
|
||||
Writer.Write(OperatorName);
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
writer.Write(_isLeftFold ? "... " : " ");
|
||||
writer.Write(_operatorName);
|
||||
writer.Write(!_isLeftFold ? " ..." : " ");
|
||||
_expression.Print(writer);
|
||||
Writer.Write(IsLeftFold ? "... " : " ");
|
||||
Writer.Write(OperatorName);
|
||||
Writer.Write(!IsLeftFold ? " ..." : " ");
|
||||
Expression.Print(Writer);
|
||||
|
||||
if (!_isLeftFold && _initializer != null)
|
||||
if (!IsLeftFold && Initializer != null)
|
||||
{
|
||||
_initializer.Print(writer);
|
||||
writer.Write(" ");
|
||||
writer.Write(_operatorName);
|
||||
writer.Write(" ");
|
||||
Initializer.Print(Writer);
|
||||
Writer.Write(" ");
|
||||
Writer.Write(OperatorName);
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
writer.Write(")");
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,11 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
// TODO: Compute inside the Demangler
|
||||
public BaseNode Reference;
|
||||
private int _index;
|
||||
private int Index;
|
||||
|
||||
public ForwardTemplateReference(int index) : base(NodeType.ForwardTemplateReference)
|
||||
public ForwardTemplateReference(int Index) : base(NodeType.ForwardTemplateReference)
|
||||
{
|
||||
_index = index;
|
||||
this.Index = Index;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
|
@ -18,14 +18,14 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return Reference.GetName();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Reference.PrintLeft(writer);
|
||||
Reference.PrintLeft(Writer);
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
Reference.PrintRight(writer);
|
||||
Reference.PrintRight(Writer);
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
|
|
|
@ -4,20 +4,20 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class FunctionParameter : BaseNode
|
||||
{
|
||||
private string _number;
|
||||
private string Number;
|
||||
|
||||
public FunctionParameter(string number) : base(NodeType.FunctionParameter)
|
||||
public FunctionParameter(string Number) : base(NodeType.FunctionParameter)
|
||||
{
|
||||
_number = number;
|
||||
this.Number = Number;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("fp ");
|
||||
Writer.Write("fp ");
|
||||
|
||||
if (_number != null)
|
||||
if (Number != null)
|
||||
{
|
||||
writer.Write(_number);
|
||||
Writer.Write(Number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,47 +4,47 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class FunctionType : BaseNode
|
||||
{
|
||||
private BaseNode _returnType;
|
||||
private BaseNode _params;
|
||||
private BaseNode _cvQualifier;
|
||||
private SimpleReferenceType _referenceQualifier;
|
||||
private BaseNode _exceptionSpec;
|
||||
private BaseNode ReturnType;
|
||||
private BaseNode Params;
|
||||
private BaseNode CVQualifier;
|
||||
private SimpleReferenceType ReferenceQualifier;
|
||||
private BaseNode ExceptionSpec;
|
||||
|
||||
public FunctionType(BaseNode returnType, BaseNode Params, BaseNode cvQualifier, SimpleReferenceType referenceQualifier, BaseNode exceptionSpec) : base(NodeType.FunctionType)
|
||||
public FunctionType(BaseNode ReturnType, BaseNode Params, BaseNode CVQualifier, SimpleReferenceType ReferenceQualifier, BaseNode ExceptionSpec) : base(NodeType.FunctionType)
|
||||
{
|
||||
_returnType = returnType;
|
||||
_params = Params;
|
||||
_cvQualifier = cvQualifier;
|
||||
_referenceQualifier = referenceQualifier;
|
||||
_exceptionSpec = exceptionSpec;
|
||||
this.ReturnType = ReturnType;
|
||||
this.Params = Params;
|
||||
this.CVQualifier = CVQualifier;
|
||||
this.ReferenceQualifier = ReferenceQualifier;
|
||||
this.ExceptionSpec = ExceptionSpec;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_returnType.PrintLeft(writer);
|
||||
writer.Write(" ");
|
||||
ReturnType.PrintLeft(Writer);
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
_params.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write("(");
|
||||
Params.Print(Writer);
|
||||
Writer.Write(")");
|
||||
|
||||
_returnType.PrintRight(writer);
|
||||
ReturnType.PrintRight(Writer);
|
||||
|
||||
_cvQualifier.Print(writer);
|
||||
CVQualifier.Print(Writer);
|
||||
|
||||
if (_referenceQualifier.Qualifier != Reference.None)
|
||||
if (ReferenceQualifier.Qualifier != Reference.None)
|
||||
{
|
||||
writer.Write(" ");
|
||||
_referenceQualifier.PrintQualifier(writer);
|
||||
Writer.Write(" ");
|
||||
ReferenceQualifier.PrintQualifier(Writer);
|
||||
}
|
||||
|
||||
if (_exceptionSpec != null)
|
||||
if (ExceptionSpec != null)
|
||||
{
|
||||
writer.Write(" ");
|
||||
_exceptionSpec.Print(writer);
|
||||
Writer.Write(" ");
|
||||
ExceptionSpec.Print(Writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class GlobalQualifiedName : ParentNode
|
||||
{
|
||||
public GlobalQualifiedName(BaseNode child) : base(NodeType.GlobalQualifiedName, child) { }
|
||||
public GlobalQualifiedName(BaseNode Child) : base(NodeType.GlobalQualifiedName, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("::");
|
||||
Child.Print(writer);
|
||||
Writer.Write("::");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,25 +5,25 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class InitListExpression : BaseNode
|
||||
{
|
||||
private BaseNode _typeNode;
|
||||
private List<BaseNode> _nodes;
|
||||
private BaseNode TypeNode;
|
||||
private List<BaseNode> Nodes;
|
||||
|
||||
public InitListExpression(BaseNode typeNode, List<BaseNode> nodes) : base(NodeType.InitListExpression)
|
||||
public InitListExpression(BaseNode TypeNode, List<BaseNode> Nodes) : base(NodeType.InitListExpression)
|
||||
{
|
||||
_typeNode = typeNode;
|
||||
_nodes = nodes;
|
||||
this.TypeNode = TypeNode;
|
||||
this.Nodes = Nodes;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_typeNode != null)
|
||||
if (TypeNode != null)
|
||||
{
|
||||
_typeNode.Print(writer);
|
||||
TypeNode.Print(Writer);
|
||||
}
|
||||
|
||||
writer.Write("{");
|
||||
writer.Write(string.Join<BaseNode>(", ", _nodes.ToArray()));
|
||||
writer.Write("}");
|
||||
Writer.Write("{");
|
||||
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
Writer.Write("}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,19 +4,19 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class IntegerCastExpression : ParentNode
|
||||
{
|
||||
private string _number;
|
||||
private string Number;
|
||||
|
||||
public IntegerCastExpression(BaseNode type, string number) : base(NodeType.IntegerCastExpression, type)
|
||||
public IntegerCastExpression(BaseNode Type, string Number) : base(NodeType.IntegerCastExpression, Type)
|
||||
{
|
||||
_number = number;
|
||||
this.Number = Number;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
Child.Print(writer);
|
||||
writer.Write(")");
|
||||
writer.Write(_number);
|
||||
Writer.Write("(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
Writer.Write(Number);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,37 +4,37 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class IntegerLiteral : BaseNode
|
||||
{
|
||||
private string _literalName;
|
||||
private string _literalValue;
|
||||
private string LitteralName;
|
||||
private string LitteralValue;
|
||||
|
||||
public IntegerLiteral(string literalName, string literalValue) : base(NodeType.IntegerLiteral)
|
||||
public IntegerLiteral(string LitteralName, string LitteralValue) : base(NodeType.IntegerLiteral)
|
||||
{
|
||||
_literalValue = literalValue;
|
||||
_literalName = literalName;
|
||||
this.LitteralValue = LitteralValue;
|
||||
this.LitteralName = LitteralName;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_literalName.Length > 3)
|
||||
if (LitteralName.Length > 3)
|
||||
{
|
||||
writer.Write("(");
|
||||
writer.Write(_literalName);
|
||||
writer.Write(")");
|
||||
Writer.Write("(");
|
||||
Writer.Write(LitteralName);
|
||||
Writer.Write(")");
|
||||
}
|
||||
|
||||
if (_literalValue[0] == 'n')
|
||||
if (LitteralValue[0] == 'n')
|
||||
{
|
||||
writer.Write("-");
|
||||
writer.Write(_literalValue.Substring(1));
|
||||
Writer.Write("-");
|
||||
Writer.Write(LitteralValue.Substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(_literalValue);
|
||||
Writer.Write(LitteralValue);
|
||||
}
|
||||
|
||||
if (_literalName.Length <= 3)
|
||||
if (LitteralName.Length <= 3)
|
||||
{
|
||||
writer.Write(_literalName);
|
||||
Writer.Write(LitteralName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class LiteralOperator : ParentNode
|
||||
{
|
||||
public LiteralOperator(BaseNode child) : base(NodeType.LiteralOperator, child) { }
|
||||
public LiteralOperator(BaseNode Child) : base(NodeType.LiteralOperator, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("operator \"");
|
||||
Child.PrintLeft(writer);
|
||||
writer.Write("\"");
|
||||
Writer.Write("operator \"");
|
||||
Child.PrintLeft(Writer);
|
||||
Writer.Write("\"");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,20 +4,20 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class LocalName : BaseNode
|
||||
{
|
||||
private BaseNode _encoding;
|
||||
private BaseNode _entity;
|
||||
private BaseNode Encoding;
|
||||
private BaseNode Entity;
|
||||
|
||||
public LocalName(BaseNode encoding, BaseNode entity) : base(NodeType.LocalName)
|
||||
public LocalName(BaseNode Encoding, BaseNode Entity) : base(NodeType.LocalName)
|
||||
{
|
||||
_encoding = encoding;
|
||||
_entity = entity;
|
||||
this.Encoding = Encoding;
|
||||
this.Entity = Entity;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_encoding.Print(writer);
|
||||
writer.Write("::");
|
||||
_entity.Print(writer);
|
||||
Encoding.Print(Writer);
|
||||
Writer.Write("::");
|
||||
Entity.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,22 +4,22 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class MemberExpression : BaseNode
|
||||
{
|
||||
private BaseNode _leftNode;
|
||||
private string _kind;
|
||||
private BaseNode _rightNode;
|
||||
private BaseNode LeftNode;
|
||||
private string Kind;
|
||||
private BaseNode RightNode;
|
||||
|
||||
public MemberExpression(BaseNode leftNode, string kind, BaseNode rightNode) : base(NodeType.MemberExpression)
|
||||
public MemberExpression(BaseNode LeftNode, string Kind, BaseNode RightNode) : base(NodeType.MemberExpression)
|
||||
{
|
||||
_leftNode = leftNode;
|
||||
_kind = kind;
|
||||
_rightNode = rightNode;
|
||||
this.LeftNode = LeftNode;
|
||||
this.Kind = Kind;
|
||||
this.RightNode = RightNode;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_leftNode.Print(writer);
|
||||
writer.Write(_kind);
|
||||
_rightNode.Print(writer);
|
||||
LeftNode.Print(Writer);
|
||||
Writer.Write(Kind);
|
||||
RightNode.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,26 +4,26 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class NameType : BaseNode
|
||||
{
|
||||
private string _nameValue;
|
||||
private string NameValue;
|
||||
|
||||
public NameType(string nameValue, NodeType type) : base(type)
|
||||
public NameType(string NameValue, NodeType Type) : base(Type)
|
||||
{
|
||||
_nameValue = nameValue;
|
||||
this.NameValue = NameValue;
|
||||
}
|
||||
|
||||
public NameType(string nameValue) : base(NodeType.NameType)
|
||||
public NameType(string NameValue) : base(NodeType.NameType)
|
||||
{
|
||||
_nameValue = nameValue;
|
||||
this.NameValue = NameValue;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return _nameValue;
|
||||
return NameValue;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(_nameValue);
|
||||
Writer.Write(NameValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,24 +4,24 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class NameTypeWithTemplateArguments : BaseNode
|
||||
{
|
||||
private BaseNode _prev;
|
||||
private BaseNode _templateArgument;
|
||||
private BaseNode Prev;
|
||||
private BaseNode TemplateArgument;
|
||||
|
||||
public NameTypeWithTemplateArguments(BaseNode prev, BaseNode templateArgument) : base(NodeType.NameTypeWithTemplateArguments)
|
||||
public NameTypeWithTemplateArguments(BaseNode Prev, BaseNode TemplateArgument) : base(NodeType.NameTypeWithTemplateArguments)
|
||||
{
|
||||
_prev = prev;
|
||||
_templateArgument = templateArgument;
|
||||
this.Prev = Prev;
|
||||
this.TemplateArgument = TemplateArgument;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return _prev.GetName();
|
||||
return Prev.GetName();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_prev.Print(writer);
|
||||
_templateArgument.Print(writer);
|
||||
Prev.Print(Writer);
|
||||
TemplateArgument.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,23 +4,23 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class NestedName : ParentNode
|
||||
{
|
||||
private BaseNode _name;
|
||||
private BaseNode Name;
|
||||
|
||||
public NestedName(BaseNode name, BaseNode type) : base(NodeType.NestedName, type)
|
||||
public NestedName(BaseNode Name, BaseNode Type) : base(NodeType.NestedName, Type)
|
||||
{
|
||||
_name = name;
|
||||
this.Name = Name;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return _name.GetName();
|
||||
return Name.GetName();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Child.Print(writer);
|
||||
writer.Write("::");
|
||||
_name.Print(writer);
|
||||
Child.Print(Writer);
|
||||
Writer.Write("::");
|
||||
Name.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,51 +4,51 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class NewExpression : BaseNode
|
||||
{
|
||||
private NodeArray _expressions;
|
||||
private BaseNode _typeNode;
|
||||
private NodeArray _initializers;
|
||||
private NodeArray Expressions;
|
||||
private BaseNode TypeNode;
|
||||
private NodeArray Initializers;
|
||||
|
||||
private bool _isGlobal;
|
||||
private bool _isArrayExpression;
|
||||
private bool IsGlobal;
|
||||
private bool IsArrayExpression;
|
||||
|
||||
public NewExpression(NodeArray expressions, BaseNode typeNode, NodeArray initializers, bool isGlobal, bool isArrayExpression) : base(NodeType.NewExpression)
|
||||
public NewExpression(NodeArray Expressions, BaseNode TypeNode, NodeArray Initializers, bool IsGlobal, bool IsArrayExpression) : base(NodeType.NewExpression)
|
||||
{
|
||||
_expressions = expressions;
|
||||
_typeNode = typeNode;
|
||||
_initializers = initializers;
|
||||
this.Expressions = Expressions;
|
||||
this.TypeNode = TypeNode;
|
||||
this.Initializers = Initializers;
|
||||
|
||||
_isGlobal = isGlobal;
|
||||
_isArrayExpression = isArrayExpression;
|
||||
this.IsGlobal = IsGlobal;
|
||||
this.IsArrayExpression = IsArrayExpression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (_isGlobal)
|
||||
if (IsGlobal)
|
||||
{
|
||||
writer.Write("::operator ");
|
||||
Writer.Write("::operator ");
|
||||
}
|
||||
|
||||
writer.Write("new ");
|
||||
Writer.Write("new ");
|
||||
|
||||
if (_isArrayExpression)
|
||||
if (IsArrayExpression)
|
||||
{
|
||||
writer.Write("[] ");
|
||||
Writer.Write("[] ");
|
||||
}
|
||||
|
||||
if (_expressions.Nodes.Count != 0)
|
||||
if (Expressions.Nodes.Count != 0)
|
||||
{
|
||||
writer.Write("(");
|
||||
_expressions.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write("(");
|
||||
Expressions.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
|
||||
_typeNode.Print(writer);
|
||||
TypeNode.Print(Writer);
|
||||
|
||||
if (_initializers.Nodes.Count != 0)
|
||||
if (Initializers.Nodes.Count != 0)
|
||||
{
|
||||
writer.Write("(");
|
||||
_initializers.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write("(");
|
||||
Initializers.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public List<BaseNode> Nodes { get; protected set; }
|
||||
|
||||
public NodeArray(List<BaseNode> nodes) : base(NodeType.NodeArray)
|
||||
public NodeArray(List<BaseNode> Nodes) : base(NodeType.NodeArray)
|
||||
{
|
||||
Nodes = nodes;
|
||||
this.Nodes = Nodes;
|
||||
}
|
||||
|
||||
public NodeArray(List<BaseNode> nodes, NodeType type) : base(type)
|
||||
public NodeArray(List<BaseNode> Nodes, NodeType Type) : base(Type)
|
||||
{
|
||||
Nodes = nodes;
|
||||
this.Nodes = Nodes;
|
||||
}
|
||||
|
||||
public override bool IsArray()
|
||||
|
@ -22,9 +22,9 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return true;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,13 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class NoexceptSpec : ParentNode
|
||||
{
|
||||
public NoexceptSpec(BaseNode child) : base(NodeType.NoexceptSpec, child) { }
|
||||
public NoexceptSpec(BaseNode Child) : base(NodeType.NoexceptSpec, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("noexcept(");
|
||||
Child.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write("noexcept(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,29 +5,29 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class PackedTemplateParameter : NodeArray
|
||||
{
|
||||
public PackedTemplateParameter(List<BaseNode> nodes) : base(nodes, NodeType.PackedTemplateParameter) { }
|
||||
public PackedTemplateParameter(List<BaseNode> Nodes) : base(Nodes, NodeType.PackedTemplateParameter) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
foreach (BaseNode node in Nodes)
|
||||
foreach (BaseNode Node in Nodes)
|
||||
{
|
||||
node.PrintLeft(writer);
|
||||
Node.PrintLeft(Writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
foreach (BaseNode node in Nodes)
|
||||
foreach (BaseNode Node in Nodes)
|
||||
{
|
||||
node.PrintLeft(writer);
|
||||
Node.PrintLeft(Writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
foreach (BaseNode node in Nodes)
|
||||
foreach (BaseNode Node in Nodes)
|
||||
{
|
||||
if (node.HasRightPart())
|
||||
if (Node.HasRightPart())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,20 +4,20 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class PackedTemplateParameterExpansion : ParentNode
|
||||
{
|
||||
public PackedTemplateParameterExpansion(BaseNode child) : base(NodeType.PackedTemplateParameterExpansion, child) {}
|
||||
public PackedTemplateParameterExpansion(BaseNode Child) : base(NodeType.PackedTemplateParameterExpansion, Child) {}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (Child is PackedTemplateParameter)
|
||||
{
|
||||
if (((PackedTemplateParameter)Child).Nodes.Count != 0)
|
||||
{
|
||||
Child.Print(writer);
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write("...");
|
||||
Writer.Write("...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public abstract class ParentNode : BaseNode
|
||||
{
|
||||
public BaseNode Child { get; }
|
||||
public BaseNode Child { get; private set; }
|
||||
|
||||
public ParentNode(NodeType type, BaseNode child) : base(type)
|
||||
public ParentNode(NodeType Type, BaseNode Child) : base(Type)
|
||||
{
|
||||
Child = child;
|
||||
this.Child = Child;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
|
|
|
@ -4,42 +4,42 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class PointerType : BaseNode
|
||||
{
|
||||
private BaseNode _child;
|
||||
private BaseNode Child;
|
||||
|
||||
public PointerType(BaseNode child) : base(NodeType.PointerType)
|
||||
public PointerType(BaseNode Child) : base(NodeType.PointerType)
|
||||
{
|
||||
_child = child;
|
||||
this.Child = Child;
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
return _child.HasRightPart();
|
||||
return Child.HasRightPart();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_child.PrintLeft(writer);
|
||||
if (_child.IsArray())
|
||||
Child.PrintLeft(Writer);
|
||||
if (Child.IsArray())
|
||||
{
|
||||
writer.Write(" ");
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
if (_child.IsArray() || _child.HasFunctions())
|
||||
if (Child.IsArray() || Child.HasFunctions())
|
||||
{
|
||||
writer.Write("(");
|
||||
Writer.Write("(");
|
||||
}
|
||||
|
||||
writer.Write("*");
|
||||
Writer.Write("*");
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
if (_child.IsArray() || _child.HasFunctions())
|
||||
if (Child.IsArray() || Child.HasFunctions())
|
||||
{
|
||||
writer.Write(")");
|
||||
Writer.Write(")");
|
||||
}
|
||||
|
||||
_child.PrintRight(writer);
|
||||
Child.PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,19 +4,19 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class PostfixExpression : ParentNode
|
||||
{
|
||||
private string _operator;
|
||||
private string Operator;
|
||||
|
||||
public PostfixExpression(BaseNode type, string Operator) : base(NodeType.PostfixExpression, type)
|
||||
public PostfixExpression(BaseNode Type, string Operator) : base(NodeType.PostfixExpression, Type)
|
||||
{
|
||||
_operator = Operator;
|
||||
this.Operator = Operator;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("(");
|
||||
Child.Print(writer);
|
||||
writer.Write(")");
|
||||
writer.Write(_operator);
|
||||
Writer.Write("(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
Writer.Write(Operator);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,17 +4,17 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class PostfixQualifiedType : ParentNode
|
||||
{
|
||||
private string _postfixQualifier;
|
||||
private string PostfixQualifier;
|
||||
|
||||
public PostfixQualifiedType(string postfixQualifier, BaseNode type) : base(NodeType.PostfixQualifiedType, type)
|
||||
public PostfixQualifiedType(string PostfixQualifier, BaseNode Type) : base(NodeType.PostfixQualifiedType, Type)
|
||||
{
|
||||
_postfixQualifier = postfixQualifier;
|
||||
this.PostfixQualifier = PostfixQualifier;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Child.Print(writer);
|
||||
writer.Write(_postfixQualifier);
|
||||
Child.Print(Writer);
|
||||
Writer.Write(PostfixQualifier);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,19 +4,19 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class PrefixExpression : ParentNode
|
||||
{
|
||||
private string _prefix;
|
||||
private string Prefix;
|
||||
|
||||
public PrefixExpression(string prefix, BaseNode child) : base(NodeType.PrefixExpression, child)
|
||||
public PrefixExpression(string Prefix, BaseNode Child) : base(NodeType.PrefixExpression, Child)
|
||||
{
|
||||
_prefix = prefix;
|
||||
this.Prefix = Prefix;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(_prefix);
|
||||
writer.Write("(");
|
||||
Child.Print(writer);
|
||||
writer.Write(")");
|
||||
Writer.Write(Prefix);
|
||||
Writer.Write("(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,20 +4,20 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class QualifiedName : BaseNode
|
||||
{
|
||||
private BaseNode _qualifier;
|
||||
private BaseNode _name;
|
||||
private BaseNode Qualifier;
|
||||
private BaseNode Name;
|
||||
|
||||
public QualifiedName(BaseNode qualifier, BaseNode name) : base(NodeType.QualifiedName)
|
||||
public QualifiedName(BaseNode Qualifier, BaseNode Name) : base(NodeType.QualifiedName)
|
||||
{
|
||||
_qualifier = qualifier;
|
||||
_name = name;
|
||||
this.Qualifier = Qualifier;
|
||||
this.Name = Name;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_qualifier.Print(writer);
|
||||
writer.Write("::");
|
||||
_name.Print(writer);
|
||||
Qualifier.Print(Writer);
|
||||
Writer.Write("::");
|
||||
Name.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using System.IO;
|
|||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public enum Cv
|
||||
public enum CV
|
||||
{
|
||||
None,
|
||||
Const,
|
||||
|
@ -17,41 +17,41 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
LValue
|
||||
}
|
||||
|
||||
public class CvType : ParentNode
|
||||
public class CVType : ParentNode
|
||||
{
|
||||
public Cv Qualifier;
|
||||
public CV Qualifier;
|
||||
|
||||
public CvType(Cv qualifier, BaseNode child) : base(NodeType.CvQualifierType, child)
|
||||
public CVType(CV Qualifier, BaseNode Child) : base(NodeType.CVQualifierType, Child)
|
||||
{
|
||||
Qualifier = qualifier;
|
||||
this.Qualifier = Qualifier;
|
||||
}
|
||||
|
||||
public void PrintQualifier(TextWriter writer)
|
||||
public void PrintQualifier(TextWriter Writer)
|
||||
{
|
||||
if ((Qualifier & Cv.Const) != 0)
|
||||
if ((Qualifier & CV.Const) != 0)
|
||||
{
|
||||
writer.Write(" const");
|
||||
Writer.Write(" const");
|
||||
}
|
||||
|
||||
if ((Qualifier & Cv.Volatile) != 0)
|
||||
if ((Qualifier & CV.Volatile) != 0)
|
||||
{
|
||||
writer.Write(" volatile");
|
||||
Writer.Write(" volatile");
|
||||
}
|
||||
|
||||
if ((Qualifier & Cv.Restricted) != 0)
|
||||
if ((Qualifier & CV.Restricted) != 0)
|
||||
{
|
||||
writer.Write(" restrict");
|
||||
Writer.Write(" restrict");
|
||||
}
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (Child != null)
|
||||
{
|
||||
Child.PrintLeft(writer);
|
||||
Child.PrintLeft(Writer);
|
||||
}
|
||||
|
||||
PrintQualifier(writer);
|
||||
PrintQualifier(Writer);
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
|
@ -59,11 +59,11 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return Child != null && Child.HasRightPart();
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
if (Child != null)
|
||||
{
|
||||
Child.PrintRight(writer);
|
||||
Child.PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,36 +72,36 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public Reference Qualifier;
|
||||
|
||||
public SimpleReferenceType(Reference qualifier, BaseNode child) : base(NodeType.SimpleReferenceType, child)
|
||||
public SimpleReferenceType(Reference Qualifier, BaseNode Child) : base(NodeType.SimpleReferenceType, Child)
|
||||
{
|
||||
Qualifier = qualifier;
|
||||
this.Qualifier = Qualifier;
|
||||
}
|
||||
|
||||
public void PrintQualifier(TextWriter writer)
|
||||
public void PrintQualifier(TextWriter Writer)
|
||||
{
|
||||
if ((Qualifier & Reference.LValue) != 0)
|
||||
{
|
||||
writer.Write("&");
|
||||
Writer.Write("&");
|
||||
}
|
||||
|
||||
if ((Qualifier & Reference.RValue) != 0)
|
||||
{
|
||||
writer.Write("&&");
|
||||
Writer.Write("&&");
|
||||
}
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (Child != null)
|
||||
{
|
||||
Child.PrintLeft(writer);
|
||||
Child.PrintLeft(Writer);
|
||||
}
|
||||
else if (Qualifier != Reference.None)
|
||||
{
|
||||
writer.Write(" ");
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
PrintQualifier(writer);
|
||||
PrintQualifier(Writer);
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
|
@ -109,11 +109,11 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return Child != null && Child.HasRightPart();
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
if (Child != null)
|
||||
{
|
||||
Child.PrintRight(writer);
|
||||
Child.PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,44 +4,44 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ReferenceType : BaseNode
|
||||
{
|
||||
private string _reference;
|
||||
private BaseNode _child;
|
||||
private string Reference;
|
||||
private BaseNode Child;
|
||||
|
||||
public ReferenceType(string reference, BaseNode child) : base(NodeType.ReferenceType)
|
||||
public ReferenceType(string Reference, BaseNode Child) : base(NodeType.ReferenceType)
|
||||
{
|
||||
_reference = reference;
|
||||
_child = child;
|
||||
this.Reference = Reference;
|
||||
this.Child = Child;
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
return _child.HasRightPart();
|
||||
return Child.HasRightPart();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
_child.PrintLeft(writer);
|
||||
Child.PrintLeft(Writer);
|
||||
|
||||
if (_child.IsArray())
|
||||
if (Child.IsArray())
|
||||
{
|
||||
writer.Write(" ");
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
if (_child.IsArray() || _child.HasFunctions())
|
||||
if (Child.IsArray() || Child.HasFunctions())
|
||||
{
|
||||
writer.Write("(");
|
||||
Writer.Write("(");
|
||||
}
|
||||
|
||||
writer.Write(_reference);
|
||||
Writer.Write(Reference);
|
||||
}
|
||||
public override void PrintRight(TextWriter writer)
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
if (_child.IsArray() || _child.HasFunctions())
|
||||
if (Child.IsArray() || Child.HasFunctions())
|
||||
{
|
||||
writer.Write(")");
|
||||
Writer.Write(")");
|
||||
}
|
||||
|
||||
_child.PrintRight(writer);
|
||||
Child.PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,17 +4,17 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class SpecialName : ParentNode
|
||||
{
|
||||
private string _specialValue;
|
||||
private string SpecialValue;
|
||||
|
||||
public SpecialName(string specialValue, BaseNode type) : base(NodeType.SpecialName, type)
|
||||
public SpecialName(string SpecialValue, BaseNode Type) : base(NodeType.SpecialName, Type)
|
||||
{
|
||||
_specialValue = specialValue;
|
||||
this.SpecialValue = SpecialValue;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write(_specialValue);
|
||||
Child.Print(writer);
|
||||
Writer.Write(SpecialValue);
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
String,
|
||||
IStream,
|
||||
OStream,
|
||||
IOStream
|
||||
IOStream,
|
||||
}
|
||||
|
||||
private SpecialType _specialSubstitutionKey;
|
||||
private SpecialType SpecialSubstitutionKey;
|
||||
|
||||
public SpecialSubstitution(SpecialType specialSubstitutionKey) : base(NodeType.SpecialSubstitution)
|
||||
public SpecialSubstitution(SpecialType SpecialSubstitutionKey) : base(NodeType.SpecialSubstitution)
|
||||
{
|
||||
_specialSubstitutionKey = specialSubstitutionKey;
|
||||
this.SpecialSubstitutionKey = SpecialSubstitutionKey;
|
||||
}
|
||||
|
||||
public void SetExtended()
|
||||
|
@ -28,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
|
||||
public override string GetName()
|
||||
{
|
||||
switch (_specialSubstitutionKey)
|
||||
switch (SpecialSubstitutionKey)
|
||||
{
|
||||
case SpecialType.Allocator:
|
||||
return "allocator";
|
||||
|
@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
|
||||
private string GetExtendedName()
|
||||
{
|
||||
switch (_specialSubstitutionKey)
|
||||
switch (SpecialSubstitutionKey)
|
||||
{
|
||||
case SpecialType.Allocator:
|
||||
return "std::allocator";
|
||||
|
@ -73,16 +73,16 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
return null;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (Type == NodeType.ExpandedSpecialSubstitution)
|
||||
{
|
||||
writer.Write(GetExtendedName());
|
||||
Writer.Write(GetExtendedName());
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write("std::");
|
||||
writer.Write(GetName());
|
||||
Writer.Write("std::");
|
||||
Writer.Write(GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class StdQualifiedName : ParentNode
|
||||
{
|
||||
public StdQualifiedName(BaseNode child) : base(NodeType.StdQualifiedName, child) { }
|
||||
public StdQualifiedName(BaseNode Child) : base(NodeType.StdQualifiedName, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("std::");
|
||||
Child.Print(writer);
|
||||
Writer.Write("std::");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,22 +5,22 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class TemplateArguments : NodeArray
|
||||
{
|
||||
public TemplateArguments(List<BaseNode> nodes) : base(nodes, NodeType.TemplateArguments) { }
|
||||
public TemplateArguments(List<BaseNode> Nodes) : base(Nodes, NodeType.TemplateArguments) { }
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
string Params = string.Join<BaseNode>(", ", Nodes.ToArray());
|
||||
|
||||
writer.Write("<");
|
||||
Writer.Write("<");
|
||||
|
||||
writer.Write(Params);
|
||||
Writer.Write(Params);
|
||||
|
||||
if (Params.EndsWith(">"))
|
||||
{
|
||||
writer.Write(" ");
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
writer.Write(">");
|
||||
Writer.Write(">");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,17 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
public class ThrowExpression : BaseNode
|
||||
{
|
||||
private BaseNode _expression;
|
||||
private BaseNode Expression;
|
||||
|
||||
public ThrowExpression(BaseNode expression) : base(NodeType.ThrowExpression)
|
||||
public ThrowExpression(BaseNode Expression) : base(NodeType.ThrowExpression)
|
||||
{
|
||||
_expression = expression;
|
||||
this.Expression = Expression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
writer.Write("throw ");
|
||||
_expression.Print(writer);
|
||||
Writer.Write("throw ");
|
||||
Expression.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -2,9 +2,9 @@ namespace Ryujinx.HLE.HOS
|
|||
{
|
||||
static class ErrorCode
|
||||
{
|
||||
public static uint MakeError(ErrorModule module, int code)
|
||||
public static uint MakeError(ErrorModule Module, int Code)
|
||||
{
|
||||
return (uint)module | ((uint)code << 9);
|
||||
return (uint)Module | ((uint)Code << 9);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,18 +8,18 @@ namespace Ryujinx.HLE.HOS
|
|||
Htcs = 4,
|
||||
Ncm = 5,
|
||||
Dd = 6,
|
||||
DebugMonitor = 7,
|
||||
Debug_Monitor = 7,
|
||||
Lr = 8,
|
||||
Loader = 9,
|
||||
IpcCommandInterface = 10,
|
||||
Ipc = 11,
|
||||
IPC_Command_Interface = 10,
|
||||
IPC = 11,
|
||||
Pm = 15,
|
||||
Ns = 16,
|
||||
Socket = 17,
|
||||
Htc = 18,
|
||||
NcmContent = 20,
|
||||
Ncm_Content = 20,
|
||||
Sm = 21,
|
||||
RoUserland = 22,
|
||||
RO_Userland = 22,
|
||||
SdMmc = 24,
|
||||
Ovln = 25,
|
||||
Spl = 26,
|
||||
|
@ -41,13 +41,13 @@ namespace Ryujinx.HLE.HOS
|
|||
Pcie = 120,
|
||||
Friends = 121,
|
||||
Bcat = 122,
|
||||
Ssl = 123,
|
||||
SSL = 123,
|
||||
Account = 124,
|
||||
News = 125,
|
||||
Mii = 126,
|
||||
Nfc = 127,
|
||||
Am = 128,
|
||||
PlayReport = 129,
|
||||
Play_Report = 129,
|
||||
Ahid = 130,
|
||||
Qlaunch = 132,
|
||||
Pcv = 133,
|
||||
|
@ -64,23 +64,23 @@ namespace Ryujinx.HLE.HOS
|
|||
Ec = 144,
|
||||
ETicket = 145,
|
||||
Ngc = 146,
|
||||
ErrorReport = 147,
|
||||
Error_Report = 147,
|
||||
Apm = 148,
|
||||
Profiler = 150,
|
||||
ErrorUpload = 151,
|
||||
Error_Upload = 151,
|
||||
Audio = 153,
|
||||
Npns = 154,
|
||||
NpnsHttpStream = 155,
|
||||
Npns_Http_Stream = 155,
|
||||
Arp = 157,
|
||||
Swkbd = 158,
|
||||
Boot = 159,
|
||||
NfcMifare = 161,
|
||||
UserlandAssert = 162,
|
||||
Nfc_Mifare = 161,
|
||||
Userland_Assert = 162,
|
||||
Fatal = 163,
|
||||
NimShop = 164,
|
||||
Nim_Shop = 164,
|
||||
Spsm = 165,
|
||||
Bgtc = 167,
|
||||
UserlandCrash = 168,
|
||||
Userland_Crash = 168,
|
||||
SRepo = 180,
|
||||
Dauth = 181,
|
||||
Hid = 202,
|
||||
|
@ -92,10 +92,10 @@ namespace Ryujinx.HLE.HOS
|
|||
Web = 210,
|
||||
Grc = 212,
|
||||
Migration = 216,
|
||||
MigrationLdcServer = 217,
|
||||
GeneralWebApplet = 800,
|
||||
WifiWebAuthApplet = 809,
|
||||
WhitelistedApplet = 810,
|
||||
Migration_Ldc_Server = 217,
|
||||
General_Web_Applet = 800,
|
||||
Wifi_Web_Auth_Applet = 809,
|
||||
Whitelisted_Applet = 810,
|
||||
ShopN = 811
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,116 +13,116 @@ namespace Ryujinx.HLE.HOS.Font
|
|||
{
|
||||
class SharedFontManager
|
||||
{
|
||||
private Switch _device;
|
||||
private Switch Device;
|
||||
|
||||
private long _physicalAddress;
|
||||
private long PhysicalAddress;
|
||||
|
||||
private string _fontsPath;
|
||||
private string FontsPath;
|
||||
|
||||
private struct FontInfo
|
||||
{
|
||||
public int Offset;
|
||||
public int Size;
|
||||
|
||||
public FontInfo(int offset, int size)
|
||||
public FontInfo(int Offset, int Size)
|
||||
{
|
||||
Offset = offset;
|
||||
Size = size;
|
||||
this.Offset = Offset;
|
||||
this.Size = Size;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<SharedFontType, FontInfo> _fontData;
|
||||
private Dictionary<SharedFontType, FontInfo> FontData;
|
||||
|
||||
public SharedFontManager(Switch device, long physicalAddress)
|
||||
public SharedFontManager(Switch Device, long PhysicalAddress)
|
||||
{
|
||||
_physicalAddress = physicalAddress;
|
||||
this.PhysicalAddress = PhysicalAddress;
|
||||
|
||||
_device = device;
|
||||
this.Device = Device;
|
||||
|
||||
_fontsPath = Path.Combine(device.FileSystem.GetSystemPath(), "fonts");
|
||||
FontsPath = Path.Combine(Device.FileSystem.GetSystemPath(), "fonts");
|
||||
}
|
||||
|
||||
public void EnsureInitialized(ContentManager contentManager)
|
||||
public void EnsureInitialized(ContentManager ContentManager)
|
||||
{
|
||||
if (_fontData == null)
|
||||
if (FontData == null)
|
||||
{
|
||||
_device.Memory.FillWithZeros(_physicalAddress, Horizon.FontSize);
|
||||
Device.Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize);
|
||||
|
||||
uint fontOffset = 0;
|
||||
uint FontOffset = 0;
|
||||
|
||||
FontInfo CreateFont(string name)
|
||||
FontInfo CreateFont(string Name)
|
||||
{
|
||||
if (contentManager.TryGetFontTitle(name, out long fontTitle))
|
||||
if (ContentManager.TryGetFontTitle(Name, out long FontTitle))
|
||||
{
|
||||
string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, ContentType.Data);
|
||||
string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath);
|
||||
string ContentPath = ContentManager.GetInstalledContentPath(FontTitle, StorageId.NandSystem, ContentType.Data);
|
||||
string FontPath = Device.FileSystem.SwitchPathToSystemPath(ContentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(fontPath))
|
||||
if (!string.IsNullOrWhiteSpace(FontPath))
|
||||
{
|
||||
int fileIndex = 0;
|
||||
int FileIndex = 0;
|
||||
|
||||
//Use second file in Chinese Font title for standard
|
||||
if(name == "FontChineseSimplified")
|
||||
if(Name == "FontChineseSimplified")
|
||||
{
|
||||
fileIndex = 1;
|
||||
FileIndex = 1;
|
||||
}
|
||||
|
||||
FileStream ncaFileStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read);
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFileStream, false);
|
||||
NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
Romfs romfs = new Romfs(nca.OpenSection(romfsSection.SectionNum, false, _device.System.FsIntegrityCheckLevel));
|
||||
Stream fontFile = romfs.OpenFile(romfs.Files[fileIndex]);
|
||||
FileStream NcaFileStream = new FileStream(FontPath, FileMode.Open, FileAccess.Read);
|
||||
Nca Nca = new Nca(Device.System.KeySet, NcaFileStream, false);
|
||||
NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
Romfs Romfs = new Romfs(Nca.OpenSection(RomfsSection.SectionNum, false, Device.System.FsIntegrityCheckLevel));
|
||||
Stream FontFile = Romfs.OpenFile(Romfs.Files[FileIndex]);
|
||||
|
||||
byte[] data = DecryptFont(fontFile);
|
||||
byte[] Data = DecryptFont(FontFile);
|
||||
|
||||
FontInfo info = new FontInfo((int)fontOffset, data.Length);
|
||||
FontInfo Info = new FontInfo((int)FontOffset, Data.Length);
|
||||
|
||||
WriteMagicAndSize(_physicalAddress + fontOffset, data.Length);
|
||||
WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);
|
||||
|
||||
fontOffset += 8;
|
||||
FontOffset += 8;
|
||||
|
||||
uint start = fontOffset;
|
||||
uint Start = FontOffset;
|
||||
|
||||
for (; fontOffset - start < data.Length; fontOffset++)
|
||||
for (; FontOffset - Start < Data.Length; FontOffset++)
|
||||
{
|
||||
_device.Memory.WriteByte(_physicalAddress + fontOffset, data[fontOffset - start]);
|
||||
Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
|
||||
}
|
||||
|
||||
ncaFileStream.Dispose();
|
||||
nca.Dispose();
|
||||
NcaFileStream.Dispose();
|
||||
Nca.Dispose();
|
||||
|
||||
return info;
|
||||
return Info;
|
||||
}
|
||||
}
|
||||
|
||||
string fontFilePath = Path.Combine(_fontsPath, name + ".ttf");
|
||||
string FontFilePath = Path.Combine(FontsPath, Name + ".ttf");
|
||||
|
||||
if (File.Exists(fontFilePath))
|
||||
if (File.Exists(FontFilePath))
|
||||
{
|
||||
byte[] data = File.ReadAllBytes(fontFilePath);
|
||||
byte[] Data = File.ReadAllBytes(FontFilePath);
|
||||
|
||||
FontInfo info = new FontInfo((int)fontOffset, data.Length);
|
||||
FontInfo Info = new FontInfo((int)FontOffset, Data.Length);
|
||||
|
||||
WriteMagicAndSize(_physicalAddress + fontOffset, data.Length);
|
||||
WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);
|
||||
|
||||
fontOffset += 8;
|
||||
FontOffset += 8;
|
||||
|
||||
uint start = fontOffset;
|
||||
uint Start = FontOffset;
|
||||
|
||||
for (; fontOffset - start < data.Length; fontOffset++)
|
||||
for (; FontOffset - Start < Data.Length; FontOffset++)
|
||||
{
|
||||
_device.Memory.WriteByte(_physicalAddress + fontOffset, data[fontOffset - start]);
|
||||
Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
|
||||
}
|
||||
|
||||
return info;
|
||||
return Info;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidSystemResourceException($"Font \"{name}.ttf\" not found. Please provide it in \"{_fontsPath}\".");
|
||||
throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\".");
|
||||
}
|
||||
}
|
||||
|
||||
_fontData = new Dictionary<SharedFontType, FontInfo>
|
||||
FontData = new Dictionary<SharedFontType, FontInfo>()
|
||||
{
|
||||
{ SharedFontType.JapanUsEurope, CreateFont("FontStandard") },
|
||||
{ SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") },
|
||||
|
@ -132,39 +132,39 @@ namespace Ryujinx.HLE.HOS.Font
|
|||
{ SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") }
|
||||
};
|
||||
|
||||
if (fontOffset > Horizon.FontSize)
|
||||
if (FontOffset > Horizon.FontSize)
|
||||
{
|
||||
throw new InvalidSystemResourceException(
|
||||
$"The sum of all fonts size exceed the shared memory size. " +
|
||||
$"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " +
|
||||
$"(actual size: {fontOffset} bytes).");
|
||||
$"(actual size: {FontOffset} bytes).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteMagicAndSize(long position, int size)
|
||||
private void WriteMagicAndSize(long Position, int Size)
|
||||
{
|
||||
const int decMagic = 0x18029a7f;
|
||||
const int key = 0x49621806;
|
||||
const int DecMagic = 0x18029a7f;
|
||||
const int Key = 0x49621806;
|
||||
|
||||
int encryptedSize = EndianSwap.Swap32(size ^ key);
|
||||
int EncryptedSize = EndianSwap.Swap32(Size ^ Key);
|
||||
|
||||
_device.Memory.WriteInt32(position + 0, decMagic);
|
||||
_device.Memory.WriteInt32(position + 4, encryptedSize);
|
||||
Device.Memory.WriteInt32(Position + 0, DecMagic);
|
||||
Device.Memory.WriteInt32(Position + 4, EncryptedSize);
|
||||
}
|
||||
|
||||
public int GetFontSize(SharedFontType fontType)
|
||||
public int GetFontSize(SharedFontType FontType)
|
||||
{
|
||||
EnsureInitialized(_device.System.ContentManager);
|
||||
EnsureInitialized(Device.System.ContentManager);
|
||||
|
||||
return _fontData[fontType].Size;
|
||||
return FontData[FontType].Size;
|
||||
}
|
||||
|
||||
public int GetSharedMemoryAddressOffset(SharedFontType fontType)
|
||||
public int GetSharedMemoryAddressOffset(SharedFontType FontType)
|
||||
{
|
||||
EnsureInitialized(_device.System.ContentManager);
|
||||
EnsureInitialized(Device.System.ContentManager);
|
||||
|
||||
return _fontData[fontType].Offset + 8;
|
||||
return FontData[FontType].Offset + 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,62 +6,62 @@ namespace Ryujinx.HLE.HOS
|
|||
{
|
||||
class GlobalStateTable
|
||||
{
|
||||
private ConcurrentDictionary<KProcess, IdDictionary> _dictByProcess;
|
||||
private ConcurrentDictionary<KProcess, IdDictionary> DictByProcess;
|
||||
|
||||
public GlobalStateTable()
|
||||
{
|
||||
_dictByProcess = new ConcurrentDictionary<KProcess, IdDictionary>();
|
||||
DictByProcess = new ConcurrentDictionary<KProcess, IdDictionary>();
|
||||
}
|
||||
|
||||
public bool Add(KProcess process, int id, object data)
|
||||
public bool Add(KProcess Process, int Id, object Data)
|
||||
{
|
||||
IdDictionary dict = _dictByProcess.GetOrAdd(process, (key) => new IdDictionary());
|
||||
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
|
||||
|
||||
return dict.Add(id, data);
|
||||
return Dict.Add(Id, Data);
|
||||
}
|
||||
|
||||
public int Add(KProcess process, object data)
|
||||
public int Add(KProcess Process, object Data)
|
||||
{
|
||||
IdDictionary dict = _dictByProcess.GetOrAdd(process, (key) => new IdDictionary());
|
||||
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
|
||||
|
||||
return dict.Add(data);
|
||||
return Dict.Add(Data);
|
||||
}
|
||||
|
||||
public object GetData(KProcess process, int id)
|
||||
public object GetData(KProcess Process, int Id)
|
||||
{
|
||||
if (_dictByProcess.TryGetValue(process, out IdDictionary dict))
|
||||
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.GetData(id);
|
||||
return Dict.GetData(Id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public T GetData<T>(KProcess process, int id)
|
||||
public T GetData<T>(KProcess Process, int Id)
|
||||
{
|
||||
if (_dictByProcess.TryGetValue(process, out IdDictionary dict))
|
||||
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.GetData<T>(id);
|
||||
return Dict.GetData<T>(Id);
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public object Delete(KProcess process, int id)
|
||||
public object Delete(KProcess Process, int Id)
|
||||
{
|
||||
if (_dictByProcess.TryGetValue(process, out IdDictionary dict))
|
||||
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.Delete(id);
|
||||
return Dict.Delete(Id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ICollection<object> DeleteProcess(KProcess process)
|
||||
public ICollection<object> DeleteProcess(KProcess Process)
|
||||
{
|
||||
if (_dictByProcess.TryRemove(process, out IdDictionary dict))
|
||||
if (DictByProcess.TryRemove(Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.Clear();
|
||||
return Dict.Clear();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -8,70 +8,70 @@ namespace Ryujinx.HLE.HOS
|
|||
public const string TemporaryNroSuffix = ".ryu_tmp.nro";
|
||||
|
||||
//http://switchbrew.org/index.php?title=Homebrew_ABI
|
||||
public static void WriteHbAbiData(MemoryManager memory, long position, int mainThreadHandle, string switchPath)
|
||||
public static void WriteHbAbiData(MemoryManager Memory, long Position, int MainThreadHandle, string SwitchPath)
|
||||
{
|
||||
//MainThreadHandle.
|
||||
WriteConfigEntry(memory, ref position, 1, 0, mainThreadHandle);
|
||||
WriteConfigEntry(Memory, ref Position, 1, 0, MainThreadHandle);
|
||||
|
||||
//NextLoadPath.
|
||||
WriteConfigEntry(memory, ref position, 2, 0, position + 0x200, position + 0x400);
|
||||
WriteConfigEntry(Memory, ref Position, 2, 0, Position + 0x200, Position + 0x400);
|
||||
|
||||
//Argv.
|
||||
long argvPosition = position + 0xC00;
|
||||
long ArgvPosition = Position + 0xC00;
|
||||
|
||||
memory.WriteBytes(argvPosition, Encoding.ASCII.GetBytes(switchPath + "\0"));
|
||||
Memory.WriteBytes(ArgvPosition, Encoding.ASCII.GetBytes(SwitchPath + "\0"));
|
||||
|
||||
WriteConfigEntry(memory, ref position, 5, 0, 0, argvPosition);
|
||||
WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition);
|
||||
|
||||
//AppletType.
|
||||
WriteConfigEntry(memory, ref position, 7);
|
||||
WriteConfigEntry(Memory, ref Position, 7);
|
||||
|
||||
//EndOfList.
|
||||
WriteConfigEntry(memory, ref position, 0);
|
||||
WriteConfigEntry(Memory, ref Position, 0);
|
||||
}
|
||||
|
||||
private static void WriteConfigEntry(
|
||||
MemoryManager memory,
|
||||
ref long position,
|
||||
int key,
|
||||
int flags = 0,
|
||||
long value0 = 0,
|
||||
long value1 = 0)
|
||||
MemoryManager Memory,
|
||||
ref long Position,
|
||||
int Key,
|
||||
int Flags = 0,
|
||||
long Value0 = 0,
|
||||
long Value1 = 0)
|
||||
{
|
||||
memory.WriteInt32(position + 0x00, key);
|
||||
memory.WriteInt32(position + 0x04, flags);
|
||||
memory.WriteInt64(position + 0x08, value0);
|
||||
memory.WriteInt64(position + 0x10, value1);
|
||||
Memory.WriteInt32(Position + 0x00, Key);
|
||||
Memory.WriteInt32(Position + 0x04, Flags);
|
||||
Memory.WriteInt64(Position + 0x08, Value0);
|
||||
Memory.WriteInt64(Position + 0x10, Value1);
|
||||
|
||||
position += 0x18;
|
||||
Position += 0x18;
|
||||
}
|
||||
|
||||
public static string ReadHbAbiNextLoadPath(MemoryManager memory, long position)
|
||||
public static string ReadHbAbiNextLoadPath(MemoryManager Memory, long Position)
|
||||
{
|
||||
string fileName = null;
|
||||
string FileName = null;
|
||||
|
||||
while (true)
|
||||
{
|
||||
long key = memory.ReadInt64(position);
|
||||
long Key = Memory.ReadInt64(Position);
|
||||
|
||||
if (key == 2)
|
||||
if (Key == 2)
|
||||
{
|
||||
long value0 = memory.ReadInt64(position + 0x08);
|
||||
long value1 = memory.ReadInt64(position + 0x10);
|
||||
long Value0 = Memory.ReadInt64(Position + 0x08);
|
||||
long Value1 = Memory.ReadInt64(Position + 0x10);
|
||||
|
||||
fileName = MemoryHelper.ReadAsciiString(memory, value0, value1 - value0);
|
||||
FileName = MemoryHelper.ReadAsciiString(Memory, Value0, Value1 - Value0);
|
||||
|
||||
break;
|
||||
}
|
||||
else if (key == 0)
|
||||
else if (Key == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
position += 0x18;
|
||||
Position += 0x18;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
return FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,34 +35,34 @@ namespace Ryujinx.HLE.HOS
|
|||
internal long PrivilegedProcessLowestId { get; set; } = 1;
|
||||
internal long PrivilegedProcessHighestId { get; set; } = 8;
|
||||
|
||||
internal Switch Device { get; }
|
||||
internal Switch Device { get; private set; }
|
||||
|
||||
public SystemStateMgr State { get; }
|
||||
public SystemStateMgr State { get; private set; }
|
||||
|
||||
internal bool KernelInitialized { get; }
|
||||
internal bool KernelInitialized { get; private set; }
|
||||
|
||||
internal KResourceLimit ResourceLimit { get; }
|
||||
internal KResourceLimit ResourceLimit { get; private set; }
|
||||
|
||||
internal KMemoryRegionManager[] MemoryRegions { get; }
|
||||
internal KMemoryRegionManager[] MemoryRegions { get; private set; }
|
||||
|
||||
internal KMemoryBlockAllocator LargeMemoryBlockAllocator { get; }
|
||||
internal KMemoryBlockAllocator SmallMemoryBlockAllocator { get; }
|
||||
internal KMemoryBlockAllocator LargeMemoryBlockAllocator { get; private set; }
|
||||
internal KMemoryBlockAllocator SmallMemoryBlockAllocator { get; private set; }
|
||||
|
||||
internal KSlabHeap UserSlabHeapPages { get; }
|
||||
internal KSlabHeap UserSlabHeapPages { get; private set; }
|
||||
|
||||
internal KCriticalSection CriticalSection { get; }
|
||||
internal KCriticalSection CriticalSection { get; private set; }
|
||||
|
||||
internal KScheduler Scheduler { get; }
|
||||
internal KScheduler Scheduler { get; private set; }
|
||||
|
||||
internal KTimeManager TimeManager { get; }
|
||||
internal KTimeManager TimeManager { get; private set; }
|
||||
|
||||
internal KSynchronization Synchronization { get; }
|
||||
internal KSynchronization Synchronization { get; private set; }
|
||||
|
||||
internal KContextIdManager ContextIdManager { get; }
|
||||
internal KContextIdManager ContextIdManager { get; private set; }
|
||||
|
||||
private long _kipId;
|
||||
private long _processId;
|
||||
private long _threadUid;
|
||||
private long KipId;
|
||||
private long ProcessId;
|
||||
private long ThreadUid;
|
||||
|
||||
internal CountdownEvent ThreadCounter;
|
||||
|
||||
|
@ -72,20 +72,20 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
internal bool EnableVersionChecks { get; private set; }
|
||||
|
||||
internal AppletStateMgr AppletState { get; }
|
||||
internal AppletStateMgr AppletState { get; private set; }
|
||||
|
||||
internal KSharedMemory HidSharedMem { get; }
|
||||
internal KSharedMemory FontSharedMem { get; }
|
||||
internal KSharedMemory HidSharedMem { get; private set; }
|
||||
internal KSharedMemory FontSharedMem { get; private set; }
|
||||
|
||||
internal SharedFontManager Font { get; }
|
||||
internal SharedFontManager Font { get; private set; }
|
||||
|
||||
internal ContentManager ContentManager { get; }
|
||||
internal ContentManager ContentManager { get; private set; }
|
||||
|
||||
internal KEvent VsyncEvent { get; }
|
||||
internal KEvent VsyncEvent { get; private set; }
|
||||
|
||||
internal Keyset KeySet { get; private set; }
|
||||
|
||||
private bool _hasStarted;
|
||||
private bool HasStarted;
|
||||
|
||||
public Nacp ControlData { get; set; }
|
||||
|
||||
|
@ -93,11 +93,11 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public IntegrityCheckLevel FsIntegrityCheckLevel { get; set; }
|
||||
|
||||
internal long HidBaseAddress { get; }
|
||||
internal long HidBaseAddress { get; private set; }
|
||||
|
||||
public Horizon(Switch device)
|
||||
public Horizon(Switch Device)
|
||||
{
|
||||
Device = device;
|
||||
this.Device = Device;
|
||||
|
||||
State = new SystemStateMgr();
|
||||
|
||||
|
@ -125,8 +125,8 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
ContextIdManager = new KContextIdManager();
|
||||
|
||||
_kipId = InitialKipId;
|
||||
_processId = InitialProcessId;
|
||||
KipId = InitialKipId;
|
||||
ProcessId = InitialProcessId;
|
||||
|
||||
Scheduler.StartAutoPreemptionThread();
|
||||
|
||||
|
@ -140,90 +140,90 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
//Note: This is not really correct, but with HLE of services, the only memory
|
||||
//region used that is used is Application, so we can use the other ones for anything.
|
||||
KMemoryRegionManager region = MemoryRegions[(int)MemoryRegion.NvServices];
|
||||
KMemoryRegionManager Region = MemoryRegions[(int)MemoryRegion.NvServices];
|
||||
|
||||
ulong hidPa = region.Address;
|
||||
ulong fontPa = region.Address + HidSize;
|
||||
ulong HidPa = Region.Address;
|
||||
ulong FontPa = Region.Address + HidSize;
|
||||
|
||||
HidBaseAddress = (long)(hidPa - DramMemoryMap.DramBase);
|
||||
HidBaseAddress = (long)(HidPa - DramMemoryMap.DramBase);
|
||||
|
||||
KPageList hidPageList = new KPageList();
|
||||
KPageList fontPageList = new KPageList();
|
||||
KPageList HidPageList = new KPageList();
|
||||
KPageList FontPageList = new KPageList();
|
||||
|
||||
hidPageList .AddRange(hidPa, HidSize / KMemoryManager.PageSize);
|
||||
fontPageList.AddRange(fontPa, FontSize / KMemoryManager.PageSize);
|
||||
HidPageList .AddRange(HidPa, HidSize / KMemoryManager.PageSize);
|
||||
FontPageList.AddRange(FontPa, FontSize / KMemoryManager.PageSize);
|
||||
|
||||
HidSharedMem = new KSharedMemory(hidPageList, 0, 0, MemoryPermission.Read);
|
||||
FontSharedMem = new KSharedMemory(fontPageList, 0, 0, MemoryPermission.Read);
|
||||
HidSharedMem = new KSharedMemory(HidPageList, 0, 0, MemoryPermission.Read);
|
||||
FontSharedMem = new KSharedMemory(FontPageList, 0, 0, MemoryPermission.Read);
|
||||
|
||||
AppletState = new AppletStateMgr(this);
|
||||
|
||||
AppletState.SetFocus(true);
|
||||
|
||||
Font = new SharedFontManager(device, (long)(fontPa - DramMemoryMap.DramBase));
|
||||
Font = new SharedFontManager(Device, (long)(FontPa - DramMemoryMap.DramBase));
|
||||
|
||||
VsyncEvent = new KEvent(this);
|
||||
|
||||
LoadKeySet();
|
||||
|
||||
ContentManager = new ContentManager(device);
|
||||
ContentManager = new ContentManager(Device);
|
||||
}
|
||||
|
||||
public void LoadCart(string exeFsDir, string romFsFile = null)
|
||||
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
||||
{
|
||||
if (romFsFile != null)
|
||||
if (RomFsFile != null)
|
||||
{
|
||||
Device.FileSystem.LoadRomFs(romFsFile);
|
||||
Device.FileSystem.LoadRomFs(RomFsFile);
|
||||
}
|
||||
|
||||
string npdmFileName = Path.Combine(exeFsDir, "main.npdm");
|
||||
string NpdmFileName = Path.Combine(ExeFsDir, "main.npdm");
|
||||
|
||||
Npdm metaData = null;
|
||||
Npdm MetaData = null;
|
||||
|
||||
if (File.Exists(npdmFileName))
|
||||
if (File.Exists(NpdmFileName))
|
||||
{
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
|
||||
|
||||
using (FileStream input = new FileStream(npdmFileName, FileMode.Open))
|
||||
using (FileStream Input = new FileStream(NpdmFileName, FileMode.Open))
|
||||
{
|
||||
metaData = new Npdm(input);
|
||||
MetaData = new Npdm(Input);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
|
||||
|
||||
metaData = GetDefaultNpdm();
|
||||
MetaData = GetDefaultNpdm();
|
||||
}
|
||||
|
||||
List<IExecutable> staticObjects = new List<IExecutable>();
|
||||
List<IExecutable> StaticObjects = new List<IExecutable>();
|
||||
|
||||
void LoadNso(string searchPattern)
|
||||
void LoadNso(string SearchPattern)
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(exeFsDir, searchPattern))
|
||||
foreach (string File in Directory.GetFiles(ExeFsDir, SearchPattern))
|
||||
{
|
||||
if (Path.GetExtension(file) != string.Empty)
|
||||
if (Path.GetExtension(File) != string.Empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(file)}...");
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}...");
|
||||
|
||||
using (FileStream input = new FileStream(file, FileMode.Open))
|
||||
using (FileStream Input = new FileStream(File, FileMode.Open))
|
||||
{
|
||||
NxStaticObject staticObject = new NxStaticObject(input);
|
||||
NxStaticObject StaticObject = new NxStaticObject(Input);
|
||||
|
||||
staticObjects.Add(staticObject);
|
||||
StaticObjects.Add(StaticObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!metaData.Is64Bits)
|
||||
if (!MetaData.Is64Bits)
|
||||
{
|
||||
throw new NotImplementedException("32-bit titles are unsupported!");
|
||||
}
|
||||
|
||||
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
||||
CurrentTitle = MetaData.ACI0.TitleId.ToString("x16");
|
||||
|
||||
LoadNso("rtld");
|
||||
LoadNso("main");
|
||||
|
@ -232,18 +232,18 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
ContentManager.LoadEntries();
|
||||
|
||||
ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray());
|
||||
ProgramLoader.LoadStaticObjects(this, MetaData, StaticObjects.ToArray());
|
||||
}
|
||||
|
||||
public void LoadXci(string xciFile)
|
||||
public void LoadXci(string XciFile)
|
||||
{
|
||||
FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read);
|
||||
FileStream File = new FileStream(XciFile, FileMode.Open, FileAccess.Read);
|
||||
|
||||
Xci xci = new Xci(KeySet, file);
|
||||
Xci Xci = new Xci(KeySet, File);
|
||||
|
||||
(Nca mainNca, Nca controlNca) = GetXciGameData(xci);
|
||||
(Nca MainNca, Nca ControlNca) = GetXciGameData(Xci);
|
||||
|
||||
if (mainNca == null)
|
||||
if (MainNca == null)
|
||||
{
|
||||
Logger.PrintError(LogClass.Loader, "Unable to load XCI");
|
||||
|
||||
|
@ -252,23 +252,23 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
ContentManager.LoadEntries();
|
||||
|
||||
LoadNca(mainNca, controlNca);
|
||||
LoadNca(MainNca, ControlNca);
|
||||
}
|
||||
|
||||
private (Nca Main, Nca Control) GetXciGameData(Xci xci)
|
||||
private (Nca Main, Nca Control) GetXciGameData(Xci Xci)
|
||||
{
|
||||
if (xci.SecurePartition == null)
|
||||
if (Xci.SecurePartition == null)
|
||||
{
|
||||
throw new InvalidDataException("Could not find XCI secure partition");
|
||||
}
|
||||
|
||||
Nca mainNca = null;
|
||||
Nca patchNca = null;
|
||||
Nca controlNca = null;
|
||||
Nca MainNca = null;
|
||||
Nca PatchNca = null;
|
||||
Nca ControlNca = null;
|
||||
|
||||
foreach (PfsFileEntry ticketEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".tik")))
|
||||
foreach (PfsFileEntry TicketEntry in Xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".tik")))
|
||||
{
|
||||
Ticket ticket = new Ticket(xci.SecurePartition.OpenFile(ticketEntry));
|
||||
Ticket ticket = new Ticket(Xci.SecurePartition.OpenFile(TicketEntry));
|
||||
|
||||
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId))
|
||||
{
|
||||
|
@ -276,107 +276,107 @@ namespace Ryujinx.HLE.HOS
|
|||
}
|
||||
}
|
||||
|
||||
foreach (PfsFileEntry fileEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
|
||||
foreach (PfsFileEntry FileEntry in Xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
|
||||
{
|
||||
Stream ncaStream = xci.SecurePartition.OpenFile(fileEntry);
|
||||
Stream NcaStream = Xci.SecurePartition.OpenFile(FileEntry);
|
||||
|
||||
Nca nca = new Nca(KeySet, ncaStream, true);
|
||||
Nca Nca = new Nca(KeySet, NcaStream, true);
|
||||
|
||||
if (nca.Header.ContentType == ContentType.Program)
|
||||
if (Nca.Header.ContentType == ContentType.Program)
|
||||
{
|
||||
if (nca.Sections.Any(x => x?.Type == SectionType.Romfs))
|
||||
if (Nca.Sections.Any(x => x?.Type == SectionType.Romfs))
|
||||
{
|
||||
mainNca = nca;
|
||||
MainNca = Nca;
|
||||
}
|
||||
else if (nca.Sections.Any(x => x?.Type == SectionType.Bktr))
|
||||
else if (Nca.Sections.Any(x => x?.Type == SectionType.Bktr))
|
||||
{
|
||||
patchNca = nca;
|
||||
PatchNca = Nca;
|
||||
}
|
||||
}
|
||||
else if (nca.Header.ContentType == ContentType.Control)
|
||||
else if (Nca.Header.ContentType == ContentType.Control)
|
||||
{
|
||||
controlNca = nca;
|
||||
ControlNca = Nca;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainNca == null)
|
||||
if (MainNca == null)
|
||||
{
|
||||
Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
|
||||
}
|
||||
|
||||
mainNca.SetBaseNca(patchNca);
|
||||
MainNca.SetBaseNca(PatchNca);
|
||||
|
||||
if (controlNca != null)
|
||||
if (ControlNca != null)
|
||||
{
|
||||
ReadControlData(controlNca);
|
||||
ReadControlData(ControlNca);
|
||||
}
|
||||
|
||||
if (patchNca != null)
|
||||
if (PatchNca != null)
|
||||
{
|
||||
patchNca.SetBaseNca(mainNca);
|
||||
PatchNca.SetBaseNca(MainNca);
|
||||
|
||||
return (patchNca, controlNca);
|
||||
return (PatchNca, ControlNca);
|
||||
}
|
||||
|
||||
return (mainNca, controlNca);
|
||||
return (MainNca, ControlNca);
|
||||
}
|
||||
|
||||
public void ReadControlData(Nca controlNca)
|
||||
public void ReadControlData(Nca ControlNca)
|
||||
{
|
||||
Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel));
|
||||
Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false, FsIntegrityCheckLevel));
|
||||
|
||||
byte[] controlFile = controlRomfs.GetFile("/control.nacp");
|
||||
byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");
|
||||
|
||||
BinaryReader reader = new BinaryReader(new MemoryStream(controlFile));
|
||||
BinaryReader Reader = new BinaryReader(new MemoryStream(ControlFile));
|
||||
|
||||
ControlData = new Nacp(reader);
|
||||
ControlData = new Nacp(Reader);
|
||||
}
|
||||
|
||||
public void LoadNca(string ncaFile)
|
||||
public void LoadNca(string NcaFile)
|
||||
{
|
||||
FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
|
||||
FileStream File = new FileStream(NcaFile, FileMode.Open, FileAccess.Read);
|
||||
|
||||
Nca nca = new Nca(KeySet, file, true);
|
||||
Nca Nca = new Nca(KeySet, File, true);
|
||||
|
||||
LoadNca(nca, null);
|
||||
LoadNca(Nca, null);
|
||||
}
|
||||
|
||||
public void LoadNsp(string nspFile)
|
||||
public void LoadNsp(string NspFile)
|
||||
{
|
||||
FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read);
|
||||
FileStream File = new FileStream(NspFile, FileMode.Open, FileAccess.Read);
|
||||
|
||||
Pfs nsp = new Pfs(file);
|
||||
Pfs Nsp = new Pfs(File);
|
||||
|
||||
PfsFileEntry ticketFile = nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
|
||||
// Load title key from the NSP's ticket in case the user doesn't have a title key file
|
||||
if (ticketFile != null)
|
||||
if (TicketFile != null)
|
||||
{
|
||||
Ticket ticket = new Ticket(nsp.OpenFile(ticketFile));
|
||||
Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile));
|
||||
|
||||
KeySet.TitleKeys[ticket.RightsId] = ticket.GetTitleKey(KeySet);
|
||||
KeySet.TitleKeys[Ticket.RightsId] = Ticket.GetTitleKey(KeySet);
|
||||
}
|
||||
|
||||
Nca mainNca = null;
|
||||
Nca controlNca = null;
|
||||
Nca MainNca = null;
|
||||
Nca ControlNca = null;
|
||||
|
||||
foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca")))
|
||||
foreach (PfsFileEntry NcaFile in Nsp.Files.Where(x => x.Name.EndsWith(".nca")))
|
||||
{
|
||||
Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true);
|
||||
Nca Nca = new Nca(KeySet, Nsp.OpenFile(NcaFile), true);
|
||||
|
||||
if (nca.Header.ContentType == ContentType.Program)
|
||||
if (Nca.Header.ContentType == ContentType.Program)
|
||||
{
|
||||
mainNca = nca;
|
||||
MainNca = Nca;
|
||||
}
|
||||
else if (nca.Header.ContentType == ContentType.Control)
|
||||
else if (Nca.Header.ContentType == ContentType.Control)
|
||||
{
|
||||
controlNca = nca;
|
||||
ControlNca = Nca;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainNca != null)
|
||||
if (MainNca != null)
|
||||
{
|
||||
LoadNca(mainNca, controlNca);
|
||||
LoadNca(MainNca, ControlNca);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -384,100 +384,100 @@ namespace Ryujinx.HLE.HOS
|
|||
Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file");
|
||||
}
|
||||
|
||||
public void LoadNca(Nca mainNca, Nca controlNca)
|
||||
public void LoadNca(Nca MainNca, Nca ControlNca)
|
||||
{
|
||||
if (mainNca.Header.ContentType != ContentType.Program)
|
||||
if (MainNca.Header.ContentType != ContentType.Program)
|
||||
{
|
||||
Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Stream romfsStream = mainNca.OpenSection(ProgramPartitionType.Data, false, FsIntegrityCheckLevel);
|
||||
Stream exefsStream = mainNca.OpenSection(ProgramPartitionType.Code, false, FsIntegrityCheckLevel);
|
||||
Stream RomfsStream = MainNca.OpenSection(ProgramPartitionType.Data, false, FsIntegrityCheckLevel);
|
||||
Stream ExefsStream = MainNca.OpenSection(ProgramPartitionType.Code, false, FsIntegrityCheckLevel);
|
||||
|
||||
if (exefsStream == null)
|
||||
if (ExefsStream == null)
|
||||
{
|
||||
Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (romfsStream == null)
|
||||
if (RomfsStream == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
|
||||
}
|
||||
else
|
||||
{
|
||||
Device.FileSystem.SetRomFs(romfsStream);
|
||||
Device.FileSystem.SetRomFs(RomfsStream);
|
||||
}
|
||||
|
||||
Pfs exefs = new Pfs(exefsStream);
|
||||
Pfs Exefs = new Pfs(ExefsStream);
|
||||
|
||||
Npdm metaData = null;
|
||||
Npdm MetaData = null;
|
||||
|
||||
if (exefs.FileExists("main.npdm"))
|
||||
if (Exefs.FileExists("main.npdm"))
|
||||
{
|
||||
Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");
|
||||
|
||||
metaData = new Npdm(exefs.OpenFile("main.npdm"));
|
||||
MetaData = new Npdm(Exefs.OpenFile("main.npdm"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
|
||||
|
||||
metaData = GetDefaultNpdm();
|
||||
MetaData = GetDefaultNpdm();
|
||||
}
|
||||
|
||||
List<IExecutable> staticObjects = new List<IExecutable>();
|
||||
List<IExecutable> StaticObjects = new List<IExecutable>();
|
||||
|
||||
void LoadNso(string filename)
|
||||
void LoadNso(string Filename)
|
||||
{
|
||||
foreach (PfsFileEntry file in exefs.Files.Where(x => x.Name.StartsWith(filename)))
|
||||
foreach (PfsFileEntry File in Exefs.Files.Where(x => x.Name.StartsWith(Filename)))
|
||||
{
|
||||
if (Path.GetExtension(file.Name) != string.Empty)
|
||||
if (Path.GetExtension(File.Name) != string.Empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading {filename}...");
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading {Filename}...");
|
||||
|
||||
NxStaticObject staticObject = new NxStaticObject(exefs.OpenFile(file));
|
||||
NxStaticObject StaticObject = new NxStaticObject(Exefs.OpenFile(File));
|
||||
|
||||
staticObjects.Add(staticObject);
|
||||
StaticObjects.Add(StaticObject);
|
||||
}
|
||||
}
|
||||
|
||||
Nacp ReadControlData()
|
||||
{
|
||||
Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel));
|
||||
Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false, FsIntegrityCheckLevel));
|
||||
|
||||
byte[] controlFile = controlRomfs.GetFile("/control.nacp");
|
||||
byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");
|
||||
|
||||
BinaryReader reader = new BinaryReader(new MemoryStream(controlFile));
|
||||
BinaryReader Reader = new BinaryReader(new MemoryStream(ControlFile));
|
||||
|
||||
Nacp controlData = new Nacp(reader);
|
||||
Nacp ControlData = new Nacp(Reader);
|
||||
|
||||
CurrentTitle = controlData.Languages[(int)State.DesiredTitleLanguage].Title;
|
||||
CurrentTitle = ControlData.Languages[(int)State.DesiredTitleLanguage].Title;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(CurrentTitle))
|
||||
{
|
||||
CurrentTitle = controlData.Languages.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
|
||||
CurrentTitle = ControlData.Languages.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
|
||||
}
|
||||
|
||||
return controlData;
|
||||
return ControlData;
|
||||
}
|
||||
|
||||
if (controlNca != null)
|
||||
if (ControlNca != null)
|
||||
{
|
||||
ReadControlData();
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
||||
CurrentTitle = MetaData.ACI0.TitleId.ToString("x16");
|
||||
}
|
||||
|
||||
if (!metaData.Is64Bits)
|
||||
if (!MetaData.Is64Bits)
|
||||
{
|
||||
throw new NotImplementedException("32-bit titles are not supported!");
|
||||
}
|
||||
|
@ -489,67 +489,67 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
ContentManager.LoadEntries();
|
||||
|
||||
ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray());
|
||||
ProgramLoader.LoadStaticObjects(this, MetaData, StaticObjects.ToArray());
|
||||
}
|
||||
|
||||
public void LoadProgram(string filePath)
|
||||
public void LoadProgram(string FilePath)
|
||||
{
|
||||
Npdm metaData = GetDefaultNpdm();
|
||||
Npdm MetaData = GetDefaultNpdm();
|
||||
|
||||
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
|
||||
bool IsNro = Path.GetExtension(FilePath).ToLower() == ".nro";
|
||||
|
||||
using (FileStream input = new FileStream(filePath, FileMode.Open))
|
||||
using (FileStream Input = new FileStream(FilePath, FileMode.Open))
|
||||
{
|
||||
IExecutable staticObject = isNro
|
||||
? (IExecutable)new NxRelocatableObject(input)
|
||||
: new NxStaticObject(input);
|
||||
IExecutable StaticObject = IsNro
|
||||
? (IExecutable)new NxRelocatableObject(Input)
|
||||
: (IExecutable)new NxStaticObject(Input);
|
||||
|
||||
ProgramLoader.LoadStaticObjects(this, metaData, new IExecutable[] { staticObject });
|
||||
ProgramLoader.LoadStaticObjects(this, MetaData, new IExecutable[] { StaticObject });
|
||||
}
|
||||
}
|
||||
|
||||
private Npdm GetDefaultNpdm()
|
||||
{
|
||||
Assembly asm = Assembly.GetCallingAssembly();
|
||||
Assembly Asm = Assembly.GetCallingAssembly();
|
||||
|
||||
using (Stream npdmStream = asm.GetManifestResourceStream("Ryujinx.HLE.Homebrew.npdm"))
|
||||
using (Stream NpdmStream = Asm.GetManifestResourceStream("Ryujinx.HLE.Homebrew.npdm"))
|
||||
{
|
||||
return new Npdm(npdmStream);
|
||||
return new Npdm(NpdmStream);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadKeySet()
|
||||
{
|
||||
string keyFile = null;
|
||||
string titleKeyFile = null;
|
||||
string consoleKeyFile = null;
|
||||
string KeyFile = null;
|
||||
string TitleKeyFile = null;
|
||||
string ConsoleKeyFile = null;
|
||||
|
||||
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
string Home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
|
||||
LoadSetAtPath(Path.Combine(home, ".switch"));
|
||||
LoadSetAtPath(Path.Combine(Home, ".switch"));
|
||||
LoadSetAtPath(Device.FileSystem.GetSystemPath());
|
||||
|
||||
KeySet = ExternalKeys.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile);
|
||||
KeySet = ExternalKeys.ReadKeyFile(KeyFile, TitleKeyFile, ConsoleKeyFile);
|
||||
|
||||
void LoadSetAtPath(string basePath)
|
||||
void LoadSetAtPath(string BasePath)
|
||||
{
|
||||
string localKeyFile = Path.Combine(basePath, "prod.keys");
|
||||
string localTitleKeyFile = Path.Combine(basePath, "title.keys");
|
||||
string localConsoleKeyFile = Path.Combine(basePath, "console.keys");
|
||||
string LocalKeyFile = Path.Combine(BasePath, "prod.keys");
|
||||
string LocalTitleKeyFile = Path.Combine(BasePath, "title.keys");
|
||||
string LocalConsoleKeyFile = Path.Combine(BasePath, "console.keys");
|
||||
|
||||
if (File.Exists(localKeyFile))
|
||||
if (File.Exists(LocalKeyFile))
|
||||
{
|
||||
keyFile = localKeyFile;
|
||||
KeyFile = LocalKeyFile;
|
||||
}
|
||||
|
||||
if (File.Exists(localTitleKeyFile))
|
||||
if (File.Exists(LocalTitleKeyFile))
|
||||
{
|
||||
titleKeyFile = localTitleKeyFile;
|
||||
TitleKeyFile = LocalTitleKeyFile;
|
||||
}
|
||||
|
||||
if (File.Exists(localConsoleKeyFile))
|
||||
if (File.Exists(LocalConsoleKeyFile))
|
||||
{
|
||||
consoleKeyFile = localConsoleKeyFile;
|
||||
ConsoleKeyFile = LocalConsoleKeyFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -561,22 +561,22 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
internal long GetThreadUid()
|
||||
{
|
||||
return Interlocked.Increment(ref _threadUid) - 1;
|
||||
return Interlocked.Increment(ref ThreadUid) - 1;
|
||||
}
|
||||
|
||||
internal long GetKipId()
|
||||
{
|
||||
return Interlocked.Increment(ref _kipId) - 1;
|
||||
return Interlocked.Increment(ref KipId) - 1;
|
||||
}
|
||||
|
||||
internal long GetProcessId()
|
||||
{
|
||||
return Interlocked.Increment(ref _processId) - 1;
|
||||
return Interlocked.Increment(ref ProcessId) - 1;
|
||||
}
|
||||
|
||||
public void EnableMultiCoreScheduling()
|
||||
{
|
||||
if (!_hasStarted)
|
||||
if (!HasStarted)
|
||||
{
|
||||
Scheduler.MultiCoreScheduling = true;
|
||||
}
|
||||
|
@ -584,7 +584,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public void DisableMultiCoreScheduling()
|
||||
{
|
||||
if (!_hasStarted)
|
||||
if (!HasStarted)
|
||||
{
|
||||
Scheduler.MultiCoreScheduling = false;
|
||||
}
|
||||
|
@ -595,16 +595,16 @@ namespace Ryujinx.HLE.HOS
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (disposing)
|
||||
if (Disposing)
|
||||
{
|
||||
//Force all threads to exit.
|
||||
lock (Processes)
|
||||
{
|
||||
foreach (KProcess process in Processes.Values)
|
||||
foreach (KProcess Process in Processes.Values)
|
||||
{
|
||||
process.StopAllThreads();
|
||||
Process.StopAllThreads();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,56 +6,56 @@ namespace Ryujinx.HLE.HOS
|
|||
{
|
||||
class IdDictionary
|
||||
{
|
||||
private ConcurrentDictionary<int, object> _objs;
|
||||
private ConcurrentDictionary<int, object> Objs;
|
||||
|
||||
public IdDictionary()
|
||||
{
|
||||
_objs = new ConcurrentDictionary<int, object>();
|
||||
Objs = new ConcurrentDictionary<int, object>();
|
||||
}
|
||||
|
||||
public bool Add(int id, object data)
|
||||
public bool Add(int Id, object Data)
|
||||
{
|
||||
return _objs.TryAdd(id, data);
|
||||
return Objs.TryAdd(Id, Data);
|
||||
}
|
||||
|
||||
public int Add(object data)
|
||||
public int Add(object Data)
|
||||
{
|
||||
for (int id = 1; id < int.MaxValue; id++)
|
||||
for (int Id = 1; Id < int.MaxValue; Id++)
|
||||
{
|
||||
if (_objs.TryAdd(id, data))
|
||||
if (Objs.TryAdd(Id, Data))
|
||||
{
|
||||
return id;
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public object GetData(int id)
|
||||
public object GetData(int Id)
|
||||
{
|
||||
if (_objs.TryGetValue(id, out object data))
|
||||
if (Objs.TryGetValue(Id, out object Data))
|
||||
{
|
||||
return data;
|
||||
return Data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public T GetData<T>(int id)
|
||||
public T GetData<T>(int Id)
|
||||
{
|
||||
if (_objs.TryGetValue(id, out object data) && data is T)
|
||||
if (Objs.TryGetValue(Id, out object Data) && Data is T)
|
||||
{
|
||||
return (T)data;
|
||||
return (T)Data;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public object Delete(int id)
|
||||
public object Delete(int Id)
|
||||
{
|
||||
if (_objs.TryRemove(id, out object obj))
|
||||
if (Objs.TryRemove(Id, out object Obj))
|
||||
{
|
||||
return obj;
|
||||
return Obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -63,11 +63,11 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public ICollection<object> Clear()
|
||||
{
|
||||
ICollection<object> values = _objs.Values;
|
||||
ICollection<object> Values = Objs.Values;
|
||||
|
||||
_objs.Clear();
|
||||
Objs.Clear();
|
||||
|
||||
return values;
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,24 +4,24 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
{
|
||||
struct IpcBuffDesc
|
||||
{
|
||||
public long Position { get; }
|
||||
public long Size { get; }
|
||||
public int Flags { get; }
|
||||
public long Position { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
public int Flags { get; private set; }
|
||||
|
||||
public IpcBuffDesc(BinaryReader reader)
|
||||
public IpcBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
long word0 = reader.ReadUInt32();
|
||||
long word1 = reader.ReadUInt32();
|
||||
long word2 = reader.ReadUInt32();
|
||||
long Word0 = Reader.ReadUInt32();
|
||||
long Word1 = Reader.ReadUInt32();
|
||||
long Word2 = Reader.ReadUInt32();
|
||||
|
||||
Position = word1;
|
||||
Position |= (word2 << 4) & 0x0f00000000;
|
||||
Position |= (word2 << 34) & 0x7000000000;
|
||||
Position = Word1;
|
||||
Position |= (Word2 << 4) & 0x0f00000000;
|
||||
Position |= (Word2 << 34) & 0x7000000000;
|
||||
|
||||
Size = word0;
|
||||
Size |= (word2 << 8) & 0xf00000000;
|
||||
Size = Word0;
|
||||
Size |= (Word2 << 8) & 0xf00000000;
|
||||
|
||||
Flags = (int)word2 & 3;
|
||||
Flags = (int)Word2 & 3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,87 +5,87 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
{
|
||||
class IpcHandleDesc
|
||||
{
|
||||
public bool HasPId { get; }
|
||||
public bool HasPId { get; private set; }
|
||||
|
||||
public long PId { get; }
|
||||
public long PId { get; private set; }
|
||||
|
||||
public int[] ToCopy { get; }
|
||||
public int[] ToMove { get; }
|
||||
public int[] ToCopy { get; private set; }
|
||||
public int[] ToMove { get; private set; }
|
||||
|
||||
public IpcHandleDesc(BinaryReader reader)
|
||||
public IpcHandleDesc(BinaryReader Reader)
|
||||
{
|
||||
int word = reader.ReadInt32();
|
||||
int Word = Reader.ReadInt32();
|
||||
|
||||
HasPId = (word & 1) != 0;
|
||||
HasPId = (Word & 1) != 0;
|
||||
|
||||
ToCopy = new int[(word >> 1) & 0xf];
|
||||
ToMove = new int[(word >> 5) & 0xf];
|
||||
ToCopy = new int[(Word >> 1) & 0xf];
|
||||
ToMove = new int[(Word >> 5) & 0xf];
|
||||
|
||||
PId = HasPId ? reader.ReadInt64() : 0;
|
||||
PId = HasPId ? Reader.ReadInt64() : 0;
|
||||
|
||||
for (int index = 0; index < ToCopy.Length; index++)
|
||||
for (int Index = 0; Index < ToCopy.Length; Index++)
|
||||
{
|
||||
ToCopy[index] = reader.ReadInt32();
|
||||
ToCopy[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
for (int index = 0; index < ToMove.Length; index++)
|
||||
for (int Index = 0; Index < ToMove.Length; Index++)
|
||||
{
|
||||
ToMove[index] = reader.ReadInt32();
|
||||
ToMove[Index] = Reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public IpcHandleDesc(int[] copy, int[] move)
|
||||
public IpcHandleDesc(int[] Copy, int[] Move)
|
||||
{
|
||||
ToCopy = copy ?? throw new ArgumentNullException(nameof(copy));
|
||||
ToMove = move ?? throw new ArgumentNullException(nameof(move));
|
||||
ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy));
|
||||
ToMove = Move ?? throw new ArgumentNullException(nameof(Move));
|
||||
}
|
||||
|
||||
public IpcHandleDesc(int[] copy, int[] move, long pId) : this(copy, move)
|
||||
public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move)
|
||||
{
|
||||
PId = pId;
|
||||
this.PId = PId;
|
||||
|
||||
HasPId = true;
|
||||
}
|
||||
|
||||
public static IpcHandleDesc MakeCopy(params int[] handles)
|
||||
public static IpcHandleDesc MakeCopy(params int[] Handles)
|
||||
{
|
||||
return new IpcHandleDesc(handles, new int[0]);
|
||||
return new IpcHandleDesc(Handles, new int[0]);
|
||||
}
|
||||
|
||||
public static IpcHandleDesc MakeMove(params int[] handles)
|
||||
public static IpcHandleDesc MakeMove(params int[] Handles)
|
||||
{
|
||||
return new IpcHandleDesc(new int[0], handles);
|
||||
return new IpcHandleDesc(new int[0], Handles);
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
int word = HasPId ? 1 : 0;
|
||||
int Word = HasPId ? 1 : 0;
|
||||
|
||||
word |= (ToCopy.Length & 0xf) << 1;
|
||||
word |= (ToMove.Length & 0xf) << 5;
|
||||
Word |= (ToCopy.Length & 0xf) << 1;
|
||||
Word |= (ToMove.Length & 0xf) << 5;
|
||||
|
||||
writer.Write(word);
|
||||
Writer.Write(Word);
|
||||
|
||||
if (HasPId)
|
||||
{
|
||||
writer.Write(PId);
|
||||
Writer.Write((long)PId);
|
||||
}
|
||||
|
||||
foreach (int handle in ToCopy)
|
||||
foreach (int Handle in ToCopy)
|
||||
{
|
||||
writer.Write(handle);
|
||||
Writer.Write(Handle);
|
||||
}
|
||||
|
||||
foreach (int handle in ToMove)
|
||||
foreach (int Handle in ToMove)
|
||||
{
|
||||
writer.Write(handle);
|
||||
Writer.Write(Handle);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,61 +8,61 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
static class IpcHandler
|
||||
{
|
||||
public static long IpcCall(
|
||||
Switch device,
|
||||
KProcess process,
|
||||
MemoryManager memory,
|
||||
KSession session,
|
||||
IpcMessage request,
|
||||
long cmdPtr)
|
||||
Switch Device,
|
||||
KProcess Process,
|
||||
MemoryManager Memory,
|
||||
KSession Session,
|
||||
IpcMessage Request,
|
||||
long CmdPtr)
|
||||
{
|
||||
IpcMessage response = new IpcMessage();
|
||||
IpcMessage Response = new IpcMessage();
|
||||
|
||||
using (MemoryStream raw = new MemoryStream(request.RawData))
|
||||
using (MemoryStream Raw = new MemoryStream(Request.RawData))
|
||||
{
|
||||
BinaryReader reqReader = new BinaryReader(raw);
|
||||
BinaryReader ReqReader = new BinaryReader(Raw);
|
||||
|
||||
if (request.Type == IpcMessageType.Request ||
|
||||
request.Type == IpcMessageType.RequestWithContext)
|
||||
if (Request.Type == IpcMessageType.Request ||
|
||||
Request.Type == IpcMessageType.RequestWithContext)
|
||||
{
|
||||
response.Type = IpcMessageType.Response;
|
||||
Response.Type = IpcMessageType.Response;
|
||||
|
||||
using (MemoryStream resMs = new MemoryStream())
|
||||
using (MemoryStream ResMS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter resWriter = new BinaryWriter(resMs);
|
||||
BinaryWriter ResWriter = new BinaryWriter(ResMS);
|
||||
|
||||
ServiceCtx context = new ServiceCtx(
|
||||
device,
|
||||
process,
|
||||
memory,
|
||||
session,
|
||||
request,
|
||||
response,
|
||||
reqReader,
|
||||
resWriter);
|
||||
ServiceCtx Context = new ServiceCtx(
|
||||
Device,
|
||||
Process,
|
||||
Memory,
|
||||
Session,
|
||||
Request,
|
||||
Response,
|
||||
ReqReader,
|
||||
ResWriter);
|
||||
|
||||
session.Service.CallMethod(context);
|
||||
Session.Service.CallMethod(Context);
|
||||
|
||||
response.RawData = resMs.ToArray();
|
||||
Response.RawData = ResMS.ToArray();
|
||||
}
|
||||
}
|
||||
else if (request.Type == IpcMessageType.Control ||
|
||||
request.Type == IpcMessageType.ControlWithContext)
|
||||
else if (Request.Type == IpcMessageType.Control ||
|
||||
Request.Type == IpcMessageType.ControlWithContext)
|
||||
{
|
||||
long magic = reqReader.ReadInt64();
|
||||
long cmdId = reqReader.ReadInt64();
|
||||
long Magic = ReqReader.ReadInt64();
|
||||
long CmdId = ReqReader.ReadInt64();
|
||||
|
||||
switch (cmdId)
|
||||
switch (CmdId)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
request = FillResponse(response, 0, session.Service.ConvertToDomain());
|
||||
Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
request = FillResponse(response, 0, 0x500);
|
||||
Request = FillResponse(Response, 0, 0x500);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -71,73 +71,73 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
case 2:
|
||||
case 4:
|
||||
{
|
||||
int unknown = reqReader.ReadInt32();
|
||||
int Unknown = ReqReader.ReadInt32();
|
||||
|
||||
if (process.HandleTable.GenerateHandle(session, out int handle) != KernelResult.Success)
|
||||
if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
response.HandleDesc = IpcHandleDesc.MakeMove(handle);
|
||||
Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||
|
||||
request = FillResponse(response, 0);
|
||||
Request = FillResponse(Response, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: throw new NotImplementedException(cmdId.ToString());
|
||||
default: throw new NotImplementedException(CmdId.ToString());
|
||||
}
|
||||
}
|
||||
else if (request.Type == IpcMessageType.CloseSession)
|
||||
else if (Request.Type == IpcMessageType.CloseSession)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(request.Type.ToString());
|
||||
throw new NotImplementedException(Request.Type.ToString());
|
||||
}
|
||||
|
||||
memory.WriteBytes(cmdPtr, response.GetBytes(cmdPtr));
|
||||
Memory.WriteBytes(CmdPtr, Response.GetBytes(CmdPtr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)
|
||||
private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
foreach (int value in values)
|
||||
foreach (int Value in Values)
|
||||
{
|
||||
writer.Write(value);
|
||||
Writer.Write(Value);
|
||||
}
|
||||
|
||||
return FillResponse(response, result, ms.ToArray());
|
||||
return FillResponse(Response, Result, MS.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private static IpcMessage FillResponse(IpcMessage response, long result, byte[] data = null)
|
||||
private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null)
|
||||
{
|
||||
response.Type = IpcMessageType.Response;
|
||||
Response.Type = IpcMessageType.Response;
|
||||
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
writer.Write(IpcMagic.Sfco);
|
||||
writer.Write(result);
|
||||
Writer.Write(IpcMagic.Sfco);
|
||||
Writer.Write(Result);
|
||||
|
||||
if (data != null)
|
||||
if (Data != null)
|
||||
{
|
||||
writer.Write(data);
|
||||
Writer.Write(Data);
|
||||
}
|
||||
|
||||
response.RawData = ms.ToArray();
|
||||
Response.RawData = MS.ToArray();
|
||||
}
|
||||
|
||||
return response;
|
||||
return Response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
|
||||
public IpcHandleDesc HandleDesc { get; set; }
|
||||
|
||||
public List<IpcPtrBuffDesc> PtrBuff { get; }
|
||||
public List<IpcBuffDesc> SendBuff { get; }
|
||||
public List<IpcBuffDesc> ReceiveBuff { get; }
|
||||
public List<IpcBuffDesc> ExchangeBuff { get; }
|
||||
public List<IpcRecvListBuffDesc> RecvListBuff { get; }
|
||||
public List<IpcPtrBuffDesc> PtrBuff { get; private set; }
|
||||
public List<IpcBuffDesc> SendBuff { get; private set; }
|
||||
public List<IpcBuffDesc> ReceiveBuff { get; private set; }
|
||||
public List<IpcBuffDesc> ExchangeBuff { get; private set; }
|
||||
public List<IpcRecvListBuffDesc> RecvListBuff { get; private set; }
|
||||
|
||||
public List<int> ObjectIds { get; }
|
||||
public List<int> ObjectIds { get; private set; }
|
||||
|
||||
public byte[] RawData { get; set; }
|
||||
|
||||
|
@ -30,185 +30,183 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
ObjectIds = new List<int>();
|
||||
}
|
||||
|
||||
public IpcMessage(byte[] data, long cmdPtr) : this()
|
||||
public IpcMessage(byte[] Data, long CmdPtr) : this()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream(data))
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(ms);
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
Initialize(reader, cmdPtr);
|
||||
Initialize(Reader, CmdPtr);
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize(BinaryReader reader, long cmdPtr)
|
||||
private void Initialize(BinaryReader Reader, long CmdPtr)
|
||||
{
|
||||
int word0 = reader.ReadInt32();
|
||||
int word1 = reader.ReadInt32();
|
||||
int Word0 = Reader.ReadInt32();
|
||||
int Word1 = Reader.ReadInt32();
|
||||
|
||||
Type = (IpcMessageType)(word0 & 0xffff);
|
||||
Type = (IpcMessageType)(Word0 & 0xffff);
|
||||
|
||||
int ptrBuffCount = (word0 >> 16) & 0xf;
|
||||
int sendBuffCount = (word0 >> 20) & 0xf;
|
||||
int recvBuffCount = (word0 >> 24) & 0xf;
|
||||
int xchgBuffCount = (word0 >> 28) & 0xf;
|
||||
int PtrBuffCount = (Word0 >> 16) & 0xf;
|
||||
int SendBuffCount = (Word0 >> 20) & 0xf;
|
||||
int RecvBuffCount = (Word0 >> 24) & 0xf;
|
||||
int XchgBuffCount = (Word0 >> 28) & 0xf;
|
||||
|
||||
int rawDataSize = (word1 >> 0) & 0x3ff;
|
||||
int recvListFlags = (word1 >> 10) & 0xf;
|
||||
bool hndDescEnable = ((word1 >> 31) & 0x1) != 0;
|
||||
int RawDataSize = (Word1 >> 0) & 0x3ff;
|
||||
int RecvListFlags = (Word1 >> 10) & 0xf;
|
||||
bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0;
|
||||
|
||||
if (hndDescEnable)
|
||||
if (HndDescEnable)
|
||||
{
|
||||
HandleDesc = new IpcHandleDesc(reader);
|
||||
HandleDesc = new IpcHandleDesc(Reader);
|
||||
}
|
||||
|
||||
for (int index = 0; index < ptrBuffCount; index++)
|
||||
for (int Index = 0; Index < PtrBuffCount; Index++)
|
||||
{
|
||||
PtrBuff.Add(new IpcPtrBuffDesc(reader));
|
||||
PtrBuff.Add(new IpcPtrBuffDesc(Reader));
|
||||
}
|
||||
|
||||
void ReadBuff(List<IpcBuffDesc> buff, int count)
|
||||
void ReadBuff(List<IpcBuffDesc> Buff, int Count)
|
||||
{
|
||||
for (int index = 0; index < count; index++)
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
buff.Add(new IpcBuffDesc(reader));
|
||||
Buff.Add(new IpcBuffDesc(Reader));
|
||||
}
|
||||
}
|
||||
|
||||
ReadBuff(SendBuff, sendBuffCount);
|
||||
ReadBuff(ReceiveBuff, recvBuffCount);
|
||||
ReadBuff(ExchangeBuff, xchgBuffCount);
|
||||
ReadBuff(SendBuff, SendBuffCount);
|
||||
ReadBuff(ReceiveBuff, RecvBuffCount);
|
||||
ReadBuff(ExchangeBuff, XchgBuffCount);
|
||||
|
||||
rawDataSize *= 4;
|
||||
RawDataSize *= 4;
|
||||
|
||||
long recvListPos = reader.BaseStream.Position + rawDataSize;
|
||||
long RecvListPos = Reader.BaseStream.Position + RawDataSize;
|
||||
|
||||
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
||||
long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr);
|
||||
|
||||
reader.BaseStream.Seek(pad0, SeekOrigin.Current);
|
||||
Reader.BaseStream.Seek(Pad0, SeekOrigin.Current);
|
||||
|
||||
int recvListCount = recvListFlags - 2;
|
||||
int RecvListCount = RecvListFlags - 2;
|
||||
|
||||
if (recvListCount == 0)
|
||||
if (RecvListCount == 0)
|
||||
{
|
||||
recvListCount = 1;
|
||||
RecvListCount = 1;
|
||||
}
|
||||
else if (recvListCount < 0)
|
||||
else if (RecvListCount < 0)
|
||||
{
|
||||
recvListCount = 0;
|
||||
RecvListCount = 0;
|
||||
}
|
||||
|
||||
RawData = reader.ReadBytes(rawDataSize);
|
||||
RawData = Reader.ReadBytes(RawDataSize);
|
||||
|
||||
reader.BaseStream.Seek(recvListPos, SeekOrigin.Begin);
|
||||
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
|
||||
|
||||
for (int index = 0; index < recvListCount; index++)
|
||||
for (int Index = 0; Index < RecvListCount; Index++)
|
||||
{
|
||||
RecvListBuff.Add(new IpcRecvListBuffDesc(reader));
|
||||
RecvListBuff.Add(new IpcRecvListBuffDesc(Reader));
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetBytes(long cmdPtr)
|
||||
public byte[] GetBytes(long CmdPtr)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
int word0;
|
||||
int word1;
|
||||
int Word0;
|
||||
int Word1;
|
||||
|
||||
word0 = (int)Type;
|
||||
word0 |= (PtrBuff.Count & 0xf) << 16;
|
||||
word0 |= (SendBuff.Count & 0xf) << 20;
|
||||
word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
||||
word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
||||
Word0 = (int)Type;
|
||||
Word0 |= (PtrBuff.Count & 0xf) << 16;
|
||||
Word0 |= (SendBuff.Count & 0xf) << 20;
|
||||
Word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
||||
Word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
||||
|
||||
byte[] handleData = new byte[0];
|
||||
byte[] HandleData = new byte[0];
|
||||
|
||||
if (HandleDesc != null)
|
||||
{
|
||||
handleData = HandleDesc.GetBytes();
|
||||
HandleData = HandleDesc.GetBytes();
|
||||
}
|
||||
|
||||
int dataLength = RawData?.Length ?? 0;
|
||||
int DataLength = RawData?.Length ?? 0;
|
||||
|
||||
int pad0 = (int)GetPadSize16(cmdPtr + 8 + handleData.Length);
|
||||
int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length);
|
||||
|
||||
//Apparently, padding after Raw Data is 16 bytes, however when there is
|
||||
//padding before Raw Data too, we need to subtract the size of this padding.
|
||||
//This is the weirdest padding I've seen so far...
|
||||
int pad1 = 0x10 - pad0;
|
||||
int Pad1 = 0x10 - Pad0;
|
||||
|
||||
dataLength = (dataLength + pad0 + pad1) / 4;
|
||||
DataLength = (DataLength + Pad0 + Pad1) / 4;
|
||||
|
||||
word1 = dataLength & 0x3ff;
|
||||
Word1 = DataLength & 0x3ff;
|
||||
|
||||
if (HandleDesc != null)
|
||||
{
|
||||
word1 |= 1 << 31;
|
||||
Word1 |= 1 << 31;
|
||||
}
|
||||
|
||||
writer.Write(word0);
|
||||
writer.Write(word1);
|
||||
writer.Write(handleData);
|
||||
Writer.Write(Word0);
|
||||
Writer.Write(Word1);
|
||||
Writer.Write(HandleData);
|
||||
|
||||
ms.Seek(pad0, SeekOrigin.Current);
|
||||
MS.Seek(Pad0, SeekOrigin.Current);
|
||||
|
||||
if (RawData != null)
|
||||
{
|
||||
writer.Write(RawData);
|
||||
Writer.Write(RawData);
|
||||
}
|
||||
|
||||
writer.Write(new byte[pad1]);
|
||||
Writer.Write(new byte[Pad1]);
|
||||
|
||||
return ms.ToArray();
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private long GetPadSize16(long position)
|
||||
private long GetPadSize16(long Position)
|
||||
{
|
||||
if ((position & 0xf) != 0)
|
||||
if ((Position & 0xf) != 0)
|
||||
{
|
||||
return 0x10 - (position & 0xf);
|
||||
return 0x10 - (Position & 0xf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public (long Position, long Size) GetBufferType0x21(int index = 0)
|
||||
public (long Position, long Size) GetBufferType0x21(int Index = 0)
|
||||
{
|
||||
if (PtrBuff.Count > index &&
|
||||
PtrBuff[index].Position != 0 &&
|
||||
PtrBuff[index].Size != 0)
|
||||
if (PtrBuff.Count > Index &&
|
||||
PtrBuff[Index].Position != 0 &&
|
||||
PtrBuff[Index].Size != 0)
|
||||
{
|
||||
return (PtrBuff[index].Position, PtrBuff[index].Size);
|
||||
return (PtrBuff[Index].Position, PtrBuff[Index].Size);
|
||||
}
|
||||
|
||||
if (SendBuff.Count > index &&
|
||||
SendBuff[index].Position != 0 &&
|
||||
SendBuff[index].Size != 0)
|
||||
if (SendBuff.Count > Index &&
|
||||
SendBuff[Index].Position != 0 &&
|
||||
SendBuff[Index].Size != 0)
|
||||
{
|
||||
return (SendBuff[index].Position, SendBuff[index].Size);
|
||||
return (SendBuff[Index].Position, SendBuff[Index].Size);
|
||||
}
|
||||
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public (long Position, long Size) GetBufferType0x22(int index = 0)
|
||||
public (long Position, long Size) GetBufferType0x22(int Index = 0)
|
||||
{
|
||||
if (RecvListBuff.Count > index &&
|
||||
RecvListBuff[index].Position != 0 &&
|
||||
RecvListBuff[index].Size != 0)
|
||||
if (RecvListBuff.Count > Index &&
|
||||
RecvListBuff[Index].Position != 0 &&
|
||||
RecvListBuff[Index].Size != 0)
|
||||
{
|
||||
return (RecvListBuff[index].Position, RecvListBuff[index].Size);
|
||||
return (RecvListBuff[Index].Position, RecvListBuff[Index].Size);
|
||||
}
|
||||
|
||||
if (ReceiveBuff.Count > index &&
|
||||
ReceiveBuff[index].Position != 0 &&
|
||||
ReceiveBuff[index].Size != 0)
|
||||
if (ReceiveBuff.Count > Index &&
|
||||
ReceiveBuff[Index].Position != 0 &&
|
||||
ReceiveBuff[Index].Size != 0)
|
||||
{
|
||||
return (ReceiveBuff[index].Position, ReceiveBuff[index].Size);
|
||||
return (ReceiveBuff[Index].Position, ReceiveBuff[Index].Size);
|
||||
}
|
||||
|
||||
return (0, 0);
|
||||
|
|
|
@ -4,23 +4,23 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
{
|
||||
struct IpcPtrBuffDesc
|
||||
{
|
||||
public long Position { get; }
|
||||
public int Index { get; }
|
||||
public long Size { get; }
|
||||
public long Position { get; private set; }
|
||||
public int Index { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
public IpcPtrBuffDesc(BinaryReader reader)
|
||||
public IpcPtrBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
long word0 = reader.ReadUInt32();
|
||||
long word1 = reader.ReadUInt32();
|
||||
long Word0 = Reader.ReadUInt32();
|
||||
long Word1 = Reader.ReadUInt32();
|
||||
|
||||
Position = word1;
|
||||
Position |= (word0 << 20) & 0x0f00000000;
|
||||
Position |= (word0 << 30) & 0x7000000000;
|
||||
Position = Word1;
|
||||
Position |= (Word0 << 20) & 0x0f00000000;
|
||||
Position |= (Word0 << 30) & 0x7000000000;
|
||||
|
||||
Index = ((int)word0 >> 0) & 0x03f;
|
||||
Index |= ((int)word0 >> 3) & 0x1c0;
|
||||
Index = ((int)Word0 >> 0) & 0x03f;
|
||||
Index |= ((int)Word0 >> 3) & 0x1c0;
|
||||
|
||||
Size = (ushort)(word0 >> 16);
|
||||
Size = (ushort)(Word0 >> 16);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,16 +4,16 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
{
|
||||
struct IpcRecvListBuffDesc
|
||||
{
|
||||
public long Position { get; }
|
||||
public long Size { get; }
|
||||
public long Position { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
public IpcRecvListBuffDesc(BinaryReader reader)
|
||||
public IpcRecvListBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
long value = reader.ReadInt64();
|
||||
long Value = Reader.ReadInt64();
|
||||
|
||||
Position = value & 0xffffffffffff;
|
||||
Position = Value & 0xffffffffffff;
|
||||
|
||||
Size = (ushort)(value >> 48);
|
||||
Size = (ushort)(Value >> 48);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.HLE.HOS.Ipc
|
||||
{
|
||||
delegate long ServiceProcessRequest(ServiceCtx context);
|
||||
delegate long ServiceProcessRequest(ServiceCtx Context);
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
private class PausableThread
|
||||
{
|
||||
public ManualResetEvent Event { get; }
|
||||
public ManualResetEvent Event { get; private set; }
|
||||
|
||||
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; }
|
||||
public long BaseAddress { get; private set; }
|
||||
|
||||
public ElfSymbol[] Symbols { get; }
|
||||
public ElfSymbol[] Symbols { get; private set; }
|
||||
|
||||
public Image(long baseAddress, ElfSymbol[] symbols)
|
||||
public Image(long BaseAddress, ElfSymbol[] Symbols)
|
||||
{
|
||||
BaseAddress = baseAddress;
|
||||
Symbols = symbols;
|
||||
this.BaseAddress = BaseAddress;
|
||||
this.Symbols = Symbols;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Image> _images;
|
||||
private List<Image> Images;
|
||||
|
||||
private int _loaded;
|
||||
private int Loaded;
|
||||
|
||||
public HleProcessDebugger(KProcess owner)
|
||||
public HleProcessDebugger(KProcess Owner)
|
||||
{
|
||||
_owner = owner;
|
||||
this.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; }
|
||||
public HleCoreManager CoreManager { get; private set; }
|
||||
|
||||
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 < CpuCoresCount; core++)
|
||||
for (int Core = 0; Core < KScheduler.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)
|
||||
{
|
||||
_system = system;
|
||||
this.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)
|
||||
{
|
||||
System = system;
|
||||
this.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)
|
||||
{
|
||||
_maxSessions = maxSessions;
|
||||
_parent = parent;
|
||||
this.MaxSessions = MaxSessions;
|
||||
this.Parent = Parent;
|
||||
}
|
||||
|
||||
public new static KernelResult RemoveName(Horizon system, string name)
|
||||
public new static KernelResult RemoveName(Horizon System, string Name)
|
||||
{
|
||||
KAutoObject foundObj = FindNamedObject(system, name);
|
||||
KAutoObject FoundObj = KAutoObject.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)
|
||||
{
|
||||
_scheduler = scheduler;
|
||||
_coreManager = coreManager;
|
||||
this.Scheduler = Scheduler;
|
||||
this.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; }
|
||||
public object LockObj { get; private set; }
|
||||
|
||||
private int _recursionCount;
|
||||
private int RecursionCount;
|
||||
|
||||
public KCriticalSection(Horizon system)
|
||||
public KCriticalSection(Horizon System)
|
||||
{
|
||||
_system = system;
|
||||
this.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; }
|
||||
public KWritableEvent WritableEvent { get; }
|
||||
public KReadableEvent ReadableEvent { get; private set; }
|
||||
public KWritableEvent WritableEvent { get; private set; }
|
||||
|
||||
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; }
|
||||
public int Index { get; private set; }
|
||||
|
||||
public ushort HandleId { get; set; }
|
||||
public object Obj { get; set; }
|
||||
|
||||
public KHandleEntry(int index)
|
||||
public KHandleEntry(int Index)
|
||||
{
|
||||
Index = index;
|
||||
this.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)
|
||||
{
|
||||
_system = system;
|
||||
this.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;
|
||||
}
|
||||
|
||||
_size = size;
|
||||
this.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) & 0xffff8000) | entry.Index;
|
||||
Handle = (int)((IdCounter << 15) & (uint)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; }
|
||||
public KMemoryArrangeRegion NvServices { get; }
|
||||
public KMemoryArrangeRegion Applet { get; }
|
||||
public KMemoryArrangeRegion Application { get; }
|
||||
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 KMemoryArrange(
|
||||
KMemoryArrangeRegion service,
|
||||
KMemoryArrangeRegion nvServices,
|
||||
KMemoryArrangeRegion applet,
|
||||
KMemoryArrangeRegion application)
|
||||
KMemoryArrangeRegion Service,
|
||||
KMemoryArrangeRegion NvServices,
|
||||
KMemoryArrangeRegion Applet,
|
||||
KMemoryArrangeRegion Application)
|
||||
{
|
||||
Service = service;
|
||||
NvServices = nvServices;
|
||||
Applet = applet;
|
||||
Application = application;
|
||||
this.Service = Service;
|
||||
this.NvServices = NvServices;
|
||||
this.Applet = Applet;
|
||||
this.Application = Application;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,15 +2,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
struct KMemoryArrangeRegion
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
|
||||
public ulong EndAddr => Address + Size;
|
||||
|
||||
public KMemoryArrangeRegion(ulong address, ulong size)
|
||||
public KMemoryArrangeRegion(ulong Address, ulong Size)
|
||||
{
|
||||
Address = address;
|
||||
Size = size;
|
||||
this.Address = Address;
|
||||
this.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)
|
||||
{
|
||||
BaseAddress = baseAddress;
|
||||
PagesCount = pagesCount;
|
||||
State = state;
|
||||
Attribute = attribute;
|
||||
Permission = permission;
|
||||
this.BaseAddress = BaseAddress;
|
||||
this.PagesCount = PagesCount;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
this.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)
|
||||
{
|
||||
_capacityElements = capacityElements;
|
||||
this.CapacityElements = CapacityElements;
|
||||
}
|
||||
|
||||
public bool CanAllocate(int count)
|
||||
public bool CanAllocate(int Count)
|
||||
{
|
||||
return (ulong)(Count + count) <= _capacityElements;
|
||||
return (ulong)(this.Count + Count) <= CapacityElements;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,32 +2,32 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
class KMemoryInfo
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
|
||||
public MemoryState State { get; }
|
||||
public MemoryPermission Permission { get; }
|
||||
public MemoryAttribute Attribute { get; }
|
||||
public MemoryState State { get; private set; }
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
public MemoryAttribute Attribute { get; private set; }
|
||||
|
||||
public int IpcRefCount { get; }
|
||||
public int DeviceRefCount { get; }
|
||||
public int IpcRefCount { get; private set; }
|
||||
public int DeviceRefCount { get; private set; }
|
||||
|
||||
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)
|
||||
{
|
||||
Address = address;
|
||||
Size = size;
|
||||
State = state;
|
||||
Attribute = attribute;
|
||||
Permission = permission;
|
||||
IpcRefCount = ipcRefCount;
|
||||
DeviceRefCount = deviceRefCount;
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
this.State = State;
|
||||
this.Attribute = Attribute;
|
||||
this.Permission = Permission;
|
||||
this.IpcRefCount = IpcRefCount;
|
||||
this.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; }
|
||||
public ulong EndAddr { get; }
|
||||
public ulong Size { get; }
|
||||
public ulong Address { get; private set; }
|
||||
public ulong EndAddr { get; private set; }
|
||||
public ulong Size { get; private set; }
|
||||
|
||||
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];
|
||||
|
||||
Address = address;
|
||||
Size = size;
|
||||
EndAddr = endAddr;
|
||||
this.Address = Address;
|
||||
this.Size = Size;
|
||||
this.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;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue