aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx/OsHle/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx/OsHle/Objects')
-rw-r--r--Ryujinx/OsHle/Objects/AccIManagerForApplication.cs17
-rw-r--r--Ryujinx/OsHle/Objects/AccIProfile.cs18
-rw-r--r--Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs56
-rw-r--r--Ryujinx/OsHle/Objects/AmIApplicationProxy.cs63
-rw-r--r--Ryujinx/OsHle/Objects/AmIAudioController.cs7
-rw-r--r--Ryujinx/OsHle/Objects/AmICommonStateGetter.cs55
-rw-r--r--Ryujinx/OsHle/Objects/AmIDebugFunctions.cs7
-rw-r--r--Ryujinx/OsHle/Objects/AmIDisplayController.cs7
-rw-r--r--Ryujinx/OsHle/Objects/AmILibraryAppletCreator.cs7
-rw-r--r--Ryujinx/OsHle/Objects/AmIParentalControlService.cs7
-rw-r--r--Ryujinx/OsHle/Objects/AmISelfController.cs28
-rw-r--r--Ryujinx/OsHle/Objects/AmIStorage.cs23
-rw-r--r--Ryujinx/OsHle/Objects/AmIStorageAccessor.cs56
-rw-r--r--Ryujinx/OsHle/Objects/AmIWindowController.cs17
-rw-r--r--Ryujinx/OsHle/Objects/ApmISession.cs13
-rw-r--r--Ryujinx/OsHle/Objects/AudIAudioRenderer.cs36
-rw-r--r--Ryujinx/OsHle/Objects/FriendIFriendService.cs7
-rw-r--r--Ryujinx/OsHle/Objects/FspSrvIFile.cs72
-rw-r--r--Ryujinx/OsHle/Objects/FspSrvIFileSystem.cs70
-rw-r--r--Ryujinx/OsHle/Objects/FspSrvIStorage.cs44
-rw-r--r--Ryujinx/OsHle/Objects/HidIAppletResource.cs22
-rw-r--r--Ryujinx/OsHle/Objects/ObjHelper.cs24
-rw-r--r--Ryujinx/OsHle/Objects/Parcel.cs58
-rw-r--r--Ryujinx/OsHle/Objects/TimeISteadyClock.cs7
-rw-r--r--Ryujinx/OsHle/Objects/TimeISystemClock.cs16
-rw-r--r--Ryujinx/OsHle/Objects/TimeITimeZoneService.cs7
-rw-r--r--Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs148
-rw-r--r--Ryujinx/OsHle/Objects/ViIHOSBinderDriver.cs211
-rw-r--r--Ryujinx/OsHle/Objects/ViIManagerDisplayService.cs17
-rw-r--r--Ryujinx/OsHle/Objects/ViISystemDisplayService.cs10
30 files changed, 1130 insertions, 0 deletions
diff --git a/Ryujinx/OsHle/Objects/AccIManagerForApplication.cs b/Ryujinx/OsHle/Objects/AccIManagerForApplication.cs
new file mode 100644
index 00000000..8e2a002b
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AccIManagerForApplication.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AccIManagerForApplication
+ {
+ public static long CheckAvailability(ServiceCtx Context)
+ {
+ return 0;
+ }
+
+ public static long GetAccountId(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(0xcafeL);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AccIProfile.cs b/Ryujinx/OsHle/Objects/AccIProfile.cs
new file mode 100644
index 00000000..2dbe189d
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AccIProfile.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AccIProfile
+ {
+ public static long GetBase(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write(0L);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs b/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs
new file mode 100644
index 00000000..e174f943
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIApplicationFunctions.cs
@@ -0,0 +1,56 @@
+using System.IO;
+
+using static Ryujinx.OsHle.Objects.ObjHelper;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIApplicationFunctions
+ {
+ private const uint LaunchParamsMagic = 0xc79497ca;
+
+ public static long PopLaunchParameter(ServiceCtx Context)
+ {
+ //Only the first 0x18 bytes of the Data seems to be actually used.
+ MakeObject(Context, new AmIStorage(MakeLaunchParams()));
+
+ return 0;
+ }
+
+ public static long EnsureSaveData(ServiceCtx Context)
+ {
+ long UIdLow = Context.RequestData.ReadInt64();
+ long UIdHigh = Context.RequestData.ReadInt64();
+
+ Context.ResponseData.Write(0L);
+
+ return 0;
+ }
+
+ public static long GetDesiredLanguage(ServiceCtx Context)
+ {
+ //This is an enumerator where each number is a differnet language.
+ //0 is Japanese and 1 is English, need to figure out the other codes.
+ Context.ResponseData.Write(1L);
+
+ return 0;
+ }
+
+ private static byte[] MakeLaunchParams()
+ {
+ //Size needs to be at least 0x88 bytes otherwise application errors.
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ MS.SetLength(0x88);
+
+ Writer.Write(LaunchParamsMagic);
+ Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used.
+ Writer.Write(1L); //User Id Low (note: User Id needs to be != 0)
+ Writer.Write(0L); //User Id High
+
+ return MS.ToArray();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIApplicationProxy.cs b/Ryujinx/OsHle/Objects/AmIApplicationProxy.cs
new file mode 100644
index 00000000..2b0bc346
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIApplicationProxy.cs
@@ -0,0 +1,63 @@
+using static Ryujinx.OsHle.Objects.ObjHelper;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIApplicationProxy
+ {
+ public static long GetCommonStateGetter(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmICommonStateGetter());
+
+ return 0;
+ }
+
+ public static long GetSelfController(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmISelfController());
+
+ return 0;
+ }
+
+ public static long GetWindowController(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmIWindowController());
+
+ return 0;
+ }
+
+ public static long GetAudioController(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmIAudioController());
+
+ return 0;
+ }
+
+ public static long GetDisplayController(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmIDisplayController());
+
+ return 0;
+ }
+
+ public static long GetLibraryAppletCreator(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmILibraryAppletCreator());
+
+ return 0;
+ }
+
+ public static long GetApplicationFunctions(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmIApplicationFunctions());
+
+ return 0;
+ }
+
+ public static long GetDebugFunctions(ServiceCtx Context)
+ {
+ MakeObject(Context, new AmIDebugFunctions());
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIAudioController.cs b/Ryujinx/OsHle/Objects/AmIAudioController.cs
new file mode 100644
index 00000000..59d94bda
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIAudioController.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIAudioController
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmICommonStateGetter.cs b/Ryujinx/OsHle/Objects/AmICommonStateGetter.cs
new file mode 100644
index 00000000..32f065c8
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmICommonStateGetter.cs
@@ -0,0 +1,55 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmICommonStateGetter
+ {
+ private enum FocusState
+ {
+ InFocus = 1,
+ OutOfFocus = 2
+ }
+
+ private enum OperationMode
+ {
+ Handheld = 0,
+ Docked = 1
+ }
+
+ public static long GetEventHandle(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(0L);
+
+ return 0;
+ }
+
+ public static long ReceiveMessage(ServiceCtx Context)
+ {
+ //Program expects 0xF at 0x17ae70 on puyo sdk,
+ //otherwise runs on a infinite loop until it reads said value.
+ //What it means is still unknown.
+ Context.ResponseData.Write(0xfL);
+
+ return 0; //0x680;
+ }
+
+ public static long GetOperationMode(ServiceCtx Context)
+ {
+ Context.ResponseData.Write((byte)OperationMode.Handheld);
+
+ return 0;
+ }
+
+ public static long GetPerformanceMode(ServiceCtx Context)
+ {
+ Context.ResponseData.Write((byte)0);
+
+ return 0;
+ }
+
+ public static long GetCurrentFocusState(ServiceCtx Context)
+ {
+ Context.ResponseData.Write((byte)FocusState.InFocus);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIDebugFunctions.cs b/Ryujinx/OsHle/Objects/AmIDebugFunctions.cs
new file mode 100644
index 00000000..9794c43f
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIDebugFunctions.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIDebugFunctions
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIDisplayController.cs b/Ryujinx/OsHle/Objects/AmIDisplayController.cs
new file mode 100644
index 00000000..be36ca0c
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIDisplayController.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIDisplayController
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmILibraryAppletCreator.cs b/Ryujinx/OsHle/Objects/AmILibraryAppletCreator.cs
new file mode 100644
index 00000000..585df9e9
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmILibraryAppletCreator.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmILibraryAppletCreator
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIParentalControlService.cs b/Ryujinx/OsHle/Objects/AmIParentalControlService.cs
new file mode 100644
index 00000000..12c3c2a9
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIParentalControlService.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIParentalControlService
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmISelfController.cs b/Ryujinx/OsHle/Objects/AmISelfController.cs
new file mode 100644
index 00000000..33cde095
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmISelfController.cs
@@ -0,0 +1,28 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmISelfController
+ {
+ public static long SetOperationModeChangedNotification(ServiceCtx Context)
+ {
+ bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
+
+ return 0;
+ }
+
+ public static long SetPerformanceModeChangedNotification(ServiceCtx Context)
+ {
+ bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
+
+ return 0;
+ }
+
+ public static long SetFocusHandlingMode(ServiceCtx Context)
+ {
+ bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false;
+ bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false;
+ bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false;
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIStorage.cs b/Ryujinx/OsHle/Objects/AmIStorage.cs
new file mode 100644
index 00000000..7e608ac8
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIStorage.cs
@@ -0,0 +1,23 @@
+using static Ryujinx.OsHle.Objects.ObjHelper;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIStorage
+ {
+ public byte[] Data { get; private set; }
+
+ public AmIStorage(byte[] Data)
+ {
+ this.Data = Data;
+ }
+
+ public static long Open(ServiceCtx Context)
+ {
+ AmIStorage Storage = Context.GetObject<AmIStorage>();
+
+ MakeObject(Context, new AmIStorageAccessor(Storage));
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIStorageAccessor.cs b/Ryujinx/OsHle/Objects/AmIStorageAccessor.cs
new file mode 100644
index 00000000..62007ef8
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIStorageAccessor.cs
@@ -0,0 +1,56 @@
+using ChocolArm64.Memory;
+using System;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIStorageAccessor
+ {
+ public AmIStorage Storage { get; private set; }
+
+ public AmIStorageAccessor(AmIStorage Storage)
+ {
+ this.Storage = Storage;
+ }
+
+ public static long GetSize(ServiceCtx Context)
+ {
+ AmIStorageAccessor Accessor = Context.GetObject<AmIStorageAccessor>();
+
+ Context.ResponseData.Write((long)Accessor.Storage.Data.Length);
+
+ return 0;
+ }
+
+ public static long Read(ServiceCtx Context)
+ {
+ AmIStorageAccessor Accessor = Context.GetObject<AmIStorageAccessor>();
+
+ AmIStorage Storage = Accessor.Storage;
+
+ long ReadPosition = Context.RequestData.ReadInt64();
+
+ if (Context.Request.RecvListBuff.Count > 0)
+ {
+ long Position = Context.Request.RecvListBuff[0].Position;
+ short Size = Context.Request.RecvListBuff[0].Size;
+
+ byte[] Data;
+
+ if (Storage.Data.Length > Size)
+ {
+ Data = new byte[Size];
+
+ Buffer.BlockCopy(Storage.Data, 0, Data, 0, Size);
+ }
+ else
+ {
+ Data = Storage.Data;
+ }
+
+ AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
+ }
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AmIWindowController.cs b/Ryujinx/OsHle/Objects/AmIWindowController.cs
new file mode 100644
index 00000000..ea967ae8
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AmIWindowController.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AmIWindowController
+ {
+ public static long GetAppletResourceUserId(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(0L);
+
+ return 0;
+ }
+
+ public static long AcquireForegroundRights(ServiceCtx Context)
+ {
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/ApmISession.cs b/Ryujinx/OsHle/Objects/ApmISession.cs
new file mode 100644
index 00000000..2b2c0351
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/ApmISession.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class ApmISession
+ {
+ public static long SetPerformanceConfiguration(ServiceCtx Context)
+ {
+ int PerfMode = Context.RequestData.ReadInt32();
+ int PerfConfig = Context.RequestData.ReadInt32();
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs b/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
new file mode 100644
index 00000000..b451d07b
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/AudIAudioRenderer.cs
@@ -0,0 +1,36 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class AudIAudioRenderer
+ {
+ public static long RequestUpdateAudioRenderer(ServiceCtx Context)
+ {
+ long Position = Context.Request.ReceiveBuff[0].Position;
+
+ //0x40 bytes header
+ Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section)
+ Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size?
+ Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size?
+ Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size?
+ Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size?
+ Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size?
+ Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header)
+
+ for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10)
+ {
+ Context.Memory.WriteInt32(Position + Offset, 5);
+ }
+
+ return 0;
+ }
+
+ public static long StartAudioRenderer(ServiceCtx Context)
+ {
+ return 0;
+ }
+
+ public static long QuerySystemEvent(ServiceCtx Context)
+ {
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/FriendIFriendService.cs b/Ryujinx/OsHle/Objects/FriendIFriendService.cs
new file mode 100644
index 00000000..9a39380a
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/FriendIFriendService.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class FriendIFriendService
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/FspSrvIFile.cs b/Ryujinx/OsHle/Objects/FspSrvIFile.cs
new file mode 100644
index 00000000..4b9f8c37
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/FspSrvIFile.cs
@@ -0,0 +1,72 @@
+using ChocolArm64.Memory;
+using System;
+
+using System.IO;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class FspSrvIFile : IDisposable
+ {
+ public Stream BaseStream { get; private set; }
+
+ public FspSrvIFile(Stream BaseStream)
+ {
+ this.BaseStream = BaseStream;
+ }
+
+ public static long Read(ServiceCtx Context)
+ {
+ FspSrvIFile File = Context.GetObject<FspSrvIFile>();
+
+ long Position = Context.Request.ReceiveBuff[0].Position;
+
+ long Zero = Context.RequestData.ReadInt64();
+ long Offset = Context.RequestData.ReadInt64();
+ long Size = Context.RequestData.ReadInt64();
+
+ byte[] Data = new byte[Size];
+
+ int ReadSize = File.BaseStream.Read(Data, 0, (int)Size);
+
+ AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
+
+ //TODO: Use ReadSize, we need to return the size that was REALLY read from the file.
+ //This is a workaround because we are doing something wrong and the game expects to read
+ //data from a file that doesn't yet exists -- and breaks if it can't read anything.
+ Context.ResponseData.Write((long)Size);
+
+ return 0;
+ }
+
+ public static long Write(ServiceCtx Context)
+ {
+ FspSrvIFile File = Context.GetObject<FspSrvIFile>();
+
+ long Position = Context.Request.SendBuff[0].Position;
+
+ long Zero = Context.RequestData.ReadInt64();
+ long Offset = Context.RequestData.ReadInt64();
+ long Size = Context.RequestData.ReadInt64();
+
+ byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)Size);
+
+ File.BaseStream.Seek(Offset, SeekOrigin.Begin);
+ File.BaseStream.Write(Data, 0, (int)Size);
+
+ return 0;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && BaseStream != null)
+ {
+ BaseStream.Dispose();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/FspSrvIFileSystem.cs b/Ryujinx/OsHle/Objects/FspSrvIFileSystem.cs
new file mode 100644
index 00000000..fed1c55a
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/FspSrvIFileSystem.cs
@@ -0,0 +1,70 @@
+using ChocolArm64.Memory;
+using System.IO;
+
+using static Ryujinx.OsHle.Objects.ObjHelper;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class FspSrvIFileSystem
+ {
+ public string FilePath { get; private set; }
+
+ public FspSrvIFileSystem(string Path)
+ {
+ this.FilePath = Path;
+ }
+
+ public static long GetEntryType(ServiceCtx Context)
+ {
+ FspSrvIFileSystem FileSystem = Context.GetObject<FspSrvIFileSystem>();
+
+ long Position = Context.Request.PtrBuff[0].Position;
+
+ string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
+
+ string FileName = Context.Ns.VFs.GetFullPath(FileSystem.FilePath, Name);
+
+ if (FileName == null)
+ {
+ //TODO: Correct error code.
+ return -1;
+ }
+
+ bool IsFile = File.Exists(FileName);
+
+ Context.ResponseData.Write(IsFile ? 1 : 0);
+
+ return 0;
+ }
+
+ public static long OpenFile(ServiceCtx Context)
+ {
+ FspSrvIFileSystem FileSystem = Context.GetObject<FspSrvIFileSystem>();
+
+ long Position = Context.Request.PtrBuff[0].Position;
+
+ int FilterFlags = Context.RequestData.ReadInt32();
+
+ string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
+
+ string FileName = Context.Ns.VFs.GetFullPath(FileSystem.FilePath, Name);
+
+ if (FileName == null)
+ {
+ //TODO: Correct error code.
+ return -1;
+ }
+
+ FileStream Stream = new FileStream(FileName, FileMode.OpenOrCreate);
+
+ MakeObject(Context, new FspSrvIFile(Stream));
+
+ return 0;
+ }
+
+ public static long Commit(ServiceCtx Context)
+ {
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/FspSrvIStorage.cs b/Ryujinx/OsHle/Objects/FspSrvIStorage.cs
new file mode 100644
index 00000000..76ad8917
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/FspSrvIStorage.cs
@@ -0,0 +1,44 @@
+using ChocolArm64.Memory;
+using Ryujinx.OsHle.Ipc;
+using System.IO;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class FspSrvIStorage
+ {
+ public Stream BaseStream { get; private set; }
+
+ public FspSrvIStorage(Stream BaseStream)
+ {
+ this.BaseStream = BaseStream;
+ }
+
+ public static long Read(ServiceCtx Context)
+ {
+ FspSrvIStorage Storage = Context.GetObject<FspSrvIStorage>();
+
+ long Offset = Context.RequestData.ReadInt64();
+ long Size = Context.RequestData.ReadInt64();
+
+ if (Context.Request.ReceiveBuff.Count > 0)
+ {
+ IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0];
+
+ //Use smaller length to avoid overflows.
+ if (Size > BuffDesc.Size)
+ {
+ Size = BuffDesc.Size;
+ }
+
+ byte[] Data = new byte[Size];
+
+ Storage.BaseStream.Seek(Offset, SeekOrigin.Begin);
+ Storage.BaseStream.Read(Data, 0, Data.Length);
+
+ AMemoryHelper.WriteBytes(Context.Memory, BuffDesc.Position, Data);
+ }
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/HidIAppletResource.cs b/Ryujinx/OsHle/Objects/HidIAppletResource.cs
new file mode 100644
index 00000000..73b948df
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/HidIAppletResource.cs
@@ -0,0 +1,22 @@
+using Ryujinx.OsHle.Handles;
+using Ryujinx.OsHle.Ipc;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class HidIAppletResource
+ {
+ public HSharedMem Handle;
+
+ public HidIAppletResource(HSharedMem Handle)
+ {
+ this.Handle = Handle;
+ }
+
+ public static long GetSharedMemoryHandle(ServiceCtx Context)
+ {
+ Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/ObjHelper.cs b/Ryujinx/OsHle/Objects/ObjHelper.cs
new file mode 100644
index 00000000..e37f5320
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/ObjHelper.cs
@@ -0,0 +1,24 @@
+using Ryujinx.OsHle.Handles;
+using Ryujinx.OsHle.Ipc;
+
+namespace Ryujinx.OsHle.Objects
+{
+ static class ObjHelper
+ {
+ public static void MakeObject(ServiceCtx Context, object Obj)
+ {
+ if (Context.Session is HDomain Dom)
+ {
+ Context.Response.ResponseObjIds.Add(Dom.GenertateObjectId(Obj));
+ }
+ else
+ {
+ HSessionObj HndData = new HSessionObj(Context.Session, Obj);
+
+ int VHandle = Context.Ns.Os.Handles.GenerateId(HndData);
+
+ Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/Parcel.cs b/Ryujinx/OsHle/Objects/Parcel.cs
new file mode 100644
index 00000000..0d322bab
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/Parcel.cs
@@ -0,0 +1,58 @@
+using System;
+using System.IO;
+
+namespace Ryujinx.OsHle.Objects.Android
+{
+ static class Parcel
+ {
+ public static byte[] GetParcelData(byte[] Parcel)
+ {
+ if (Parcel == null)
+ {
+ throw new ArgumentNullException(nameof(Parcel));
+ }
+
+ using (MemoryStream MS = new MemoryStream(Parcel))
+ {
+ BinaryReader Reader = new BinaryReader(MS);
+
+ int DataSize = Reader.ReadInt32();
+ int DataOffset = Reader.ReadInt32();
+ int ObjsSize = Reader.ReadInt32();
+ int ObjsOffset = Reader.ReadInt32();
+
+ MS.Seek(DataOffset - 0x10, SeekOrigin.Current);
+
+ return Reader.ReadBytes(DataSize);
+ }
+ }
+
+ public static byte[] MakeParcel(byte[] Data, byte[] Objs)
+ {
+ if (Data == null)
+ {
+ throw new ArgumentNullException(nameof(Data));
+ }
+
+ if (Objs == null)
+ {
+ throw new ArgumentNullException(nameof(Objs));
+ }
+
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ Writer.Write(Data.Length);
+ Writer.Write(0x10);
+ Writer.Write(Objs.Length);
+ Writer.Write(Data.Length + 0x10);
+
+ Writer.Write(Data);
+ Writer.Write(Objs);
+
+ return MS.ToArray();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/TimeISteadyClock.cs b/Ryujinx/OsHle/Objects/TimeISteadyClock.cs
new file mode 100644
index 00000000..ead8c41a
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/TimeISteadyClock.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class TimeISteadyClock
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/TimeISystemClock.cs b/Ryujinx/OsHle/Objects/TimeISystemClock.cs
new file mode 100644
index 00000000..d9a3a073
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/TimeISystemClock.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class TimeISystemClock
+ {
+ private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ public static long GetCurrentTime(ServiceCtx Context)
+ {
+ Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/TimeITimeZoneService.cs b/Ryujinx/OsHle/Objects/TimeITimeZoneService.cs
new file mode 100644
index 00000000..af5490a6
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/TimeITimeZoneService.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class TimeITimeZoneService
+ {
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs b/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs
new file mode 100644
index 00000000..81616ae1
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/ViIApplicationDisplayService.cs
@@ -0,0 +1,148 @@
+using ChocolArm64.Memory;
+using Ryujinx.OsHle.Handles;
+using Ryujinx.OsHle.Ipc;
+using System.IO;
+
+using static Ryujinx.OsHle.Objects.Android.Parcel;
+using static Ryujinx.OsHle.Objects.ObjHelper;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class ViIApplicationDisplayService
+ {
+ public static long GetRelayService(ServiceCtx Context)
+ {
+ MakeObject(Context, new ViIHOSBinderDriver());
+
+ return 0;
+ }
+
+ public static long GetSystemDisplayService(ServiceCtx Context)
+ {
+ MakeObject(Context, new ViISystemDisplayService());
+
+ return 0;
+ }
+
+ public static long GetManagerDisplayService(ServiceCtx Context)
+ {
+ MakeObject(Context, new ViIManagerDisplayService());
+
+ return 0;
+ }
+
+ public static long OpenDisplay(ServiceCtx Context)
+ {
+ string Name = GetDisplayName(Context);
+
+ long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name));
+
+ Context.ResponseData.Write(DisplayId);
+
+ return 0;
+ }
+
+ public static long OpenLayer(ServiceCtx Context)
+ {
+ long LayerId = Context.RequestData.ReadInt64();
+ long UserId = Context.RequestData.ReadInt64();
+
+ long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
+
+ byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
+
+ AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel);
+
+ Context.ResponseData.Write((long)Parcel.Length);
+
+ return 0;
+ }
+
+ public static long CreateStrayLayer(ServiceCtx Context)
+ {
+ long LayerFlags = Context.RequestData.ReadInt64();
+ long DisplayId = Context.RequestData.ReadInt64();
+
+ long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
+
+ Display Disp = Context.Ns.Os.Displays.GetData<Display>((int)DisplayId);
+
+ byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
+
+ AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel);
+
+ Context.ResponseData.Write(0L);
+ Context.ResponseData.Write((long)Parcel.Length);
+
+ return 0;
+ }
+
+ public static long SetLayerScalingMode(ServiceCtx Context)
+ {
+ int ScalingMode = Context.RequestData.ReadInt32();
+ long Unknown = Context.RequestData.ReadInt64();
+
+ return 0;
+ }
+
+ public static long GetDisplayVSyncEvent(ServiceCtx Context)
+ {
+ string Name = GetDisplayName(Context);
+
+ int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+
+ Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
+
+ return 0;
+ }
+
+ private static byte[] MakeIGraphicsBufferProducer(long BasePtr)
+ {
+ long Id = 0x20;
+ long CookiePtr = 0L;
+
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ //flat_binder_object (size is 0x28)
+ Writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER)
+ Writer.Write(0); //Flags
+ Writer.Write((int)(Id >> 0));
+ Writer.Write((int)(Id >> 32));
+ Writer.Write((int)(CookiePtr >> 0));
+ Writer.Write((int)(CookiePtr >> 32));
+ Writer.Write((byte)'d');
+ Writer.Write((byte)'i');
+ Writer.Write((byte)'s');
+ Writer.Write((byte)'p');
+ Writer.Write((byte)'d');
+ Writer.Write((byte)'r');
+ Writer.Write((byte)'v');
+ Writer.Write((byte)'\0');
+ Writer.Write(0L); //Pad
+
+ return MakeParcel(MS.ToArray(), new byte[] { 0, 0, 0, 0 });
+ }
+ }
+
+ private static string GetDisplayName(ServiceCtx Context)
+ {
+ string Name = string.Empty;
+
+ for (int Index = 0; Index < 8 &&
+ Context.RequestData.BaseStream.Position <
+ Context.RequestData.BaseStream.Length; Index++)
+ {
+ byte Chr = Context.RequestData.ReadByte();
+
+ if (Chr >= 0x20 && Chr < 0x7f)
+ {
+ Name += (char)Chr;
+ }
+ }
+
+ return Name;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/ViIHOSBinderDriver.cs b/Ryujinx/OsHle/Objects/ViIHOSBinderDriver.cs
new file mode 100644
index 00000000..72a472ae
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/ViIHOSBinderDriver.cs
@@ -0,0 +1,211 @@
+using ChocolArm64.Memory;
+using Ryujinx.OsHle.Handles;
+using Ryujinx.OsHle.Ipc;
+using Ryujinx.OsHle.Utilities;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+using static Ryujinx.OsHle.Objects.Android.Parcel;
+
+namespace Ryujinx.OsHle.Objects
+{
+ class ViIHOSBinderDriver
+ {
+ private delegate long ServiceProcessRequest(ServiceCtx Context, byte[] ParcelData);
+
+ private static Dictionary<(string, int), ServiceProcessRequest> InterfaceMthd =
+ new Dictionary<(string, int), ServiceProcessRequest>()
+ {
+ { ("android.gui.IGraphicBufferProducer", 0x1), GraphicBufferProducerRequestBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x3), GraphicBufferProducerDequeueBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x7), GraphicBufferProducerQueueBuffer },
+ //{ ("android.gui.IGraphicBufferProducer", 0x8), GraphicBufferProducerCancelBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x9), GraphicBufferProducerQuery },
+ { ("android.gui.IGraphicBufferProducer", 0xa), GraphicBufferProducerConnect },
+ { ("android.gui.IGraphicBufferProducer", 0xe), GraphicBufferPreallocateBuffer },
+ };
+
+ private class BufferObj
+ {
+
+ }
+
+ public IdPoolWithObj BufferSlots { get; private set; }
+
+ public byte[] Gbfr;
+
+ public ViIHOSBinderDriver()
+ {
+ BufferSlots = new IdPoolWithObj();
+ }
+
+ public static long TransactParcel(ServiceCtx Context)
+ {
+ int Id = Context.RequestData.ReadInt32();
+ int Code = Context.RequestData.ReadInt32();
+
+ long DataPos = Context.Request.SendBuff[0].Position;
+ long DataSize = Context.Request.SendBuff[0].Size;
+
+ byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)DataSize);
+
+ Data = GetParcelData(Data);
+
+ using (MemoryStream MS = new MemoryStream(Data))
+ {
+ BinaryReader Reader = new BinaryReader(MS);
+
+ MS.Seek(4, SeekOrigin.Current);
+
+ int StrSize = Reader.ReadInt32();
+
+ string InterfaceName = Encoding.Unicode.GetString(Data, 8, StrSize * 2);
+
+ if (InterfaceMthd.TryGetValue((InterfaceName, Code), out ServiceProcessRequest ProcReq))
+ {
+ return ProcReq(Context, Data);
+ }
+ else
+ {
+ throw new NotImplementedException($"{InterfaceName} {Code}");
+ }
+ }
+ }
+
+ private static long GraphicBufferProducerRequestBuffer(ServiceCtx Context, byte[] ParcelData)
+ {
+ ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
+
+ int GbfrSize = BinderDriver.Gbfr?.Length ?? 0;
+
+ byte[] Data = new byte[GbfrSize + 4];
+
+ if (BinderDriver.Gbfr != null)
+ {
+ Buffer.BlockCopy(BinderDriver.Gbfr, 0, Data, 0, GbfrSize);
+ }
+
+ return MakeReplyParcel(Context, Data);
+ }
+
+ private static long GraphicBufferProducerDequeueBuffer(ServiceCtx Context, byte[] ParcelData)
+ {
+ ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
+
+ //Note: It seems that the maximum number of slots is 64, because if we return
+ //a Slot number > 63, it seems to cause a buffer overrun and it reads garbage.
+ //Note 2: The size of each object associated with the slot is 0x30.
+ int Slot = BinderDriver.BufferSlots.GenerateId(new BufferObj());
+
+ return MakeReplyParcel(Context, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ private static long GraphicBufferProducerQueueBuffer(ServiceCtx Context, byte[] ParcelData)
+ {
+ return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
+ }
+
+ private static long GraphicBufferProducerCancelBuffer(ServiceCtx Context, byte[] ParcelData)
+ {
+ ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
+
+ using (MemoryStream MS = new MemoryStream(ParcelData))
+ {
+ BinaryReader Reader = new BinaryReader(MS);
+
+ MS.Seek(0x50, SeekOrigin.Begin);
+
+ int Slot = Reader.ReadInt32();
+
+ BinderDriver.BufferSlots.Delete(Slot);
+
+ return MakeReplyParcel(Context, 0);
+ }
+ }
+
+ private static long GraphicBufferProducerQuery(ServiceCtx Context, byte[] ParcelData)
+ {
+ return MakeReplyParcel(Context, 0, 0);
+ }
+
+ private static long GraphicBufferProducerConnect(ServiceCtx Context, byte[] ParcelData)
+ {
+ return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
+ }
+
+ private static long GraphicBufferPreallocateBuffer(ServiceCtx Context, byte[] ParcelData)
+ {
+ ViIHOSBinderDriver BinderDriver = Context.GetObject<ViIHOSBinderDriver>();
+
+ int GbfrSize = ParcelData.Length - 0x54;
+
+ BinderDriver.Gbfr = new byte[GbfrSize];
+
+ Buffer.BlockCopy(ParcelData, 0x54, BinderDriver.Gbfr, 0, GbfrSize);
+
+ using (MemoryStream MS = new MemoryStream(ParcelData))
+ {
+ BinaryReader Reader = new BinaryReader(MS);
+
+ MS.Seek(0xd4, SeekOrigin.Begin);
+
+ int Handle = Reader.ReadInt32();
+
+ HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+
+ Context.Ns.Gpu.Renderer.FrameBufferPtr =
+ Context.Memory.Manager.GetPhys(NvMap.Address, AMemoryPerm.Read);
+ }
+
+ return MakeReplyParcel(Context, 0);
+ }
+
+ private static long MakeReplyParcel(ServiceCtx Context, params int[] Ints)
+ {
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ foreach (int Int in Ints)
+ {
+ Writer.Write(Int);
+ }
+
+ return MakeReplyParcel(Context, MS.ToArray());
+ }
+ }
+
+ private static long MakeReplyParcel(ServiceCtx Context, byte[] Data)
+ {
+ long ReplyPos = Context.Request.ReceiveBuff[0].Position;
+ long ReplySize = Context.Request.ReceiveBuff[0].Position;
+
+ byte[] Reply = MakeParcel(Data, new byte[0]);
+
+ AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply);
+
+ return 0;
+ }
+
+ public static long AdjustRefcount(ServiceCtx Context)
+ {
+ int Id = Context.RequestData.ReadInt32();
+ int AddVal = Context.RequestData.ReadInt32();
+ int Type = Context.RequestData.ReadInt32();
+
+ return 0;
+ }
+
+ public static long GetNativeHandle(ServiceCtx Context)
+ {
+ int Id = Context.RequestData.ReadInt32();
+ uint Unk = Context.RequestData.ReadUInt32();
+
+ Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/ViIManagerDisplayService.cs b/Ryujinx/OsHle/Objects/ViIManagerDisplayService.cs
new file mode 100644
index 00000000..0fdca3ba
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/ViIManagerDisplayService.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class ViIManagerDisplayService
+ {
+ public static long CreateManagedLayer(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(0L); //LayerId
+
+ return 0;
+ }
+
+ public static long AddToLayerStack(ServiceCtx Context)
+ {
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/OsHle/Objects/ViISystemDisplayService.cs b/Ryujinx/OsHle/Objects/ViISystemDisplayService.cs
new file mode 100644
index 00000000..8d3a51f4
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/ViISystemDisplayService.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.OsHle.Objects
+{
+ class ViISystemDisplayService
+ {
+ public static long SetLayerZ(ServiceCtx Context)
+ {
+ return 0;
+ }
+ }
+} \ No newline at end of file