aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-04-22 01:21:49 -0300
committergdkchan <gab.dark.100@gmail.com>2018-04-22 01:22:46 -0300
commitbd9b1e2c6b912c7cdab55ec6acc063c88a59cff1 (patch)
tree077ab8da47828f9fd23893eeefa54c7d8fb2a314
parent4906acdde96c09b4e12a3801a4bacd5233a2f8e6 (diff)
Stub a few services, add support for generating call stacks on the CPU
-rw-r--r--ChocolArm64/AOptimizations.cs2
-rw-r--r--ChocolArm64/Instruction/AInstEmitException.cs12
-rw-r--r--ChocolArm64/Instruction/AInstEmitFlow.cs31
-rw-r--r--ChocolArm64/State/AThreadState.cs30
-rw-r--r--ChocolArm64/Translation/AILEmitterCtx.cs15
-rw-r--r--Ryujinx.Core/Loaders/Executable.cs8
-rw-r--r--Ryujinx.Core/Loaders/Executables/IExecutable.cs2
-rw-r--r--Ryujinx.Core/Loaders/Executables/Nro.cs6
-rw-r--r--Ryujinx.Core/Loaders/Executables/Nso.cs6
-rw-r--r--Ryujinx.Core/LogClass.cs1
-rw-r--r--Ryujinx.Core/OsHle/Horizon.cs10
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThread.cs8
-rw-r--r--Ryujinx.Core/OsHle/Process.cs79
-rw-r--r--Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs10
-rw-r--r--Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs (renamed from Ryujinx.Core/OsHle/Services/Aud/IAudioDeviceService.cs)19
-rw-r--r--Ryujinx.Core/OsHle/Services/Aud/IAudioRendererManager.cs2
-rw-r--r--Ryujinx.Core/OsHle/Services/Caps/IAlbumAccessorService.cs20
-rw-r--r--Ryujinx.Core/OsHle/Services/Caps/IScreenshotService.cs20
-rw-r--r--Ryujinx.Core/OsHle/Services/ServiceFactory.cs10
-rw-r--r--Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs15
20 files changed, 266 insertions, 40 deletions
diff --git a/ChocolArm64/AOptimizations.cs b/ChocolArm64/AOptimizations.cs
index a3c82dcc..2627c236 100644
--- a/ChocolArm64/AOptimizations.cs
+++ b/ChocolArm64/AOptimizations.cs
@@ -1,4 +1,6 @@
public static class AOptimizations
{
public static bool DisableMemoryChecks = false;
+
+ public static bool GenerateCallStack = true;
} \ No newline at end of file
diff --git a/ChocolArm64/Instruction/AInstEmitException.cs b/ChocolArm64/Instruction/AInstEmitException.cs
index 3964c949..041e2890 100644
--- a/ChocolArm64/Instruction/AInstEmitException.cs
+++ b/ChocolArm64/Instruction/AInstEmitException.cs
@@ -8,8 +8,6 @@ namespace ChocolArm64.Instruction
{
static partial class AInstEmit
{
- private const BindingFlags Binding = BindingFlags.NonPublic | BindingFlags.Instance;
-
public static void Brk(AILEmitterCtx Context)
{
EmitExceptionCall(Context, nameof(AThreadState.OnBreak));
@@ -30,9 +28,7 @@ namespace ChocolArm64.Instruction
Context.EmitLdc_I4(Op.Id);
- MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding);
-
- Context.EmitCall(MthdInfo);
+ Context.EmitPrivateCall(typeof(AThreadState), MthdName);
//Check if the thread should still be running, if it isn't then we return 0
//to force a return to the dispatcher and then exit the thread.
@@ -73,11 +69,7 @@ namespace ChocolArm64.Instruction
Context.EmitLdc_I8(Op.Position);
Context.EmitLdc_I4(Op.RawOpCode);
- string MthdName = nameof(AThreadState.OnUndefined);
-
- MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding);
-
- Context.EmitCall(MthdInfo);
+ Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.OnUndefined));
if (Context.CurrBlock.Next != null)
{
diff --git a/ChocolArm64/Instruction/AInstEmitFlow.cs b/ChocolArm64/Instruction/AInstEmitFlow.cs
index 91262834..89979d05 100644
--- a/ChocolArm64/Instruction/AInstEmitFlow.cs
+++ b/ChocolArm64/Instruction/AInstEmitFlow.cs
@@ -35,6 +35,14 @@ namespace ChocolArm64.Instruction
{
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
+ if (AOptimizations.GenerateCallStack)
+ {
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+ Context.EmitLdc_I8(Op.Imm);
+
+ Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.EnterMethod));
+ }
+
Context.EmitLdc_I(Op.Position + 4);
Context.EmitStint(AThreadState.LRIndex);
Context.EmitStoreState();
@@ -72,6 +80,14 @@ namespace ChocolArm64.Instruction
{
AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp;
+ if (AOptimizations.GenerateCallStack)
+ {
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+ Context.EmitLdintzr(Op.Rn);
+
+ Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.EnterMethod));
+ }
+
Context.EmitLdc_I(Op.Position + 4);
Context.EmitStint(AThreadState.LRIndex);
Context.EmitStoreState();
@@ -84,6 +100,14 @@ namespace ChocolArm64.Instruction
{
AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp;
+ if (AOptimizations.GenerateCallStack)
+ {
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+ Context.EmitLdintzr(Op.Rn);
+
+ Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.JumpMethod));
+ }
+
Context.EmitStoreState();
Context.EmitLdintzr(Op.Rn);
@@ -105,6 +129,13 @@ namespace ChocolArm64.Instruction
public static void Ret(AILEmitterCtx Context)
{
+ if (AOptimizations.GenerateCallStack)
+ {
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
+ Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.ExitMethod));
+ }
+
Context.EmitStoreState();
Context.EmitLdint(AThreadState.LRIndex);
diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs
index 6f3f62f6..ce127886 100644
--- a/ChocolArm64/State/AThreadState.cs
+++ b/ChocolArm64/State/AThreadState.cs
@@ -1,5 +1,6 @@
using ChocolArm64.Events;
using System;
+using System.Collections.Generic;
using System.Diagnostics;
namespace ChocolArm64.State
@@ -56,10 +57,17 @@ namespace ChocolArm64.State
public event EventHandler<AInstExceptionEventArgs> SvcCall;
public event EventHandler<AInstUndefinedEventArgs> Undefined;
+ private Stack<long> CallStack;
+
private static Stopwatch TickCounter;
private static double HostTickFreq;
+ public AThreadState()
+ {
+ CallStack = new Stack<long>();
+ }
+
static AThreadState()
{
HostTickFreq = 1.0 / Stopwatch.Frequency;
@@ -83,5 +91,27 @@ namespace ChocolArm64.State
{
Undefined?.Invoke(this, new AInstUndefinedEventArgs(Position, RawOpCode));
}
+
+ internal void EnterMethod(long Position)
+ {
+ CallStack.Push(Position);
+ }
+
+ internal void ExitMethod()
+ {
+ CallStack.TryPop(out _);
+ }
+
+ internal void JumpMethod(long Position)
+ {
+ CallStack.TryPop(out _);
+
+ CallStack.Push(Position);
+ }
+
+ public long[] GetCallStack()
+ {
+ return CallStack.ToArray();
+ }
}
} \ No newline at end of file
diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs
index 2f4a67e1..a004a966 100644
--- a/ChocolArm64/Translation/AILEmitterCtx.cs
+++ b/ChocolArm64/Translation/AILEmitterCtx.cs
@@ -461,6 +461,21 @@ namespace ChocolArm64.Translation
EmitCall(ObjType.GetMethod(MthdName));
}
+ public void EmitPrivateCall(Type ObjType, string MthdName)
+ {
+ if (ObjType == null)
+ {
+ throw new ArgumentNullException(nameof(ObjType));
+ }
+
+ if (MthdName == null)
+ {
+ throw new ArgumentNullException(nameof(MthdName));
+ }
+
+ EmitCall(ObjType.GetMethod(MthdName, BindingFlags.Instance | BindingFlags.NonPublic));
+ }
+
public void EmitCall(MethodInfo MthdInfo)
{
if (MthdInfo == null)
diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs
index 943b8e51..39ee9618 100644
--- a/Ryujinx.Core/Loaders/Executable.cs
+++ b/Ryujinx.Core/Loaders/Executable.cs
@@ -7,14 +7,16 @@ namespace Ryujinx.Core.Loaders
{
class Executable
{
- private AMemory Memory;
-
private List<ElfDyn> Dynamic;
private Dictionary<long, string> m_SymbolTable;
public IReadOnlyDictionary<long, string> SymbolTable => m_SymbolTable;
+ public string Name { get; private set; }
+
+ private AMemory Memory;
+
public long ImageBase { get; private set; }
public long ImageEnd { get; private set; }
@@ -24,6 +26,8 @@ namespace Ryujinx.Core.Loaders
m_SymbolTable = new Dictionary<long, string>();
+ Name = Exe.Name;
+
this.Memory = Memory;
this.ImageBase = ImageBase;
this.ImageEnd = ImageBase;
diff --git a/Ryujinx.Core/Loaders/Executables/IExecutable.cs b/Ryujinx.Core/Loaders/Executables/IExecutable.cs
index 09d0aab2..412058d8 100644
--- a/Ryujinx.Core/Loaders/Executables/IExecutable.cs
+++ b/Ryujinx.Core/Loaders/Executables/IExecutable.cs
@@ -2,6 +2,8 @@ namespace Ryujinx.Core.Loaders.Executables
{
public interface IExecutable
{
+ string Name { get; }
+
byte[] Text { get; }
byte[] RO { get; }
byte[] Data { get; }
diff --git a/Ryujinx.Core/Loaders/Executables/Nro.cs b/Ryujinx.Core/Loaders/Executables/Nro.cs
index 9f4ef59f..c3411d22 100644
--- a/Ryujinx.Core/Loaders/Executables/Nro.cs
+++ b/Ryujinx.Core/Loaders/Executables/Nro.cs
@@ -4,6 +4,8 @@ namespace Ryujinx.Core.Loaders.Executables
{
class Nro : IExecutable
{
+ public string Name { get; private set; }
+
public byte[] Text { get; private set; }
public byte[] RO { get; private set; }
public byte[] Data { get; private set; }
@@ -14,8 +16,10 @@ namespace Ryujinx.Core.Loaders.Executables
public int DataOffset { get; private set; }
public int BssSize { get; private set; }
- public Nro(Stream Input)
+ public Nro(Stream Input, string Name)
{
+ this.Name = Name;
+
BinaryReader Reader = new BinaryReader(Input);
Input.Seek(4, SeekOrigin.Begin);
diff --git a/Ryujinx.Core/Loaders/Executables/Nso.cs b/Ryujinx.Core/Loaders/Executables/Nso.cs
index 7341ba62..bfe159d7 100644
--- a/Ryujinx.Core/Loaders/Executables/Nso.cs
+++ b/Ryujinx.Core/Loaders/Executables/Nso.cs
@@ -6,6 +6,8 @@ namespace Ryujinx.Core.Loaders.Executables
{
class Nso : IExecutable
{
+ public string Name { get; private set; }
+
public byte[] Text { get; private set; }
public byte[] RO { get; private set; }
public byte[] Data { get; private set; }
@@ -27,8 +29,10 @@ namespace Ryujinx.Core.Loaders.Executables
HasDataHash = 1 << 5
}
- public Nso(Stream Input)
+ public Nso(Stream Input, string Name)
{
+ this.Name = Name;
+
BinaryReader Reader = new BinaryReader(Input);
Input.Seek(0, SeekOrigin.Begin);
diff --git a/Ryujinx.Core/LogClass.cs b/Ryujinx.Core/LogClass.cs
index 60a8de78..014b5732 100644
--- a/Ryujinx.Core/LogClass.cs
+++ b/Ryujinx.Core/LogClass.cs
@@ -16,6 +16,7 @@
ServiceApm,
ServiceAudio,
ServiceBsd,
+ ServiceCaps,
ServiceFriend,
ServiceFs,
ServiceHid,
diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs
index 9e113080..6c625b09 100644
--- a/Ryujinx.Core/OsHle/Horizon.cs
+++ b/Ryujinx.Core/OsHle/Horizon.cs
@@ -58,7 +58,9 @@ namespace Ryujinx.Core.OsHle
using (FileStream Input = new FileStream(File, FileMode.Open))
{
- Nso Program = new Nso(Input);
+ string Name = Path.GetFileNameWithoutExtension(File);
+
+ Nso Program = new Nso(Input, Name);
MainProcess.LoadProgram(Program);
}
@@ -80,13 +82,15 @@ namespace Ryujinx.Core.OsHle
{
bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
+ string Name = Path.GetFileNameWithoutExtension(FileName);
+
Process MainProcess = MakeProcess();
using (FileStream Input = new FileStream(FileName, FileMode.Open))
{
MainProcess.LoadProgram(IsNro
- ? (IExecutable)new Nro(Input)
- : (IExecutable)new Nso(Input));
+ ? (IExecutable)new Nro(Input, Name)
+ : (IExecutable)new Nso(Input, Name));
}
MainProcess.SetEmptyArgs();
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
index 1e4d61b4..e1300b73 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
@@ -156,13 +156,13 @@ namespace Ryujinx.Core.OsHle.Kernel
private void SvcSetThreadActivity(AThreadState ThreadState)
{
int Handle = (int)ThreadState.X0;
- bool Active = (int)ThreadState.X1 != 0;
+ bool Active = (int)ThreadState.X1 == 0;
- KThread CurrThread = Process.HandleTable.GetData<KThread>(Handle);
+ KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
- if (CurrThread != null)
+ if (Thread != null)
{
- Process.Scheduler.SetThreadActivity(CurrThread, Active);
+ Process.Scheduler.SetThreadActivity(Thread, Active);
ThreadState.X0 = 0;
}
diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs
index bd4ff1ff..0f8c726c 100644
--- a/Ryujinx.Core/OsHle/Process.cs
+++ b/Ryujinx.Core/OsHle/Process.cs
@@ -1,6 +1,7 @@
using ChocolArm64;
using ChocolArm64.Events;
using ChocolArm64.Memory;
+using ChocolArm64.State;
using Ryujinx.Core.Loaders;
using Ryujinx.Core.Loaders.Executables;
using Ryujinx.Core.OsHle.Exceptions;
@@ -10,6 +11,7 @@ using Ryujinx.Core.OsHle.Services.Nv;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Text;
namespace Ryujinx.Core.OsHle
{
@@ -47,9 +49,11 @@ namespace Ryujinx.Core.OsHle
private ConcurrentDictionary<long, KThread> Threads;
+ private KThread MainThread;
+
private List<Executable> Executables;
- private KThread MainThread;
+ private Dictionary<long, string> SymbolTable;
private long ImageBase;
@@ -121,6 +125,8 @@ namespace Ryujinx.Core.OsHle
return false;
}
+ MakeSymbolTable();
+
MapRWMemRegion(
MemoryRegions.MainStackAddress,
MemoryRegions.MainStackSize,
@@ -227,20 +233,23 @@ namespace Ryujinx.Core.OsHle
throw new UndefinedInstructionException(e.Position, e.RawOpCode);
}
- private ATranslator GetTranslator()
+ private void MakeSymbolTable()
{
- if (Translator == null)
- {
- Dictionary<long, string> SymbolTable = new Dictionary<long, string>();
+ SymbolTable = new Dictionary<long, string>();
- foreach (Executable Exe in Executables)
+ foreach (Executable Exe in Executables)
+ {
+ foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
{
- foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
- {
- SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
- }
+ SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
}
+ }
+ }
+ private ATranslator GetTranslator()
+ {
+ if (Translator == null)
+ {
Translator = new ATranslator(SymbolTable);
Translator.CpuTrace += CpuTraceHandler;
@@ -249,6 +258,16 @@ namespace Ryujinx.Core.OsHle
return Translator;
}
+ public void EnableCpuTracing()
+ {
+ Translator.EnableCpuTrace = true;
+ }
+
+ public void DisableCpuTracing()
+ {
+ Translator.EnableCpuTrace = false;
+ }
+
private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
{
string NsoName = string.Empty;
@@ -263,17 +282,47 @@ namespace Ryujinx.Core.OsHle
}
}
- Logging.Trace(LogClass.Loader, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
+ Logging.Trace(LogClass.CPU, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
}
- public void EnableCpuTracing()
+ public void PrintStackTrace(AThreadState ThreadState)
{
- Translator.EnableCpuTrace = true;
+ long[] Positions = ThreadState.GetCallStack();
+
+ StringBuilder Trace = new StringBuilder();
+
+ Trace.AppendLine("Guest stack trace:");
+
+ foreach (long Position in Positions)
+ {
+ if (!SymbolTable.TryGetValue(Position, out string SubName))
+ {
+ SubName = $"Sub{Position:x16}";
+ }
+
+ Trace.AppendLine(" " + SubName + " (" + GetNsoNameAndAddress(Position) + ")");
+ }
+
+ Logging.Trace(LogClass.CPU, Trace.ToString());
}
- public void DisableCpuTracing()
+ private string GetNsoNameAndAddress(long Position)
{
- Translator.EnableCpuTrace = false;
+ string Name = string.Empty;
+
+ for (int Index = Executables.Count - 1; Index >= 0; Index--)
+ {
+ if (Position >= Executables[Index].ImageBase)
+ {
+ long Offset = Position - Executables[Index].ImageBase;
+
+ Name = $"{Executables[Index].Name}:{Offset:x8}";
+
+ break;
+ }
+ }
+
+ return Name;
}
private int GetFreeTlsSlot(AThread Thread)
diff --git a/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs b/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs
index ca4e368a..f1c63fac 100644
--- a/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs
+++ b/Ryujinx.Core/OsHle/Services/Am/IApplicationFunctions.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Core.OsHle.Services.Am
{ 20, EnsureSaveData },
{ 21, GetDesiredLanguage },
{ 22, SetTerminateResult },
+ { 23, GetDisplayVersion },
{ 40, NotifyRunning }
};
}
@@ -67,6 +68,15 @@ namespace Ryujinx.Core.OsHle.Services.Am
return 0;
}
+ public long GetDisplayVersion(ServiceCtx Context)
+ {
+ //FIXME: Need to check correct version on a switch.
+ Context.ResponseData.Write(1L);
+ Context.ResponseData.Write(0L);
+
+ return 0;
+ }
+
public long NotifyRunning(ServiceCtx Context)
{
Context.ResponseData.Write(1);
diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioDeviceService.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs
index b27d1448..039a4413 100644
--- a/Ryujinx.Core/OsHle/Services/Aud/IAudioDeviceService.cs
+++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioDevice.cs
@@ -6,7 +6,7 @@ using System.Text;
namespace Ryujinx.Core.OsHle.Services.Aud
{
- class IAudioDeviceService : IpcService
+ class IAudioDevice : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
@@ -14,12 +14,13 @@ namespace Ryujinx.Core.OsHle.Services.Aud
private KEvent SystemEvent;
- public IAudioDeviceService()
+ public IAudioDevice()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, ListAudioDeviceName },
{ 1, SetAudioDeviceOutputVolume },
+ { 3, GetActiveAudioDeviceName },
{ 4, QueryAudioDeviceSystemEvent },
{ 5, GetActiveChannelCount }
};
@@ -72,6 +73,20 @@ namespace Ryujinx.Core.OsHle.Services.Aud
return 0;
}
+ public long GetActiveAudioDeviceName(ServiceCtx Context)
+ {
+ string Name = "FIXME";
+
+ long Position = Context.Request.ReceiveBuff[0].Position;
+ long Size = Context.Request.ReceiveBuff[0].Size;
+
+ byte[] Buffer = Encoding.ASCII.GetBytes(Name + '\0');
+
+ AMemoryHelper.WriteBytes(Context.Memory, Position, Buffer);
+
+ return 0;
+ }
+
public long QueryAudioDeviceSystemEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioRendererManager.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioRendererManager.cs
index eee47089..dcf3c7b7 100644
--- a/Ryujinx.Core/OsHle/Services/Aud/IAudioRendererManager.cs
+++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioRendererManager.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.Core.OsHle.Services.Aud
{
long UserId = Context.RequestData.ReadInt64();
- MakeObject(Context, new IAudioDeviceService());
+ MakeObject(Context, new IAudioDevice());
return 0;
}
diff --git a/Ryujinx.Core/OsHle/Services/Caps/IAlbumAccessorService.cs b/Ryujinx.Core/OsHle/Services/Caps/IAlbumAccessorService.cs
new file mode 100644
index 00000000..d92f3e53
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Caps/IAlbumAccessorService.cs
@@ -0,0 +1,20 @@
+using Ryujinx.Core.OsHle.Ipc;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle.Services.Caps
+{
+ class IAlbumAccessorService : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ public IAlbumAccessorService()
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ //...
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Caps/IScreenshotService.cs b/Ryujinx.Core/OsHle/Services/Caps/IScreenshotService.cs
new file mode 100644
index 00000000..af9b53a8
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Caps/IScreenshotService.cs
@@ -0,0 +1,20 @@
+using Ryujinx.Core.OsHle.Ipc;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle.Services.Caps
+{
+ class IScreenshotService : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ public IScreenshotService()
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ //...
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
index 11a5e46a..8e639b94 100644
--- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
+++ b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
@@ -3,6 +3,7 @@ using Ryujinx.Core.OsHle.Services.Am;
using Ryujinx.Core.OsHle.Services.Apm;
using Ryujinx.Core.OsHle.Services.Aud;
using Ryujinx.Core.OsHle.Services.Bsd;
+using Ryujinx.Core.OsHle.Services.Caps;
using Ryujinx.Core.OsHle.Services.Friend;
using Ryujinx.Core.OsHle.Services.FspSrv;
using Ryujinx.Core.OsHle.Services.Hid;
@@ -57,9 +58,18 @@ namespace Ryujinx.Core.OsHle.Services
case "bsd:u":
return new IClient();
+ case "caps:a":
+ return new IAlbumAccessorService();
+
+ case "caps:ss":
+ return new IScreenshotService();
+
case "friend:a":
return new IServiceCreator();
+ case "friend:u":
+ return new IServiceCreator();
+
case "fsp-srv":
return new IFileSystemProxy();
diff --git a/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs b/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs
index 767d3cc7..ec50c82f 100644
--- a/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs
+++ b/Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs
@@ -16,10 +16,23 @@ namespace Ryujinx.Core.OsHle.Services.Time
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
- { 101, ToCalendarTimeWithMyRule }
+ { 0, GetDeviceLocationName },
+ { 101, ToCalendarTimeWithMyRule }
};
}
+ public long GetDeviceLocationName(ServiceCtx Context)
+ {
+ Logging.Stub(LogClass.ServiceTime, "Stubbed");
+
+ for (int Index = 0; Index < 0x24; Index++)
+ {
+ Context.ResponseData.Write((byte)0);
+ }
+
+ return 0;
+ }
+
public long ToCalendarTimeWithMyRule(ServiceCtx Context)
{
long PosixTime = Context.RequestData.ReadInt64();