Merge remote-tracking branch 'upstream/master'

This commit is contained in:
MS-DOS1999 2018-03-21 11:17:27 +01:00
commit ff43f32ce3
134 changed files with 1898 additions and 1087 deletions

View file

@ -139,6 +139,7 @@ namespace ChocolArm64
Set("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg));
Set("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg));
Set("0x10111100000xxx<<x101xxxxxxxxxx", AInstEmit.Bic_Vi, typeof(AOpCodeSimdImm));
Set("0x101110111xxxxx000111xxxxxxxxxx", AInstEmit.Bif_V, typeof(AOpCodeSimdReg));
Set("0x101110011xxxxx000111xxxxxxxxxx", AInstEmit.Bsl_V, typeof(AOpCodeSimdReg));
Set("0>101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg));
Set("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd));
@ -229,6 +230,7 @@ namespace ChocolArm64
Set("xx111100x11xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemReg));
Set("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeSimdMemLit));
Set("0x001110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mla_V, typeof(AOpCodeSimdReg));
Set("0x101111xxxxxxxx0000x0xxxxxxxxxx", AInstEmit.Mla_Ve, typeof(AOpCodeSimdRegElem));
Set("0x101110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mls_V, typeof(AOpCodeSimdReg));
Set("0x00111100000xxx0xx001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
Set("0x00111100000xxx10x001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));

View file

@ -82,6 +82,7 @@ namespace ChocolArm64.Decoder
}
}
this.Index = Index;
this.SElems = SElems;
this.Size = Scale;

View file

@ -11,9 +11,8 @@ namespace ChocolArm64.Decoder
switch (Size)
{
case 1:
Index = (OpCode >> 21) & 1 |
(OpCode >> 10) & 2 |
(OpCode >> 18) & 4;
Index = (OpCode >> 20) & 3 |
(OpCode >> 9) & 4;
Rm &= 0xf;

View file

@ -360,6 +360,15 @@ namespace ChocolArm64.Instruction
});
}
public static void Mla_Ve(AILEmitterCtx Context)
{
EmitVectorTernaryOpByElemZx(Context, () =>
{
Context.Emit(OpCodes.Mul);
Context.Emit(OpCodes.Add);
});
}
public static void Mls_V(AILEmitterCtx Context)
{
EmitVectorTernaryOpZx(Context, () =>

View file

@ -381,13 +381,16 @@ namespace ChocolArm64.Instruction
}
EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
EmitVectorExtract(Context, Op.Rm, Index, Op.Size, Signed);
EmitVectorExtract(Context, Op.Rm, Elem, Op.Size, Signed);
Emit();
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
EmitVectorInsertTmp(Context, Index, Op.Size);
}
Context.EmitLdvectmp();
Context.EmitStvec(Op.Rd);
if (Op.RegisterSize == ARegisterSize.SIMD64)
{
EmitVectorZeroUpper(Context, Op.Rd);

View file

@ -32,6 +32,36 @@ namespace ChocolArm64.Instruction
});
}
public static void Bif_V(AILEmitterCtx Context)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
{
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
Context.Emit(OpCodes.Xor);
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
Context.Emit(OpCodes.And);
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
Context.Emit(OpCodes.Xor);
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
}
if (Op.RegisterSize == ARegisterSize.SIMD64)
{
EmitVectorZeroUpper(Context, Op.Rd);
}
}
public static void Bsl_V(AILEmitterCtx Context)
{
EmitVectorTernaryOpZx(Context, () =>

View file

@ -41,15 +41,15 @@ namespace ChocolArm64.Instruction
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
public static uint Crc32b(uint Crc, byte Val) => Crc32 (Crc, Crc32RevPoly, Val);
public static uint Crc32h(uint Crc, byte Val) => Crc32h(Crc, Crc32RevPoly, Val);
public static uint Crc32w(uint Crc, byte Val) => Crc32w(Crc, Crc32RevPoly, Val);
public static uint Crc32x(uint Crc, byte Val) => Crc32x(Crc, Crc32RevPoly, Val);
public static uint Crc32b(uint Crc, byte Val) => Crc32 (Crc, Crc32RevPoly, Val);
public static uint Crc32h(uint Crc, ushort Val) => Crc32h(Crc, Crc32RevPoly, Val);
public static uint Crc32w(uint Crc, uint Val) => Crc32w(Crc, Crc32RevPoly, Val);
public static uint Crc32x(uint Crc, ulong Val) => Crc32x(Crc, Crc32RevPoly, Val);
public static uint Crc32cb(uint Crc, byte Val) => Crc32 (Crc, Crc32cRevPoly, Val);
public static uint Crc32ch(uint Crc, byte Val) => Crc32h(Crc, Crc32cRevPoly, Val);
public static uint Crc32cw(uint Crc, byte Val) => Crc32w(Crc, Crc32cRevPoly, Val);
public static uint Crc32cx(uint Crc, byte Val) => Crc32x(Crc, Crc32cRevPoly, Val);
public static uint Crc32cb(uint Crc, byte Val) => Crc32 (Crc, Crc32cRevPoly, Val);
public static uint Crc32ch(uint Crc, ushort Val) => Crc32h(Crc, Crc32cRevPoly, Val);
public static uint Crc32cw(uint Crc, uint Val) => Crc32w(Crc, Crc32cRevPoly, Val);
public static uint Crc32cx(uint Crc, ulong Val) => Crc32x(Crc, Crc32cRevPoly, Val);
private static uint Crc32h(uint Crc, uint Poly, ushort Val)
{

View file

@ -1,4 +1,6 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace ChocolArm64.Memory
@ -20,11 +22,11 @@ namespace ChocolArm64.Memory
}
}
public static byte[] ReadBytes(AMemory Memory, long Position, int Size)
public static byte[] ReadBytes(AMemory Memory, long Position, long Size)
{
byte[] Data = new byte[Size];
for (int Offs = 0; Offs < Size; Offs++)
for (long Offs = 0; Offs < Size; Offs++)
{
Data[Offs] = (byte)Memory.ReadByte(Position + Offs);
}
@ -40,11 +42,39 @@ namespace ChocolArm64.Memory
}
}
public static string ReadAsciiString(AMemory Memory, long Position, int MaxSize = -1)
public unsafe static T Read<T>(AMemory Memory, long Position) where T : struct
{
long Size = Marshal.SizeOf<T>();
if ((ulong)(Position + Size) > AMemoryMgr.AddrSize)
{
throw new ArgumentOutOfRangeException(nameof(Position));
}
IntPtr Ptr = new IntPtr((byte*)Memory.Ram + Position);
return Marshal.PtrToStructure<T>(Ptr);
}
public unsafe static void Write<T>(AMemory Memory, long Position, T Value) where T : struct
{
long Size = Marshal.SizeOf<T>();
if ((ulong)(Position + Size) > AMemoryMgr.AddrSize)
{
throw new ArgumentOutOfRangeException(nameof(Position));
}
IntPtr Ptr = new IntPtr((byte*)Memory.Ram + Position);
Marshal.StructureToPtr<T>(Value, Ptr, false);
}
public static string ReadAsciiString(AMemory Memory, long Position, long MaxSize = -1)
{
using (MemoryStream MS = new MemoryStream())
{
for (int Offs = 0; Offs < MaxSize || MaxSize == -1; Offs++)
for (long Offs = 0; Offs < MaxSize || MaxSize == -1; Offs++)
{
byte Value = (byte)Memory.ReadByte(Position + Offs);

View file

@ -3,7 +3,7 @@ using System;
namespace ChocolArm64
{
using System.Reflection.Emit;
static class ILGeneratorEx
{
public static void EmitLdc_I4(this ILGenerator Generator,int Value)

View file

@ -0,0 +1,13 @@
namespace Ryujinx.Audio
{
public enum AudioFormat
{
Invalid = 0,
PcmInt8 = 1,
PcmInt16 = 2,
PcmImt24 = 3,
PcmImt32 = 4,
PcmFloat = 5,
Adpcm = 6
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Audio
{
public interface IAalOutput
{
int OpenTrack(
int SampleRate,
int Channels,
ReleaseCallback Callback,
out AudioFormat Format);
void CloseTrack(int Track);
bool ContainsBuffer(int Track, long Tag);
long[] GetReleasedBuffers(int Track, int MaxCount);
void AppendBuffer(int Track, long Tag, byte[] Buffer);
void Start(int Track);
void Stop(int Track);
PlaybackState GetState(int Track);
}
}

View file

@ -0,0 +1,365 @@
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.Audio.OpenAL
{
public class OpenALAudioOut : IAalOutput
{
private const int MaxTracks = 256;
private const int MaxReleased = 32;
private AudioContext Context;
private class Track : IDisposable
{
public int SourceId { get; private set; }
public int SampleRate { get; private set; }
public ALFormat Format { get; private set; }
private ReleaseCallback Callback;
public PlaybackState State { get; set; }
private bool ShouldCallReleaseCallback;
private ConcurrentDictionary<long, int> Buffers;
private Queue<long> QueuedTagsQueue;
private Queue<long> ReleasedTagsQueue;
private int LastReleasedCount;
private bool Disposed;
public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
{
this.SampleRate = SampleRate;
this.Format = Format;
this.Callback = Callback;
State = PlaybackState.Stopped;
SourceId = AL.GenSource();
Buffers = new ConcurrentDictionary<long, int>();
QueuedTagsQueue = new Queue<long>();
ReleasedTagsQueue = new Queue<long>();
}
public bool ContainsBuffer(long Tag)
{
SyncQueuedTags();
foreach (long QueuedTag in QueuedTagsQueue)
{
if (QueuedTag == Tag)
{
return true;
}
}
return false;
}
public long[] GetReleasedBuffers(int MaxCount)
{
ClearReleased();
List<long> Tags = new List<long>();
HashSet<long> Unique = new HashSet<long>();
while (MaxCount-- > 0 && ReleasedTagsQueue.TryDequeue(out long Tag))
{
if (Unique.Add(Tag))
{
Tags.Add(Tag);
}
}
return Tags.ToArray();
}
public int AppendBuffer(long Tag)
{
if (Disposed)
{
throw new ObjectDisposedException(nameof(Track));
}
int Id = AL.GenBuffer();
Buffers.AddOrUpdate(Tag, Id, (Key, OldId) =>
{
AL.DeleteBuffer(OldId);
return Id;
});
QueuedTagsQueue.Enqueue(Tag);
return Id;
}
public void ClearReleased()
{
SyncQueuedTags();
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
if (ReleasedCount > 0)
{
AL.SourceUnqueueBuffers(SourceId, ReleasedCount);
}
}
public void CallReleaseCallbackIfNeeded()
{
CheckReleaseChanges();
if (ShouldCallReleaseCallback)
{
ShouldCallReleaseCallback = false;
Callback();
}
}
private void CheckReleaseChanges()
{
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
}
private void CheckReleaseChanges(int NewReleasedCount)
{
if (LastReleasedCount != NewReleasedCount)
{
LastReleasedCount = NewReleasedCount;
ShouldCallReleaseCallback = true;
}
}
private void SyncQueuedTags()
{
AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount);
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
QueuedCount -= ReleasedCount;
while (QueuedTagsQueue.Count > QueuedCount)
{
ReleasedTagsQueue.Enqueue(QueuedTagsQueue.Dequeue());
}
while (ReleasedTagsQueue.Count > MaxReleased)
{
ReleasedTagsQueue.Dequeue();
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing && !Disposed)
{
Disposed = true;
AL.DeleteSource(SourceId);
foreach (int Id in Buffers.Values)
{
AL.DeleteBuffer(Id);
}
}
}
}
private ConcurrentDictionary<int, Track> Tracks;
private Thread AudioPollerThread;
private bool KeepPolling;
public OpenALAudioOut()
{
Context = new AudioContext();
Tracks = new ConcurrentDictionary<int, Track>();
KeepPolling = true;
AudioPollerThread = new Thread(AudioPollerWork);
AudioPollerThread.Start();
}
private void AudioPollerWork()
{
do
{
foreach (Track Td in Tracks.Values)
{
Td.CallReleaseCallbackIfNeeded();
}
Thread.Yield();
}
while (KeepPolling);
}
public int OpenTrack(
int SampleRate,
int Channels,
ReleaseCallback Callback,
out AudioFormat Format)
{
Format = AudioFormat.PcmInt16;
Track Td = new Track(SampleRate, GetALFormat(Channels, Format), Callback);
for (int Id = 0; Id < MaxTracks; Id++)
{
if (Tracks.TryAdd(Id, Td))
{
return Id;
}
}
return -1;
}
private ALFormat GetALFormat(int Channels, AudioFormat Format)
{
if (Channels < 1 || Channels > 2)
{
throw new ArgumentOutOfRangeException(nameof(Channels));
}
if (Channels == 1)
{
switch (Format)
{
case AudioFormat.PcmInt8: return ALFormat.Mono8;
case AudioFormat.PcmInt16: return ALFormat.Mono16;
}
}
else /* if (Channels == 2) */
{
switch (Format)
{
case AudioFormat.PcmInt8: return ALFormat.Stereo8;
case AudioFormat.PcmInt16: return ALFormat.Stereo16;
}
}
throw new ArgumentException(nameof(Format));
}
public void CloseTrack(int Track)
{
if (Tracks.TryRemove(Track, out Track Td))
{
Td.Dispose();
}
}
public bool ContainsBuffer(int Track, long Tag)
{
if (Tracks.TryGetValue(Track, out Track Td))
{
return Td.ContainsBuffer(Tag);
}
return false;
}
public long[] GetReleasedBuffers(int Track, int MaxCount)
{
if (Tracks.TryGetValue(Track, out Track Td))
{
return Td.GetReleasedBuffers(MaxCount);
}
return null;
}
public void AppendBuffer(int Track, long Tag, byte[] Buffer)
{
if (Tracks.TryGetValue(Track, out Track Td))
{
int BufferId = Td.AppendBuffer(Tag);
AL.BufferData(BufferId, Td.Format, Buffer, Buffer.Length, Td.SampleRate);
AL.SourceQueueBuffer(Td.SourceId, BufferId);
StartPlaybackIfNeeded(Td);
}
}
public void Start(int Track)
{
if (Tracks.TryGetValue(Track, out Track Td))
{
Td.State = PlaybackState.Playing;
StartPlaybackIfNeeded(Td);
}
}
private void StartPlaybackIfNeeded(Track Td)
{
AL.GetSource(Td.SourceId, ALGetSourcei.SourceState, out int StateInt);
ALSourceState State = (ALSourceState)StateInt;
if (State != ALSourceState.Playing && Td.State == PlaybackState.Playing)
{
Td.ClearReleased();
AL.SourcePlay(Td.SourceId);
}
}
public void Stop(int Track)
{
if (Tracks.TryGetValue(Track, out Track Td))
{
Td.State = PlaybackState.Stopped;
AL.SourceStop(Td.SourceId);
}
}
public PlaybackState GetState(int Track)
{
if (Tracks.TryGetValue(Track, out Track Td))
{
return Td.State;
}
return PlaybackState.Stopped;
}
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Audio
{
public enum PlaybackState
{
Playing = 0,
Stopped = 1
}
}

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Audio
{
public delegate void ReleaseCallback();
}

View file

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
</ItemGroup>
</Project>

View file

@ -9,6 +9,7 @@ namespace Ryujinx.Core
{
public static class Config
{
public static bool EnableMemoryChecks { get; private set; }
public static bool LoggingEnableInfo { get; private set; }
public static bool LoggingEnableTrace { get; private set; }
public static bool LoggingEnableDebug { get; private set; }
@ -26,6 +27,7 @@ namespace Ryujinx.Core
var iniPath = Path.Combine(iniFolder, "Ryujinx.conf");
IniParser Parser = new IniParser(iniPath);
EnableMemoryChecks = Convert.ToBoolean(Parser.Value("Enable_Memory_Checks"));
LoggingEnableInfo = Convert.ToBoolean(Parser.Value("Logging_Enable_Info"));
LoggingEnableTrace = Convert.ToBoolean(Parser.Value("Logging_Enable_Trace"));
LoggingEnableDebug = Convert.ToBoolean(Parser.Value("Logging_Enable_Debug"));

View file

@ -0,0 +1,62 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Services.Am;
using System;
using System.Collections.Concurrent;
namespace Ryujinx.Core.OsHle
{
class AppletStateMgr : IDisposable
{
private ConcurrentQueue<MessageInfo> Messages;
public FocusState FocusState { get; private set; }
public KEvent MessageEvent { get; private set; }
public AppletStateMgr()
{
Messages = new ConcurrentQueue<MessageInfo>();
MessageEvent = new KEvent();
}
public void SetFocus(bool IsFocused)
{
FocusState = IsFocused
? FocusState.InFocus
: FocusState.OutOfFocus;
EnqueueMessage(MessageInfo.FocusStateChanged);
}
public void EnqueueMessage(MessageInfo Message)
{
Messages.Enqueue(Message);
MessageEvent.Handle.Set();
}
public bool TryDequeueMessage(out MessageInfo Message)
{
if (Messages.Count < 2)
{
MessageEvent.Handle.Reset();
}
return Messages.TryDequeue(out Message);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
MessageEvent.Dispose();
}
}
}
}

View file

@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle
private bool OwnsCondVarValue;
private List<HThread> WaitingThreads;
private List<KThread> WaitingThreads;
public CondVar(Process Process, long CondVarAddress, long Timeout)
{
@ -21,10 +21,10 @@ namespace Ryujinx.Core.OsHle
this.CondVarAddress = CondVarAddress;
this.Timeout = Timeout;
WaitingThreads = new List<HThread>();
WaitingThreads = new List<KThread>();
}
public bool WaitForSignal(HThread Thread)
public bool WaitForSignal(KThread Thread)
{
int Count = Process.Memory.ReadInt32(CondVarAddress);
@ -66,7 +66,7 @@ namespace Ryujinx.Core.OsHle
return true;
}
public void SetSignal(HThread Thread, int Count)
public void SetSignal(KThread Thread, int Count)
{
lock (WaitingThreads)
{

View file

@ -1,12 +0,0 @@
namespace Ryujinx.Core.OsHle
{
class FileDesc
{
public string Name { get; private set; }
public FileDesc(string Name)
{
this.Name = Name;
}
}
}

View file

@ -0,0 +1,69 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle
{
class GlobalStateTable
{
private ConcurrentDictionary<Process, IdDictionary> DictByProcess;
public GlobalStateTable()
{
DictByProcess = new ConcurrentDictionary<Process, IdDictionary>();
}
public bool Add(Process Process, int Id, object Data)
{
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
return Dict.Add(Id, Data);
}
public int Add(Process Process, object Data)
{
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
return Dict.Add(Data);
}
public object GetData(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.GetData(Id);
}
return null;
}
public T GetData<T>(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.GetData<T>(Id);
}
return default(T);
}
public object Delete(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.Delete(Id);
}
return null;
}
public ICollection<object> DeleteProcess(Process Process)
{
if (DictByProcess.TryRemove(Process, out IdDictionary Dict))
{
return Dict.Clear();
}
return null;
}
}
}

View file

@ -1,48 +0,0 @@
using System;
namespace Ryujinx.Core.OsHle.Handles
{
class HDomain : HSession, IDisposable
{
private IdDictionary Objects;
public HDomain(HSession Session) : base(Session)
{
Objects = new IdDictionary();
}
public int Add(object Obj)
{
return Objects.Add(Obj);
}
public bool Delete(int Id)
{
return Objects.Delete(Id);
}
public object GetObject(int Id)
{
return Objects.GetData(Id);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
foreach (object Obj in Objects)
{
if (Obj != this && Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
}
}
}
}
}

View file

@ -1,7 +0,0 @@
namespace Ryujinx.Core.OsHle.Handles
{
class HEvent
{
}
}

View file

@ -1,29 +0,0 @@
using Ryujinx.Core.OsHle.IpcServices;
namespace Ryujinx.Core.OsHle.Handles
{
class HSession
{
public IIpcService Service { get; private set; }
public bool IsInitialized { get; private set; }
public int State { get; set; }
public HSession(IIpcService Service)
{
this.Service = Service;
}
public HSession(HSession Session)
{
Service = Session.Service;
IsInitialized = Session.IsInitialized;
}
public void Initialize()
{
IsInitialized = true;
}
}
}

View file

@ -1,30 +0,0 @@
using System;
namespace Ryujinx.Core.OsHle.Handles
{
class HSessionObj : HSession, IDisposable
{
public object Obj { get; private set; }
public HSessionObj(HSession Session, object Obj) : base(Session)
{
this.Obj = Obj;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing && Obj != null)
{
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
}
}
}
}

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Core.OsHle.Handles
{
class KEvent : KSynchronizationObject { }
}

View file

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.Handles
{
class KProcessHandleTable : IDisposable
class KProcessHandleTable
{
private IdDictionary Handles;
@ -21,43 +21,14 @@ namespace Ryujinx.Core.OsHle.Handles
return Handles.GetData<T>(Handle);
}
public bool ReplaceData(int Id, object Data)
public object CloseHandle(int Handle)
{
return Handles.ReplaceData(Id, Data);
}
public bool CloseHandle(int Handle)
{
object Data = Handles.GetData(Handle);
if (Data is HTransferMem TMem)
{
TMem.Memory.Manager.Reprotect(
TMem.Position,
TMem.Size,
TMem.Perm);
}
return Handles.Delete(Handle);
}
public void Dispose()
public ICollection<object> Clear()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
foreach (object Obj in Handles)
{
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
}
}
return Handles.Clear();
}
}
}

View file

@ -5,15 +5,15 @@ using System.Threading;
namespace Ryujinx.Core.OsHle.Handles
{
public class KProcessScheduler : IDisposable
class KProcessScheduler : IDisposable
{
private class SchedulerThread : IDisposable
{
public HThread Thread { get; private set; }
public KThread Thread { get; private set; }
public AutoResetEvent WaitEvent { get; private set; }
public SchedulerThread(HThread Thread)
public SchedulerThread(KThread Thread)
{
this.Thread = Thread;
@ -95,7 +95,7 @@ namespace Ryujinx.Core.OsHle.Handles
}
}
private ConcurrentDictionary<HThread, SchedulerThread> AllThreads;
private ConcurrentDictionary<KThread, SchedulerThread> AllThreads;
private ThreadQueue[] WaitingToRun;
@ -105,7 +105,7 @@ namespace Ryujinx.Core.OsHle.Handles
public KProcessScheduler()
{
AllThreads = new ConcurrentDictionary<HThread, SchedulerThread>();
AllThreads = new ConcurrentDictionary<KThread, SchedulerThread>();
WaitingToRun = new ThreadQueue[4];
@ -119,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Handles
SchedLock = new object();
}
public void StartThread(HThread Thread)
public void StartThread(KThread Thread)
{
lock (SchedLock)
{
@ -164,7 +164,7 @@ namespace Ryujinx.Core.OsHle.Handles
}
}
public void Resume(HThread CurrThread)
public void Resume(KThread CurrThread)
{
SchedulerThread SchedThread;
@ -183,7 +183,7 @@ namespace Ryujinx.Core.OsHle.Handles
TryResumingExecution(SchedThread);
}
public bool WaitForSignal(HThread Thread, int Timeout = -1)
public bool WaitForSignal(KThread Thread, int Timeout = -1)
{
SchedulerThread SchedThread;
@ -230,7 +230,7 @@ namespace Ryujinx.Core.OsHle.Handles
private void TryResumingExecution(SchedulerThread SchedThread)
{
HThread Thread = SchedThread.Thread;
KThread Thread = SchedThread.Thread;
lock (SchedLock)
{
@ -249,7 +249,7 @@ namespace Ryujinx.Core.OsHle.Handles
Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
}
public void Yield(HThread Thread)
public void Yield(KThread Thread)
{
SchedulerThread SchedThread;
@ -295,11 +295,11 @@ namespace Ryujinx.Core.OsHle.Handles
}
}
public void Signal(params HThread[] Threads)
public void Signal(params KThread[] Threads)
{
lock (SchedLock)
{
foreach (HThread Thread in Threads)
foreach (KThread Thread in Threads)
{
if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
{
@ -314,7 +314,7 @@ namespace Ryujinx.Core.OsHle.Handles
}
}
private string GetDbgThreadInfo(HThread Thread)
private string GetDbgThreadInfo(KThread Thread)
{
return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}";
}

View file

@ -0,0 +1,28 @@
using Ryujinx.Core.OsHle.Services;
using System;
namespace Ryujinx.Core.OsHle.Handles
{
class KSession : IDisposable
{
public IpcService Service { get; private set; }
public KSession(IpcService Service)
{
this.Service = Service;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing && Service is IDisposable DisposableService)
{
DisposableService.Dispose();
}
}
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Threading;
namespace Ryujinx.Core.OsHle.Handles
{
class KSynchronizationObject : IDisposable
{
public ManualResetEvent Handle { get; private set; }
public KSynchronizationObject()
{
Handle = new ManualResetEvent(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Handle.Dispose();
}
}
}
}

View file

@ -2,7 +2,7 @@ using ChocolArm64;
namespace Ryujinx.Core.OsHle.Handles
{
public class HThread
class KThread : KSynchronizationObject
{
public AThread Thread { get; private set; }
@ -11,7 +11,7 @@ namespace Ryujinx.Core.OsHle.Handles
public int ThreadId => Thread.ThreadId;
public HThread(AThread Thread, int ProcessorId, int Priority)
public KThread(AThread Thread, int ProcessorId, int Priority)
{
this.Thread = Thread;
this.ProcessorId = ProcessorId;

View file

@ -51,7 +51,7 @@ namespace Ryujinx.Core.OsHle
long Value0 = Memory.ReadInt64(Position + 0x08);
long Value1 = Memory.ReadInt64(Position + 0x10);
FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, (int)(Value1 - Value0));
FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, Value1 - Value0);
break;
}

View file

@ -16,8 +16,10 @@ namespace Ryujinx.Core.OsHle
private ConcurrentDictionary<int, Process> Processes;
internal HSharedMem HidSharedMem;
internal HSharedMem FontSharedMem;
internal HSharedMem HidSharedMem { get; private set; }
internal HSharedMem FontSharedMem { get; private set; }
internal KEvent VsyncEvent { get; private set; }
private Switch Ns;
@ -32,6 +34,8 @@ namespace Ryujinx.Core.OsHle
HidSharedMem = new HSharedMem();
FontSharedMem = new HSharedMem();
VsyncEvent = new KEvent();
}
public void LoadCart(string ExeFsDir, string RomFsFile = null)
@ -91,6 +95,8 @@ namespace Ryujinx.Core.OsHle
MainProcess.Run(IsNro);
}
public void SignalVsync() => VsyncEvent.Handle.Set();
private Process MakeProcess()
{
Process Process;
@ -109,9 +115,16 @@ namespace Ryujinx.Core.OsHle
Processes.TryAdd(ProcessId, Process);
}
InitializeProcess(Process);
return Process;
}
private void InitializeProcess(Process Process)
{
Process.AppletState.SetFocus(true);
}
internal void ExitProcess(int ProcessId)
{
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
@ -171,6 +184,8 @@ namespace Ryujinx.Core.OsHle
Process.StopAllThreadsAsync();
Process.Dispose();
}
VsyncEvent.Dispose();
}
}
}

View file

@ -1,11 +1,10 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle
{
class IdDictionary : IEnumerable<object>
class IdDictionary
{
private ConcurrentDictionary<int, object> Objs;
@ -16,6 +15,11 @@ namespace Ryujinx.Core.OsHle
Objs = new ConcurrentDictionary<int, object>();
}
public bool Add(int Id, object Data)
{
return Objs.TryAdd(Id, Data);
}
public int Add(object Data)
{
if (Objs.TryAdd(FreeIdHint, Data))
@ -39,18 +43,6 @@ namespace Ryujinx.Core.OsHle
throw new InvalidOperationException();
}
public bool ReplaceData(int Id, object Data)
{
if (Objs.ContainsKey(Id))
{
Objs[Id] = Data;
return true;
}
return false;
}
public object GetData(int Id)
{
if (Objs.TryGetValue(Id, out object Data))
@ -71,31 +63,25 @@ namespace Ryujinx.Core.OsHle
return default(T);
}
public bool Delete(int Id)
public object Delete(int Id)
{
if (Objs.TryRemove(Id, out object Obj))
{
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
FreeIdHint = Id;
return true;
return Obj;
}
return false;
return null;
}
IEnumerator<object> IEnumerable<object>.GetEnumerator()
public ICollection<object> Clear()
{
return Objs.Values.GetEnumerator();
}
ICollection<object> Values = Objs.Values;
IEnumerator IEnumerable.GetEnumerator()
{
return Objs.Values.GetEnumerator();
Objs.Clear();
return Values;
}
}
}

View file

@ -1,8 +0,0 @@
namespace Ryujinx.Core.OsHle.Ipc
{
enum IpcDomCmd
{
SendMsg = 1,
DeleteObj = 2
}
}

View file

@ -1,6 +1,5 @@
using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices;
using System;
using System.IO;
@ -8,20 +7,15 @@ namespace Ryujinx.Core.OsHle.Ipc
{
static class IpcHandler
{
private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
public static void IpcCall(
Switch Ns,
Process Process,
AMemory Memory,
HSession Session,
KSession Session,
IpcMessage Request,
int ThreadId,
long CmdPtr,
int HndId)
long CmdPtr)
{
IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request);
IpcMessage Response = new IpcMessage();
using (MemoryStream Raw = new MemoryStream(Request.RawData))
{
@ -29,94 +23,25 @@ namespace Ryujinx.Core.OsHle.Ipc
if (Request.Type == IpcMessageType.Request)
{
string ServiceName = Session.Service.GetType().Name;
Response.Type = IpcMessageType.Response;
ServiceProcessRequest ProcReq = null;
bool IgnoreNullPR = false;
string DbgServiceName = string.Empty;
if (Session is HDomain Dom)
using (MemoryStream ResMS = new MemoryStream())
{
if (Request.DomCmd == IpcDomCmd.SendMsg)
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
BinaryWriter ResWriter = new BinaryWriter(ResMS);
object Obj = Dom.GetObject(Request.DomObjId);
ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
if (Obj is HDomain)
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
Session.Service.CallMethod(Context);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else if (Obj != null)
{
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
{
Dom.Delete(Request.DomObjId);
Response = FillResponse(Response, 0);
IgnoreNullPR = true;
}
}
else
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
if (Session is HSessionObj)
{
object Obj = ((HSessionObj)Session).Obj;
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
Logging.Debug($"IpcMessage: {DbgServiceName}");
if (ProcReq != null)
{
using (MemoryStream ResMS = new MemoryStream())
{
BinaryWriter ResWriter = new BinaryWriter(ResMS);
ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
long Result = ProcReq(Context);
Response = FillResponse(Response, Result, ResMS.ToArray());
}
}
else if (!IgnoreNullPR)
{
throw new NotImplementedException(DbgServiceName);
Response.RawData = ResMS.ToArray();
}
}
else if (Request.Type == IpcMessageType.Control)
@ -128,11 +53,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{
case 0:
{
HDomain Dom = new HDomain(Session);
Process.HandleTable.ReplaceData(HndId, Dom);
Request = FillResponse(Response, 0, Dom.Add(Dom));
Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
break;
}
@ -198,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{
BinaryWriter Writer = new BinaryWriter(MS);
Writer.Write(SfcoMagic);
Writer.Write(IpcMagic.Sfco);
Writer.Write(Result);
if (Data != null)

View file

@ -125,8 +125,7 @@ namespace Ryujinx.Core.OsHle.Ipc
Reader.ReadInt64(); //Padding
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine +
$" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine +
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + Environment.NewLine +
$" DomObjId: {DomObjId.ToString()}" + Environment.NewLine;
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.Ipc
{
abstract class IpcMagic
{
public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
}
}

View file

@ -17,10 +17,6 @@ namespace Ryujinx.Core.OsHle.Ipc
public List<int> ResponseObjIds { get; private set; }
public bool IsDomain { get; private set; }
public IpcDomCmd DomCmd { get; private set; }
public int DomObjId { get; private set; }
public byte[] RawData { get; set; }
public IpcMessage()
@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc
ResponseObjIds = new List<int>();
}
public IpcMessage(bool Domain) : this()
public IpcMessage(byte[] Data, long CmdPtr) : this()
{
IsDomain = Domain;
}
public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this()
{
Logging.Ipc(Data, CmdPtr, Domain);
using (MemoryStream MS = new MemoryStream(Data))
{
BinaryReader Reader = new BinaryReader(MS);
Initialize(Reader, CmdPtr, Domain);
Initialize(Reader, CmdPtr);
}
}
private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain)
private void Initialize(BinaryReader Reader, long CmdPtr)
{
IsDomain = Domain;
int Word0 = Reader.ReadInt32();
int Word1 = Reader.ReadInt32();
@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc
RecvListCount = 0;
}
if (Domain && Type == IpcMessageType.Request)
{
int DomWord0 = Reader.ReadInt32();
DomCmd = (IpcDomCmd)(DomWord0 & 0xff);
RawDataSize = (DomWord0 >> 16) & 0xffff;
DomObjId = Reader.ReadInt32();
Reader.ReadInt64(); //Padding
}
RawData = Reader.ReadBytes(RawDataSize);
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
@ -165,9 +139,7 @@ namespace Ryujinx.Core.OsHle.Ipc
//This is the weirdest padding I've seen so far...
int Pad1 = 0x10 - Pad0;
DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4;
DataLength += ResponseObjIds.Count;
DataLength = (DataLength + Pad0 + Pad1) / 4;
Word1 = DataLength & 0x3ff;
@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc
MS.Seek(Pad0, SeekOrigin.Current);
if (IsDomain)
{
Writer.Write(ResponseObjIds.Count);
Writer.Write(0);
Writer.Write(0L);
}
if (RawData != null)
{
Writer.Write(RawData);
}
foreach (int Id in ResponseObjIds)
{
Writer.Write(Id);
}
Writer.Write(new byte[Pad1]);
return MS.ToArray();

View file

@ -6,7 +6,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{
public long Position { get; private set; }
public int Index { get; private set; }
public short Size { get; private set; }
public long Size { get; private set; }
public IpcPtrBuffDesc(BinaryReader Reader)
{
@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle.Ipc
Index = ((int)Word0 >> 0) & 0x03f;
Index |= ((int)Word0 >> 3) & 0x1c0;
Size = (short)(Word0 >> 16);
Size = (ushort)(Word0 >> 16);
}
}
}

View file

@ -6,6 +6,5 @@ namespace Ryujinx.Core.OsHle
public const int InvalidHandle = 114;
public const int Timeout = 117;
public const int InvalidInfo = 120;
public const int InvalidIpcReq = 123;
}
}

View file

@ -16,7 +16,7 @@ namespace Ryujinx.Core.OsHle
private object EnterWaitLock;
private ConcurrentQueue<HThread> WaitingThreads;
private ConcurrentQueue<KThread> WaitingThreads;
public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
{
@ -27,10 +27,10 @@ namespace Ryujinx.Core.OsHle
EnterWaitLock = new object();
WaitingThreads = new ConcurrentQueue<HThread>();
WaitingThreads = new ConcurrentQueue<KThread>();
}
public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle)
public void WaitForLock(KThread RequestingThread, int RequestingThreadHandle)
{
AcquireMutexValue();
@ -83,11 +83,11 @@ namespace Ryujinx.Core.OsHle
ReleaseMutexValue();
HThread[] UnlockedThreads = new HThread[WaitingThreads.Count];
KThread[] UnlockedThreads = new KThread[WaitingThreads.Count];
int Index = 0;
while (WaitingThreads.TryDequeue(out HThread Thread))
while (WaitingThreads.TryDequeue(out KThread Thread))
{
UnlockedThreads[Index++] = Thread;
}

View file

@ -5,6 +5,7 @@ using Ryujinx.Core.Loaders;
using Ryujinx.Core.Loaders.Executables;
using Ryujinx.Core.OsHle.Exceptions;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Services.Nv;
using Ryujinx.Core.OsHle.Svc;
using System;
using System.Collections.Concurrent;
@ -31,21 +32,21 @@ namespace Ryujinx.Core.OsHle
public AMemory Memory { get; private set; }
public ServiceMgr Services { get; private set; }
public KProcessScheduler Scheduler { get; private set; }
public KProcessHandleTable HandleTable { get; private set; }
public AppletStateMgr AppletState { get; private set; }
private SvcHandler SvcHandler;
private ConcurrentDictionary<int, AThread> TlsSlots;
private ConcurrentDictionary<long, HThread> ThreadsByTpidr;
private ConcurrentDictionary<long, KThread> ThreadsByTpidr;
private List<Executable> Executables;
private HThread MainThread;
private KThread MainThread;
private long ImageBase;
@ -60,17 +61,17 @@ namespace Ryujinx.Core.OsHle
Memory = new AMemory();
Services = new ServiceMgr();
HandleTable = new KProcessHandleTable();
Scheduler = new KProcessScheduler();
Scheduler = new KProcessScheduler();
AppletState = new AppletStateMgr();
SvcHandler = new SvcHandler(Ns, this);
TlsSlots = new ConcurrentDictionary<int, AThread>();
ThreadsByTpidr = new ConcurrentDictionary<long, HThread>();
ThreadsByTpidr = new ConcurrentDictionary<long, KThread>();
Executables = new List<Executable>();
@ -132,7 +133,7 @@ namespace Ryujinx.Core.OsHle
return false;
}
MainThread = HandleTable.GetData<HThread>(Handle);
MainThread = HandleTable.GetData<KThread>(Handle);
if (NeedsHbAbi)
{
@ -186,7 +187,7 @@ namespace Ryujinx.Core.OsHle
AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
KThread ThreadHnd = new KThread(Thread, ProcessorId, Priority);
int Handle = HandleTable.OpenHandle(ThreadHnd);
@ -311,9 +312,9 @@ namespace Ryujinx.Core.OsHle
return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize);
}
public HThread GetThread(long Tpidr)
public KThread GetThread(long Tpidr)
{
if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread))
if (!ThreadsByTpidr.TryGetValue(Tpidr, out KThread Thread))
{
Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!");
}
@ -344,11 +345,27 @@ namespace Ryujinx.Core.OsHle
}
Disposed = true;
Services.Dispose();
HandleTable.Dispose();
foreach (object Obj in HandleTable.Clear())
{
if (Obj is KSession Session)
{
Session.Dispose();
}
}
ServiceNvDrv.Fds.DeleteProcess(this);
ServiceNvDrv.NvMaps .DeleteProcess(this);
ServiceNvDrv.NvMapsById.DeleteProcess(this);
ServiceNvDrv.NvMapsFb .DeleteProcess(this);
Scheduler.Dispose();
AppletState.Dispose();
SvcHandler.Dispose();
Memory.Dispose();
Logging.Info($"Process {ProcessId} exiting...");

View file

@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle
public Switch Ns { get; private set; }
public Process Process { get; private set; }
public AMemory Memory { get; private set; }
public HSession Session { get; private set; }
public KSession Session { get; private set; }
public IpcMessage Request { get; private set; }
public IpcMessage Response { get; private set; }
public BinaryReader RequestData { get; private set; }
@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle
Switch Ns,
Process Process,
AMemory Memory,
HSession Session,
KSession Session,
IpcMessage Request,
IpcMessage Response,
BinaryReader RequestData,

View file

@ -1,110 +0,0 @@
using Ryujinx.Core.OsHle.IpcServices;
using Ryujinx.Core.OsHle.IpcServices.Acc;
using Ryujinx.Core.OsHle.IpcServices.Am;
using Ryujinx.Core.OsHle.IpcServices.Apm;
using Ryujinx.Core.OsHle.IpcServices.Aud;
using Ryujinx.Core.OsHle.IpcServices.Bsd;
using Ryujinx.Core.OsHle.IpcServices.Friend;
using Ryujinx.Core.OsHle.IpcServices.FspSrv;
using Ryujinx.Core.OsHle.IpcServices.Hid;
using Ryujinx.Core.OsHle.IpcServices.Lm;
using Ryujinx.Core.OsHle.IpcServices.Nifm;
using Ryujinx.Core.OsHle.IpcServices.Ns;
using Ryujinx.Core.OsHle.IpcServices.NvServices;
using Ryujinx.Core.OsHle.IpcServices.Pctl;
using Ryujinx.Core.OsHle.IpcServices.Pl;
using Ryujinx.Core.OsHle.IpcServices.Set;
using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
using Ryujinx.Core.OsHle.IpcServices.Sm;
using Ryujinx.Core.OsHle.IpcServices.Ssl;
using Ryujinx.Core.OsHle.IpcServices.Time;
using Ryujinx.Core.OsHle.IpcServices.Vi;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle
{
class ServiceMgr : IDisposable
{
private Dictionary<string, IIpcService> Services;
public ServiceMgr()
{
Services = new Dictionary<string, IIpcService>();
}
public IIpcService GetService(string Name)
{
lock (Services)
{
if (!Services.TryGetValue(Name, out IIpcService Service))
{
switch (Name)
{
case "acc:u0": Service = new ServiceAcc(); break;
case "aoc:u": Service = new ServiceNs(); break;
case "apm": Service = new ServiceApm(); break;
case "apm:p": Service = new ServiceApm(); break;
case "appletOE": Service = new ServiceAppletOE(); break;
case "audout:u": Service = new ServiceAudOut(); break;
case "audren:u": Service = new ServiceAudRen(); break;
case "bsd:s": Service = new ServiceBsd(); break;
case "bsd:u": Service = new ServiceBsd(); break;
case "friend:a": Service = new ServiceFriend(); break;
case "fsp-srv": Service = new ServiceFspSrv(); break;
case "hid": Service = new ServiceHid(); break;
case "lm": Service = new ServiceLm(); break;
case "nifm:u": Service = new ServiceNifm(); break;
case "nvdrv": Service = new ServiceNvDrv(); break;
case "nvdrv:a": Service = new ServiceNvDrv(); break;
case "pctl:a": Service = new ServicePctl(); break;
case "pl:u": Service = new ServicePl(); break;
case "set": Service = new ServiceSet(); break;
case "set:sys": Service = new ServiceSetSys(); break;
case "sfdnsres": Service = new ServiceSfdnsres(); break;
case "sm:": Service = new ServiceSm(); break;
case "ssl": Service = new ServiceSsl(); break;
case "time:s": Service = new ServiceTime(); break;
case "time:u": Service = new ServiceTime(); break;
case "vi:m": Service = new ServiceVi(); break;
case "vi:s": Service = new ServiceVi(); break;
case "vi:u": Service = new ServiceVi(); break;
}
if (Service == null)
{
throw new NotImplementedException(Name);
}
Services.Add(Name, Service);
}
return Service;
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
lock (Services)
{
foreach (IIpcService Service in Services.Values)
{
if (Service is IDisposable DisposableSrv)
{
DisposableSrv.Dispose();
}
}
Services.Clear();
}
}
}
}
}

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Acc
namespace Ryujinx.Core.OsHle.Services.Acc
{
class IManagerForApplication : IIpcService
class IManagerForApplication : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IManagerForApplication()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Acc
namespace Ryujinx.Core.OsHle.Services.Acc
{
class IProfile : IIpcService
class IProfile : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IProfile()
{

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Acc
namespace Ryujinx.Core.OsHle.Services.Acc
{
class ServiceAcc : IIpcService
class ServiceAcc : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAcc()
{

View file

@ -0,0 +1,7 @@
namespace Ryujinx.Core.OsHle.Services.Am
{
static class AmErr
{
public const int NoMessages = 3;
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.Services.Am
{
enum FocusState
{
InFocus = 1,
OutOfFocus = 2
}
}

View file

@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using System.IO;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IApplicationFunctions : IIpcService
class IApplicationFunctions : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IApplicationFunctions()
{

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IApplicationProxy : IIpcService
class IApplicationProxy : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IApplicationProxy()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IAudioController : IIpcService
class IAudioController : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioController()
{

View file

@ -1,13 +1,16 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
using static Ryujinx.Core.OsHle.ErrorCode;
namespace Ryujinx.Core.OsHle.Services.Am
{
class ICommonStateGetter : IIpcService
class ICommonStateGetter : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ICommonStateGetter()
{
@ -17,37 +20,31 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
{ 1, ReceiveMessage },
{ 5, GetOperationMode },
{ 6, GetPerformanceMode },
{ 9, GetCurrentFocusState },
{ 9, GetCurrentFocusState }
};
}
private enum FocusState
{
InFocus = 1,
OutOfFocus = 2
}
private enum OperationMode
{
Handheld = 0,
Docked = 1
}
public long GetEventHandle(ServiceCtx Context)
{
Context.ResponseData.Write(0L);
KEvent Event = Context.Process.AppletState.MessageEvent;
int Handle = Context.Process.HandleTable.OpenHandle(Event);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0;
}
public 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);
if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message))
{
return MakeError(ErrorModule.Am, AmErr.NoMessages);
}
return 0; //0x680;
Context.ResponseData.Write((int)Message);
return 0;
}
public long GetOperationMode(ServiceCtx Context)
@ -66,7 +63,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
public long GetCurrentFocusState(ServiceCtx Context)
{
Context.ResponseData.Write((byte)FocusState.InFocus);
Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState);
return 0;
}

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IDebugFunctions : IIpcService
class IDebugFunctions : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IDebugFunctions()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IDisplayController : IIpcService
class IDisplayController : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IDisplayController()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class ILibraryAppletCreator : IIpcService
class ILibraryAppletCreator : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ILibraryAppletCreator()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class ISelfController : IIpcService
class ISelfController : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISelfController()
{

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IStorage : IIpcService
class IStorage : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public byte[] Data { get; private set; }

View file

@ -3,13 +3,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IStorageAccessor : IIpcService
class IStorageAccessor : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IStorage Storage;

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class IWindowController : IIpcService
class IWindowController : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IWindowController()
{

View file

@ -0,0 +1,9 @@
namespace Ryujinx.Core.OsHle.Services.Am
{
enum MessageInfo
{
FocusStateChanged = 0xf,
OperationModeChanged = 0x1e,
PerformanceModeChanged = 0x1f
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.Services.Am
{
enum OperationMode
{
Handheld = 0,
Docked = 1
}
}

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am
namespace Ryujinx.Core.OsHle.Services.Am
{
class ServiceAppletOE : IIpcService
class ServiceAppletOE : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAppletOE()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Apm
namespace Ryujinx.Core.OsHle.Services.Apm
{
class ISession : IIpcService
class ISession : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISession()
{

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Apm
namespace Ryujinx.Core.OsHle.Services.Apm
{
class ServiceApm : IIpcService
class ServiceApm : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceApm()
{

View file

@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace Ryujinx.Core.OsHle.Services.Aud
{
[StructLayout(LayoutKind.Sequential)]
struct AudioOutData
{
public long NextBufferPtr;
public long SampleBufferPtr;
public long SampleBufferCapacity;
public long SampleBufferSize;
public long SampleBufferInnerOffset;
}
}

View file

@ -3,13 +3,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.Aud
namespace Ryujinx.Core.OsHle.Services.Aud
{
class IAudioDevice : IIpcService
class IAudioDevice : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioDevice()
{
@ -55,7 +55,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
long Position = Context.Request.SendBuff[0].Position;
long Size = Context.Request.SendBuff[0].Size;
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position, (int)Size);
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position, Size);
return 0;
}

View file

@ -1,145 +1,86 @@
using ChocolArm64.Memory;
using Ryujinx.Audio;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using System;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.Aud
namespace Ryujinx.Core.OsHle.Services.Aud
{
class IAudioOut : IIpcService, IDisposable
class IAudioOut : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioOut()
private IAalOutput AudioOut;
private KEvent ReleaseEvent;
private int Track;
public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, GetAudioOutState },
{ 1, StartAudioOut },
{ 2, StopAudioOut },
{ 3, AppendAudioOutBuffer },
{ 4, RegisterBufferEvent },
{ 5, GetReleasedAudioOutBuffer },
{ 6, ContainsAudioOutBuffer },
{ 7, AppendAudioOutBuffer_ex },
{ 8, GetReleasedAudioOutBuffer_ex }
{ 0, GetAudioOutState },
{ 1, StartAudioOut },
{ 2, StopAudioOut },
{ 3, AppendAudioOutBuffer },
{ 4, RegisterBufferEvent },
{ 5, GetReleasedAudioOutBuffer },
{ 6, ContainsAudioOutBuffer },
{ 7, AppendAudioOutBufferEx },
{ 8, GetReleasedAudioOutBufferEx }
};
this.AudioOut = AudioOut;
this.ReleaseEvent = ReleaseEvent;
this.Track = Track;
}
enum AudioOutState
{
Started,
Stopped
};
//IAudioOut
private AudioOutState State = AudioOutState.Stopped;
private Queue<long> BufferIdQueue = new Queue<long>();
//OpenAL
private bool OpenALInstalled = true;
private AudioContext AudioCtx;
private int Source;
private int Buffer;
//Return State of IAudioOut
public long GetAudioOutState(ServiceCtx Context)
{
Context.ResponseData.Write((int)State);
Context.ResponseData.Write((int)AudioOut.GetState(Track));
return 0;
}
public long StartAudioOut(ServiceCtx Context)
{
if (State == AudioOutState.Stopped)
{
State = AudioOutState.Started;
try
{
AudioCtx = new AudioContext(); //Create the audio context
}
catch (Exception)
{
Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!");
OpenALInstalled = false;
}
if (OpenALInstalled) AL.Listener(ALListenerf.Gain, 8.0f); //Add more gain to it
}
AudioOut.Start(Track);
return 0;
}
public long StopAudioOut(ServiceCtx Context)
{
if (State == AudioOutState.Started)
{
if (OpenALInstalled)
{
if (AudioCtx == null) //Needed to call the instance of AudioContext()
return 0;
AL.SourceStop(Source);
AL.DeleteSource(Source);
AL.DeleteBuffers(1, ref Buffer);
}
State = AudioOutState.Stopped;
}
AudioOut.Stop(Track);
return 0;
}
public long AppendAudioOutBuffer(ServiceCtx Context)
{
long BufferId = Context.RequestData.ReadInt64();
long Tag = Context.RequestData.ReadInt64();
byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5);
AudioOutData Data = AMemoryHelper.Read<AudioOutData>(
Context.Memory,
Context.Request.SendBuff[0].Position);
byte[] Buffer = AMemoryHelper.ReadBytes(
Context.Memory,
Data.SampleBufferPtr,
Data.SampleBufferSize);
using (MemoryStream MS = new MemoryStream(AudioOutBuffer))
{
BinaryReader Reader = new BinaryReader(MS);
long PointerNextBuffer = Reader.ReadInt64();
long PointerSampleBuffer = Reader.ReadInt64();
long CapacitySampleBuffer = Reader.ReadInt64();
long SizeDataInSampleBuffer = Reader.ReadInt64();
long OffsetDataInSampleBuffer = Reader.ReadInt64();
if (SizeDataInSampleBuffer > 0)
{
BufferIdQueue.Enqueue(BufferId);
byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer);
if (OpenALInstalled)
{
if (AudioCtx == null) //Needed to call the instance of AudioContext()
return 0;
EnsureAudioFinalized();
Source = AL.GenSource();
Buffer = AL.GenBuffer();
AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000);
AL.SourceQueueBuffer(Source, Buffer);
AL.SourcePlay(Source);
}
}
}
AudioOut.AppendBuffer(Track, Tag, Buffer);
return 0;
}
public long RegisterBufferEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
@ -148,62 +89,65 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long GetReleasedAudioOutBuffer(ServiceCtx Context)
{
int ReleasedBuffersCount = 0;
long Position = Context.Request.ReceiveBuff[0].Position;
long Size = Context.Request.ReceiveBuff[0].Size;
for(int i = 0; i < BufferIdQueue.Count; i++)
uint Count = (uint)((ulong)Size >> 3);
long[] ReleasedBuffers = AudioOut.GetReleasedBuffers(Track, (int)Count);
for (uint Index = 0; Index < Count; Index++)
{
long BufferId = BufferIdQueue.Dequeue();
long Tag = 0;
AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position + (8 * i), BitConverter.GetBytes(BufferId));
if (Index < ReleasedBuffers.Length)
{
Tag = ReleasedBuffers[Index];
}
ReleasedBuffersCount++;
Context.Memory.WriteInt64(Position + Index * 8, Tag);
}
Context.ResponseData.Write(ReleasedBuffersCount);
Context.ResponseData.Write(ReleasedBuffers.Length);
return 0;
}
public long ContainsAudioOutBuffer(ServiceCtx Context)
{
long Tag = Context.RequestData.ReadInt64();
Context.ResponseData.Write(AudioOut.ContainsBuffer(Track, Tag) ? 1 : 0);
return 0;
}
public long AppendAudioOutBuffer_ex(ServiceCtx Context)
public long AppendAudioOutBufferEx(ServiceCtx Context)
{
Logging.Warn("Not implemented!");
return 0;
}
public long GetReleasedAudioOutBuffer_ex(ServiceCtx Context)
public long GetReleasedAudioOutBufferEx(ServiceCtx Context)
{
Logging.Warn("Not implemented!");
return 0;
}
private void EnsureAudioFinalized()
{
if (Source != 0 ||
Buffer != 0)
{
AL.SourceStop(Source);
AL.SourceUnqueueBuffer(Buffer);
AL.DeleteSource(Source);
AL.DeleteBuffers(1, ref Buffer);
Source = 0;
Buffer = 0;
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
protected virtual void Dispose(bool Disposing)
{
if (disposing)
if (Disposing)
{
EnsureAudioFinalized();
AudioOut.CloseTrack(Track);
ReleaseEvent.Dispose();
}
}
}

View file

@ -1,14 +1,17 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Aud
namespace Ryujinx.Core.OsHle.Services.Aud
{
class IAudioRenderer : IIpcService
class IAudioRenderer : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent UpdateEvent;
public IAudioRenderer()
{
@ -19,6 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ 6, StopAudioRenderer },
{ 7, QuerySystemEvent }
};
UpdateEvent = new KEvent();
}
public long RequestUpdateAudioRenderer(ServiceCtx Context)
@ -41,6 +46,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
Context.Memory.WriteInt32(Position + Offset, 5);
}
//TODO: We shouldn't be signaling this here.
UpdateEvent.Handle.Set();
return 0;
}
@ -56,11 +64,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long QuerySystemEvent(ServiceCtx Context)
{
int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
UpdateEvent.Dispose();
}
}
}
}

View file

@ -1,24 +1,24 @@
using ChocolArm64.Memory;
using Ryujinx.Audio;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using System.Text;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud
namespace Ryujinx.Core.OsHle.Services.Aud
{
class ServiceAudOut : IIpcService
class ServiceAudOut : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudOut()
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
{ 0, ListAudioOuts },
{ 1, OpenAudioOut },
{ 1, OpenAudioOut }
};
}
@ -35,21 +35,58 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long OpenAudioOut(ServiceCtx Context)
{
MakeObject(Context, new IAudioOut());
IAalOutput AudioOut = Context.Ns.AudioOut;
Context.ResponseData.Write(48000); //Sample Rate
Context.ResponseData.Write(2); //Channel Count
Context.ResponseData.Write(2); //PCM Format
/*
0 - Invalid
1 - INT8
2 - INT16
3 - INT24
4 - INT32
5 - PCM Float
6 - ADPCM
*/
Context.ResponseData.Write(0); //Unknown
string DeviceName = AMemoryHelper.ReadAsciiString(
Context.Memory,
Context.Request.SendBuff[0].Position,
Context.Request.SendBuff[0].Size);
if (DeviceName == string.Empty)
{
DeviceName = "FIXME";
}
long DeviceNamePosition = Context.Request.ReceiveBuff[0].Position;
long DeviceNameSize = Context.Request.ReceiveBuff[0].Size;
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DeviceName);
if (DeviceName.Length <= DeviceNameSize)
{
AMemoryHelper.WriteBytes(Context.Memory, DeviceNamePosition, DeviceNameBuffer);
}
int SampleRate = Context.RequestData.ReadInt32();
int Channels = Context.RequestData.ReadInt32();
Channels = (ushort)(Channels >> 16);
if (SampleRate == 0)
{
SampleRate = 48000;
}
if (Channels < 1 || Channels > 2)
{
Channels = 2;
}
KEvent ReleaseEvent = new KEvent();
ReleaseCallback Callback = () =>
{
ReleaseEvent.Handle.Set();
};
int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format);
MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));
Context.ResponseData.Write(SampleRate);
Context.ResponseData.Write(Channels);
Context.ResponseData.Write((int)Format);
Context.ResponseData.Write((int)PlaybackState.Stopped);
return 0;
}

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud
namespace Ryujinx.Core.OsHle.Services.Aud
{
class ServiceAudRen : IIpcService
class ServiceAudRen : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudRen()
{

View file

@ -8,7 +8,7 @@ using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Ryujinx.Core.OsHle.IpcServices.Bsd
namespace Ryujinx.Core.OsHle.Services.Bsd
{
//bsd_errno == (SocketException.ErrorCode - 10000)
@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
public Socket Handle;
}
class ServiceBsd : IIpcService
class ServiceBsd : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private List<SocketBsd> Sockets = new List<SocketBsd>();
@ -151,7 +151,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
Context.Request.SendBuff[0].Position,
(int)Context.Request.SendBuff[0].Size);
Context.Request.SendBuff[0].Size);
int SocketId = Get32(SentBuffer, 0);
short RequestedEvents = (short)Get16(SentBuffer, 4);
short ReturnedEvents = (short)Get16(SentBuffer, 6);
@ -197,7 +197,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
int SocketFlags = Context.RequestData.ReadInt32();
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
Context.Request.SendBuff[0].Position,
(int)Context.Request.SendBuff[0].Size);
Context.Request.SendBuff[0].Size);
try
{
@ -224,10 +224,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
int SocketFlags = Context.RequestData.ReadInt32();
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
Context.Request.SendBuff[0].Position,
(int)Context.Request.SendBuff[0].Size);
Context.Request.SendBuff[0].Size);
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
Context.Request.SendBuff[1].Position,
(int)Context.Request.SendBuff[1].Size);
Context.Request.SendBuff[1].Size);
if (!Sockets[SocketId].Handle.Connected)
{
@ -333,7 +333,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
Context.Request.SendBuff[0].Position,
(int)Context.Request.SendBuff[0].Size);
Context.Request.SendBuff[0].Size);
try
{
@ -358,7 +358,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
Context.Request.SendBuff[0].Position,
(int)Context.Request.SendBuff[0].Size);
Context.Request.SendBuff[0].Size);
try
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Friend
namespace Ryujinx.Core.OsHle.Services.Friend
{
class IFriendService : IIpcService
class IFriendService : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IFriendService()
{

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Friend
namespace Ryujinx.Core.OsHle.Services.Friend
{
class ServiceFriend : IIpcService
class ServiceFriend : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceFriend()
{

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
namespace Ryujinx.Core.OsHle.Services.FspSrv
{
static class FsErr
{

View file

@ -5,15 +5,15 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
namespace Ryujinx.Core.OsHle.Services.FspSrv
{
class IDirectory : IIpcService, IDisposable
class IDirectory : IpcService, IDisposable
{
private const int DirectoryEntrySize = 0x310;
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private List<string> DirectoryEntries;

View file

@ -4,13 +4,13 @@ using System;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
namespace Ryujinx.Core.OsHle.Services.FspSrv
{
class IFile : IIpcService, IDisposable
class IFile : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Stream BaseStream;
@ -62,7 +62,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
long Offset = Context.RequestData.ReadInt64();
long Size = Context.RequestData.ReadInt64();
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)Size);
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, Size);
BaseStream.Seek(Offset, SeekOrigin.Begin);
BaseStream.Write(Data, 0, (int)Size);

View file

@ -5,15 +5,14 @@ using System.IO;
using System.Text;
using static Ryujinx.Core.OsHle.ErrorCode;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
namespace Ryujinx.Core.OsHle.Services.FspSrv
{
class IFileSystem : IIpcService
class IFileSystem : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private HashSet<string> OpenPaths;

View file

@ -3,13 +3,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
namespace Ryujinx.Core.OsHle.Services.FspSrv
{
class IStorage : IIpcService
class IStorage : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Stream BaseStream;

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
namespace Ryujinx.Core.OsHle.Services.FspSrv
{
class ServiceFspSrv : IIpcService
class ServiceFspSrv : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceFspSrv()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Hid
namespace Ryujinx.Core.OsHle.Services.Hid
{
class IActiveApplicationDeviceList : IIpcService
class IActiveApplicationDeviceList : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IActiveApplicationDeviceList()
{

View file

@ -2,13 +2,13 @@ using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Hid
namespace Ryujinx.Core.OsHle.Services.Hid
{
class IAppletResource : IIpcService
class IAppletResource : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private HSharedMem HidSharedMem;

View file

@ -1,16 +1,14 @@
using Ryujinx.Core.Input;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using Ryujinx.Core.Input;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Hid
namespace Ryujinx.Core.OsHle.Services.Hid
{
class ServiceHid : IIpcService
class ServiceHid : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceHid()
{

View file

@ -1,7 +1,7 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices
namespace Ryujinx.Core.OsHle.Services
{
interface IIpcService
{

View file

@ -0,0 +1,151 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Core.OsHle.Services
{
abstract class IpcService : IIpcService
{
public abstract IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
private IdDictionary DomainObjects;
private int SelfId;
private bool IsDomain;
public IpcService()
{
DomainObjects = new IdDictionary();
SelfId = -1;
}
public int ConvertToDomain()
{
if (SelfId == -1)
{
SelfId = DomainObjects.Add(this);
}
IsDomain = true;
return SelfId;
}
public void ConvertToSession()
{
IsDomain = false;
}
public void CallMethod(ServiceCtx Context)
{
IIpcService Service = this;
if (IsDomain)
{
int DomainWord0 = Context.RequestData.ReadInt32();
int DomainObjId = Context.RequestData.ReadInt32();
long Padding = Context.RequestData.ReadInt64();
int DomainCmd = DomainWord0 & 0xff;
if (DomainCmd == 1)
{
Service = GetObject(DomainObjId);
Context.ResponseData.Write(0L);
Context.ResponseData.Write(0L);
}
else if (DomainCmd == 2)
{
Delete(DomainObjId);
Context.ResponseData.Write(0L);
return;
}
else
{
throw new NotImplementedException($"Domain command: {DomainCmd}");
}
}
long SfciMagic = Context.RequestData.ReadInt64();
int CommandId = (int)Context.RequestData.ReadInt64();
if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest))
{
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin);
Logging.Trace($"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
long Result = ProcessRequest(Context);
if (IsDomain)
{
foreach (int Id in Context.Response.ResponseObjIds)
{
Context.ResponseData.Write(Id);
}
Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin);
Context.ResponseData.Write(Context.Response.ResponseObjIds.Count);
}
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin);
Context.ResponseData.Write(IpcMagic.Sfco);
Context.ResponseData.Write(Result);
}
else
{
throw new NotImplementedException($"{Service.GetType().Name}: {CommandId}");
}
}
protected static void MakeObject(ServiceCtx Context, IpcService Obj)
{
IpcService Service = Context.Session.Service;
if (Service.IsDomain)
{
Context.Response.ResponseObjIds.Add(Service.Add(Obj));
}
else
{
KSession Session = new KSession(Obj);
int Handle = Context.Process.HandleTable.OpenHandle(Session);
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
}
}
private int Add(IIpcService Obj)
{
return DomainObjects.Add(Obj);
}
private bool Delete(int Id)
{
object Obj = DomainObjects.Delete(Id);
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
return Obj != null;
}
private IIpcService GetObject(int Id)
{
return DomainObjects.GetData<IIpcService>(Id);
}
}
}

View file

@ -5,13 +5,13 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.Lm
namespace Ryujinx.Core.OsHle.Services.Lm
{
class ILogger : IIpcService
class ILogger : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ILogger()
{
@ -54,7 +54,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
long BufferPosition = Context.Request.PtrBuff[0].Position;
long BufferLen = Context.Request.PtrBuff[0].Size;
byte[] LogBuffer = AMemoryHelper.ReadBytes(Context.Memory, BufferPosition, (int)BufferLen);
byte[] LogBuffer = AMemoryHelper.ReadBytes(Context.Memory, BufferPosition, BufferLen);
MemoryStream LogMessage = new MemoryStream(LogBuffer);
BinaryReader bReader = new BinaryReader(LogMessage);

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Lm
namespace Ryujinx.Core.OsHle.Services.Lm
{
class ServiceLm : IIpcService
class ServiceLm : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceLm()
{
@ -21,8 +19,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
public long Initialize(ServiceCtx Context)
{
Context.Session.Initialize();
MakeObject(Context, new ILogger());
return 0;

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
namespace Ryujinx.Core.OsHle.Services.Nifm
{
class IGeneralService : IIpcService
class IGeneralService : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IGeneralService()
{

View file

@ -1,13 +1,17 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
namespace Ryujinx.Core.OsHle.Services.Nifm
{
class IRequest : IIpcService
class IRequest : IpcService, IDisposable
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent Event;
public IRequest()
{
@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ 1, GetResult },
{ 2, GetSystemEventReadableHandles }
};
Event = new KEvent();
}
// -> i32
public long GetRequestState(ServiceCtx Context)
{
Context.ResponseData.Write(0);
@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
//GetSystemEventReadableHandles() -> (KObject, KObject)
public long GetSystemEventReadableHandles(ServiceCtx Context)
{
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe);
//FIXME: Is this supposed to return 2 events?
int Handle = Context.Process.HandleTable.OpenHandle(Event);
//Todo: Stub
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
return 0;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
}
}
}

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
namespace Ryujinx.Core.OsHle.Services.Nifm
{
class ServiceNifm : IIpcService
class ServiceNifm : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceNifm()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Ns
namespace Ryujinx.Core.OsHle.Services.Ns
{
class ServiceNs : IIpcService
class ServiceNs : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceNs()
{

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Core.OsHle.IpcServices.NvServices
namespace Ryujinx.Core.OsHle.Services.Nv
{
class NvFd
{

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Core.OsHle.IpcServices.NvServices
namespace Ryujinx.Core.OsHle.Services.Nv
{
class NvMap
{
@ -7,6 +7,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
public int Size;
public int Align;
public int Kind;
public long Address;
public long CpuAddress;
}
}

View file

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.Services.Nv
{
class NvMapFb
{
private List<long> BufferOffs;
public NvMapFb()
{
BufferOffs = new List<long>();
}
public void AddBufferOffset(long Offset)
{
BufferOffs.Add(Offset);
}
public bool HasBufferOffset(int Index)
{
if ((uint)Index >= BufferOffs.Count)
{
return false;
}
return true;
}
public long GetBufferOffset(int Index)
{
if ((uint)Index >= BufferOffs.Count)
{
throw new ArgumentOutOfRangeException(nameof(Index));
}
return BufferOffs[Index];
}
}
}

View file

@ -1,26 +1,30 @@
using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.Utilities;
using Ryujinx.Graphics.Gpu;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.NvServices
namespace Ryujinx.Core.OsHle.Services.Nv
{
class ServiceNvDrv : IIpcService
class ServiceNvDrv : IpcService, IDisposable
{
private delegate long ServiceProcessIoctl(ServiceCtx Context);
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
private IdDictionary Fds;
public static GlobalStateTable Fds { get; private set; }
private IdDictionary NvMaps;
private IdDictionary NvMapsById;
public static GlobalStateTable NvMaps { get; private set; }
public static GlobalStateTable NvMapsById { get; private set; }
public static GlobalStateTable NvMapsFb { get; private set; }
private KEvent Event;
public ServiceNvDrv()
{
@ -64,10 +68,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ ("/dev/nvmap", 0x010e), NvMapIocGetId },
};
Fds = new IdDictionary();
Event = new KEvent();
}
NvMaps = new IdDictionary();
NvMapsById = new IdDictionary();
static ServiceNvDrv()
{
Fds = new GlobalStateTable();
NvMaps = new GlobalStateTable();
NvMapsById = new GlobalStateTable();
NvMapsFb = new GlobalStateTable();
}
public long Open(ServiceCtx Context)
@ -76,7 +86,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
int Fd = Fds.Add(new NvFd(Name));
int Fd = Fds.Add(Context.Process, new NvFd(Name));
Context.ResponseData.Write(Fd);
Context.ResponseData.Write(0);
@ -89,7 +99,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Fd = Context.RequestData.ReadInt32();
int Cmd = Context.RequestData.ReadInt32() & 0xffff;
NvFd FdData = Fds.GetData<NvFd>(Fd);
NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
long Position = Context.Request.GetSendBuffPtr();
@ -109,7 +119,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{
int Fd = Context.RequestData.ReadInt32();
Fds.Delete(Fd);
Fds.Delete(Context.Process, Fd);
Context.ResponseData.Write(0);
@ -123,6 +133,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
Context.ResponseData.Write(0);
NvMapsFb.Add(Context.Process, 0, new NvMapFb());
return 0;
}
@ -131,7 +143,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Fd = Context.RequestData.ReadInt32();
int EventId = Context.RequestData.ReadInt32();
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe);
//TODO: Use Fd/EventId, different channels have different events.
int Handle = Context.Process.HandleTable.OpenHandle(Event);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
Context.ResponseData.Write(0);
@ -198,12 +213,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
if (Handle == 0)
{
//Handle 0 is valid here, but it refers to something else.
//TODO: Figure out what, for now just return success.
//This is used to store offsets for the Framebuffer(s);
NvMapFb MapFb = (NvMapFb)NvMapsFb.GetData(Context.Process, 0);
MapFb.AddBufferOffset(BuffAddr);
return 0;
}
NvMap Map = NvMaps.GetData<NvMap>(Handle);
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null)
{
@ -214,11 +232,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
if ((Flags & 1) != 0)
{
Offset = Context.Ns.Gpu.MapMemory(Map.Address, Offset, Map.Size);
Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Offset, Map.Size);
}
else
{
Offset = Context.Ns.Gpu.MapMemory(Map.Address, Map.Size);
Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Map.Size);
}
Context.Memory.WriteInt64(Position + 0x20, Offset);
@ -550,9 +568,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
NvMap Map = new NvMap() { Size = Size };
Map.Handle = NvMaps.Add(Map);
Map.Handle = NvMaps.Add(Context.Process, Map);
Map.Id = NvMapsById.Add(Map);
Map.Id = NvMapsById.Add(Context.Process, Map);
Context.Memory.WriteInt32(Position + 4, Map.Handle);
@ -567,7 +585,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Id = Context.Memory.ReadInt32(Position);
NvMap Map = NvMapsById.GetData<NvMap>(Id);
NvMap Map = NvMapsById.GetData<NvMap>(Context.Process, Id);
if (Map == null)
{
@ -594,7 +612,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
byte Kind = (byte)Reader.ReadInt64();
long Addr = Reader.ReadInt64();
NvMap Map = NvMaps.GetData<NvMap>(Handle);
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null)
{
@ -603,7 +621,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return -1; //TODO: Corrent error code.
}
Map.Address = Addr;
Map.CpuAddress = Addr;
Map.Align = Align;
Map.Kind = Kind;
@ -620,7 +638,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32();
int Padding = Reader.ReadInt32();
NvMap Map = NvMaps.GetData<NvMap>(Handle);
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null)
{
@ -645,7 +663,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32();
int Param = Reader.ReadInt32();
NvMap Map = NvMaps.GetData<NvMap>(Handle);
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null)
{
@ -675,7 +693,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Context.Memory.ReadInt32(Position + 4);
NvMap Map = NvMaps.GetData<NvMap>(Handle);
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null)
{
@ -689,9 +707,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0;
}
public NvMap GetNvMap(int Handle)
public void Dispose()
{
return NvMaps.GetData<NvMap>(Handle);
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
}
}
}

View file

@ -1,24 +0,0 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
namespace Ryujinx.Core.OsHle.IpcServices
{
static class ObjHelper
{
public static void MakeObject(ServiceCtx Context, object Obj)
{
if (Context.Session is HDomain Dom)
{
Context.Response.ResponseObjIds.Add(Dom.Add(Obj));
}
else
{
HSessionObj HndData = new HSessionObj(Context.Session, Obj);
int VHandle = Context.Process.HandleTable.OpenHandle(HndData);
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
}
}
}
}

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Pctl
namespace Ryujinx.Core.OsHle.Services.Pctl
{
class IParentalControlService : IIpcService
class IParentalControlService : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IParentalControlService()
{

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Pctl
namespace Ryujinx.Core.OsHle.Services.Pctl
{
class ServicePctl : IIpcService
class ServicePctl : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServicePctl()
{

View file

@ -1,13 +1,13 @@
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Pl
namespace Ryujinx.Core.OsHle.Services.Pl
{
class ServicePl : IIpcService
class ServicePl : IpcService
{
private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServicePl()
{

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Core.OsHle.IpcServices.Pl
namespace Ryujinx.Core.OsHle.Services.Pl
{
enum SharedFontType
{

Some files were not shown because too many files have changed in this diff Show more