| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- using ChocolArm64.Memory;
- using Ryujinx.Common;
- using Ryujinx.Common.Logging;
- using Ryujinx.HLE.HOS.Kernel;
- using Ryujinx.HLE.Loaders.Executables;
- using Ryujinx.HLE.Loaders.Npdm;
- namespace Ryujinx.HLE.HOS
- {
- class ProgramLoader
- {
- private const bool AslrEnabled = true;
- private const int ArgsHeaderSize = 8;
- private const int ArgsDataSize = 0x9000;
- private const int ArgsTotalSize = ArgsHeaderSize + ArgsDataSize;
- public static bool LoadKernelInitalProcess(Horizon System, KernelInitialProcess Kip)
- {
- int EndOffset = Kip.DataOffset + Kip.Data.Length;
- if (Kip.BssSize != 0)
- {
- EndOffset = Kip.BssOffset + Kip.BssSize;
- }
- int CodeSize = BitUtils.AlignUp(Kip.TextOffset + EndOffset, KMemoryManager.PageSize);
- int CodePagesCount = CodeSize / KMemoryManager.PageSize;
- ulong CodeBaseAddress = Kip.Addr39Bits ? 0x8000000UL : 0x200000UL;
- ulong CodeAddress = CodeBaseAddress + (ulong)Kip.TextOffset;
- int MmuFlags = 0;
- if (AslrEnabled)
- {
- //TODO: Randomization.
- MmuFlags |= 0x20;
- }
- if (Kip.Addr39Bits)
- {
- MmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
- }
- if (Kip.Is64Bits)
- {
- MmuFlags |= 1;
- }
- ProcessCreationInfo CreationInfo = new ProcessCreationInfo(
- Kip.Name,
- Kip.ProcessCategory,
- Kip.TitleId,
- CodeAddress,
- CodePagesCount,
- MmuFlags,
- 0,
- 0);
- MemoryRegion MemRegion = Kip.IsService
- ? MemoryRegion.Service
- : MemoryRegion.Application;
- KMemoryRegionManager Region = System.MemoryRegions[(int)MemRegion];
- KernelResult Result = Region.AllocatePages((ulong)CodePagesCount, false, out KPageList PageList);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
- return false;
- }
- KProcess Process = new KProcess(System);
- Result = Process.InitializeKip(
- CreationInfo,
- Kip.Capabilities,
- PageList,
- System.ResourceLimit,
- MemRegion);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
- return false;
- }
- Result = LoadIntoMemory(Process, Kip, CodeBaseAddress);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
- return false;
- }
- Result = Process.Start(Kip.MainThreadPriority, (ulong)Kip.MainThreadStackSize);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process start returned error \"{Result}\".");
- return false;
- }
- System.Processes.Add(Process.Pid, Process);
- return true;
- }
- public static bool LoadStaticObjects(
- Horizon System,
- Npdm MetaData,
- IExecutable[] StaticObjects,
- byte[] Arguments = null)
- {
- ulong ArgsStart = 0;
- int ArgsSize = 0;
- ulong CodeStart = 0x8000000;
- int CodeSize = 0;
- ulong[] NsoBase = new ulong[StaticObjects.Length];
- for (int Index = 0; Index < StaticObjects.Length; Index++)
- {
- IExecutable StaticObject = StaticObjects[Index];
- int TextEnd = StaticObject.TextOffset + StaticObject.Text.Length;
- int ROEnd = StaticObject.ROOffset + StaticObject.RO.Length;
- int DataEnd = StaticObject.DataOffset + StaticObject.Data.Length + StaticObject.BssSize;
- int NsoSize = TextEnd;
- if ((uint)NsoSize < (uint)ROEnd)
- {
- NsoSize = ROEnd;
- }
- if ((uint)NsoSize < (uint)DataEnd)
- {
- NsoSize = DataEnd;
- }
- NsoSize = BitUtils.AlignUp(NsoSize, KMemoryManager.PageSize);
- NsoBase[Index] = CodeStart + (ulong)CodeSize;
- CodeSize += NsoSize;
- if (Arguments != null && ArgsSize == 0)
- {
- ArgsStart = (ulong)CodeSize;
- ArgsSize = BitUtils.AlignDown(Arguments.Length * 2 + ArgsTotalSize - 1, KMemoryManager.PageSize);
- CodeSize += ArgsSize;
- }
- }
- int CodePagesCount = CodeSize / KMemoryManager.PageSize;
- int PersonalMmHeapPagesCount = MetaData.PersonalMmHeapSize / KMemoryManager.PageSize;
- ProcessCreationInfo CreationInfo = new ProcessCreationInfo(
- MetaData.TitleName,
- MetaData.ProcessCategory,
- MetaData.ACI0.TitleId,
- CodeStart,
- CodePagesCount,
- MetaData.MmuFlags,
- 0,
- PersonalMmHeapPagesCount);
- KernelResult Result;
- KResourceLimit ResourceLimit = new KResourceLimit(System);
- long ApplicationRgSize = (long)System.MemoryRegions[(int)MemoryRegion.Application].Size;
- Result = ResourceLimit.SetLimitValue(LimitableResource.Memory, ApplicationRgSize);
- Result |= ResourceLimit.SetLimitValue(LimitableResource.Thread, 608);
- Result |= ResourceLimit.SetLimitValue(LimitableResource.Event, 700);
- Result |= ResourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
- Result |= ResourceLimit.SetLimitValue(LimitableResource.Session, 894);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process initialization failed setting resource limit values.");
- return false;
- }
- KProcess Process = new KProcess(System);
- Result = Process.Initialize(
- CreationInfo,
- MetaData.ACI0.KernelAccessControl.Capabilities,
- ResourceLimit,
- MemoryRegion.Application);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
- return false;
- }
- for (int Index = 0; Index < StaticObjects.Length; Index++)
- {
- Logger.PrintInfo(LogClass.Loader, $"Loading image {Index} at 0x{NsoBase[Index]:x16}...");
- Result = LoadIntoMemory(Process, StaticObjects[Index], NsoBase[Index]);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{Result}\".");
- return false;
- }
- }
- Result = Process.Start(MetaData.MainThreadPriority, (ulong)MetaData.MainThreadStackSize);
- if (Result != KernelResult.Success)
- {
- Logger.PrintError(LogClass.Loader, $"Process start returned error \"{Result}\".");
- return false;
- }
- System.Processes.Add(Process.Pid, Process);
- return true;
- }
- private static KernelResult LoadIntoMemory(KProcess Process, IExecutable Image, ulong BaseAddress)
- {
- ulong TextStart = BaseAddress + (ulong)Image.TextOffset;
- ulong ROStart = BaseAddress + (ulong)Image.ROOffset;
- ulong DataStart = BaseAddress + (ulong)Image.DataOffset;
- ulong BssStart = BaseAddress + (ulong)Image.BssOffset;
- ulong End = DataStart + (ulong)Image.Data.Length;
- if (Image.BssSize != 0)
- {
- End = BssStart + (ulong)Image.BssSize;
- }
- Process.CpuMemory.WriteBytes((long)TextStart, Image.Text);
- Process.CpuMemory.WriteBytes((long)ROStart, Image.RO);
- Process.CpuMemory.WriteBytes((long)DataStart, Image.Data);
- MemoryHelper.FillWithZeros(Process.CpuMemory, (long)BssStart, Image.BssSize);
- KernelResult SetProcessMemoryPermission(ulong Address, ulong Size, MemoryPermission Permission)
- {
- if (Size == 0)
- {
- return KernelResult.Success;
- }
- Size = BitUtils.AlignUp(Size, KMemoryManager.PageSize);
- return Process.MemoryManager.SetProcessMemoryPermission(Address, Size, Permission);
- }
- KernelResult Result = SetProcessMemoryPermission(TextStart, (ulong)Image.Text.Length, MemoryPermission.ReadAndExecute);
- if (Result != KernelResult.Success)
- {
- return Result;
- }
- Result = SetProcessMemoryPermission(ROStart, (ulong)Image.RO.Length, MemoryPermission.Read);
- if (Result != KernelResult.Success)
- {
- return Result;
- }
- return SetProcessMemoryPermission(DataStart, End - DataStart, MemoryPermission.ReadAndWrite);
- }
- }
- }
|