diff options
Diffstat (limited to 'Ryujinx.HLE')
| -rw-r--r-- | Ryujinx.HLE/HOS/Horizon.cs | 215 | ||||
| -rw-r--r-- | Ryujinx.HLE/Ryujinx.HLE.csproj | 1 | ||||
| -rw-r--r-- | Ryujinx.HLE/Switch.cs | 15 | ||||
| -rw-r--r-- | Ryujinx.HLE/VirtualFileSystem.cs | 6 |
4 files changed, 237 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index a5579675..92a87661 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -1,3 +1,4 @@ +using LibHac; using Ryujinx.HLE.HOS.Font; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.SystemState; @@ -7,6 +8,7 @@ using Ryujinx.HLE.Logging; using System; using System.Collections.Concurrent; using System.IO; +using System.Linq; namespace Ryujinx.HLE.HOS { @@ -30,6 +32,8 @@ namespace Ryujinx.HLE.HOS internal KEvent VsyncEvent { get; private set; } + internal Keyset KeySet { get; private set; } + public Horizon(Switch Device) { this.Device = Device; @@ -52,6 +56,8 @@ namespace Ryujinx.HLE.HOS Font = new SharedFontManager(Device, FontSharedMem.PA); VsyncEvent = new KEvent(); + + LoadKeySet(); } public void LoadCart(string ExeFsDir, string RomFsFile = null) @@ -119,6 +125,179 @@ namespace Ryujinx.HLE.HOS MainProcess.Run(); } + public void LoadXci(string XciFile) + { + FileStream File = new FileStream(XciFile, FileMode.Open, FileAccess.Read); + + Xci Xci = new Xci(KeySet, File); + + Nca Nca = GetXciMainNca(Xci); + + if (Nca == null) + { + Device.Log.PrintError(LogClass.Loader, "Unable to load XCI"); + + return; + } + + LoadNca(Nca); + } + + private Nca GetXciMainNca(Xci Xci) + { + if (Xci.SecurePartition == null) + { + throw new InvalidDataException("Could not find XCI secure partition"); + } + + Nca MainNca = null; + Nca PatchNca = null; + + foreach (PfsFileEntry FileEntry in Xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca"))) + { + Stream NcaStream = Xci.SecurePartition.OpenFile(FileEntry); + + Nca Nca = new Nca(KeySet, NcaStream, true); + + if (Nca.Header.ContentType == ContentType.Program) + { + if (Nca.Sections.Any(x => x?.Type == SectionType.Romfs)) + { + MainNca = Nca; + } + else if (Nca.Sections.Any(x => x?.Type == SectionType.Bktr)) + { + PatchNca = Nca; + } + } + } + + if (MainNca == null) + { + Device.Log.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file"); + } + + MainNca.SetBaseNca(PatchNca); + + return MainNca; + } + + public void LoadNca(string NcaFile) + { + FileStream File = new FileStream(NcaFile, FileMode.Open, FileAccess.Read); + + Nca Nca = new Nca(KeySet, File, true); + + LoadNca(Nca); + } + + public void LoadNsp(string NspFile) + { + FileStream File = new FileStream(NspFile, FileMode.Open, FileAccess.Read); + + Pfs Nsp = new Pfs(File); + + 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) + { + // todo Change when Ticket(Stream) overload is added + Ticket Ticket = new Ticket(new BinaryReader(Nsp.OpenFile(TicketFile))); + + KeySet.TitleKeys[Ticket.RightsId] = Ticket.GetTitleKey(KeySet); + } + + foreach (PfsFileEntry NcaFile in Nsp.Files.Where(x => x.Name.EndsWith(".nca"))) + { + Nca Nca = new Nca(KeySet, Nsp.OpenFile(NcaFile), true); + + if (Nca.Header.ContentType == ContentType.Program) + { + LoadNca(Nca); + + return; + } + } + + Device.Log.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file"); + } + + public void LoadNca(Nca Nca) + { + NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs); + NcaSection ExefsSection = Nca.Sections.FirstOrDefault(x => x?.IsExefs == true); + + if (ExefsSection == null) + { + Device.Log.PrintError(LogClass.Loader, "No ExeFS found in NCA"); + + return; + } + + if (RomfsSection == null) + { + Device.Log.PrintError(LogClass.Loader, "No RomFS found in NCA"); + + return; + } + + Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false); + Device.FileSystem.SetRomFs(RomfsStream); + + Stream ExefsStream = Nca.OpenSection(ExefsSection.SectionNum, false); + Pfs Exefs = new Pfs(ExefsStream); + + Npdm MetaData = null; + + if (Exefs.FileExists("main.npdm")) + { + Device.Log.PrintInfo(LogClass.Loader, "Loading main.npdm..."); + + MetaData = new Npdm(Exefs.OpenFile("main.npdm")); + } + else + { + Device.Log.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); + } + + Process MainProcess = MakeProcess(MetaData); + + void LoadNso(string Filename) + { + foreach (PfsFileEntry File in Exefs.Files.Where(x => x.Name.StartsWith(Filename))) + { + if (Path.GetExtension(File.Name) != string.Empty) + { + continue; + } + + Device.Log.PrintInfo(LogClass.Loader, $"Loading {Filename}..."); + + string Name = Path.GetFileNameWithoutExtension(File.Name); + + Nso Program = new Nso(Exefs.OpenFile(File), Name); + + MainProcess.LoadProgram(Program); + } + } + + if (!MainProcess.MetaData.Is64Bits) + { + throw new NotImplementedException("32-bit titles are unsupported!"); + } + + LoadNso("rtld"); + + MainProcess.SetEmptyArgs(); + + LoadNso("main"); + LoadNso("subsdk"); + LoadNso("sdk"); + + MainProcess.Run(); + } + public void LoadProgram(string FilePath) { bool IsNro = Path.GetExtension(FilePath).ToLower() == ".nro"; @@ -156,6 +335,42 @@ namespace Ryujinx.HLE.HOS MainProcess.Run(IsNro); } + public void LoadKeySet() + { + string KeyFile = null; + string TitleKeyFile = null; + string ConsoleKeyFile = null; + + string Home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + LoadSetAtPath(Path.Combine(Home, ".switch")); + LoadSetAtPath(Device.FileSystem.GetSystemPath()); + + KeySet = ExternalKeys.ReadKeyFile(KeyFile, TitleKeyFile, ConsoleKeyFile); + + 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"); + + if (File.Exists(LocalKeyFile)) + { + KeyFile = LocalKeyFile; + } + + if (File.Exists(LocalTitleKeyFile)) + { + TitleKeyFile = LocalTitleKeyFile; + } + + if (File.Exists(LocalConsoleKeyFile)) + { + ConsoleKeyFile = LocalConsoleKeyFile; + } + } + } + public void SignalVsync() => VsyncEvent.WaitEvent.Set(); private Process MakeProcess(Npdm MetaData = null) diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj index fa4c254e..cd1bb034 100644 --- a/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -25,6 +25,7 @@ <ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" /> <ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" /> + <PackageReference Include="LibHac" Version="0.1.1" /> </ItemGroup> </Project> diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 32d5bef6..090aae11 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -61,6 +61,21 @@ namespace Ryujinx.HLE System.LoadCart(ExeFsDir, RomFsFile); } + public void LoadXci(string XciFile) + { + System.LoadXci(XciFile); + } + + public void LoadNca(string NcaFile) + { + System.LoadNca(NcaFile); + } + + public void LoadNsp(string NspFile) + { + System.LoadNsp(NspFile); + } + public void LoadProgram(string FileName) { System.LoadProgram(FileName); diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/VirtualFileSystem.cs index 31b8e184..133538f9 100644 --- a/Ryujinx.HLE/VirtualFileSystem.cs +++ b/Ryujinx.HLE/VirtualFileSystem.cs @@ -17,6 +17,12 @@ namespace Ryujinx.HLE RomFs = new FileStream(FileName, FileMode.Open, FileAccess.Read); } + public void SetRomFs(Stream RomfsStream) + { + RomFs?.Close(); + RomFs = RomfsStream; + } + public string GetFullPath(string BasePath, string FileName) { if (FileName.StartsWith("//")) |
