This reverts commit 85dbb9559a
.
This commit is contained in:
parent
85dbb9559a
commit
3615a70cae
299 changed files with 12276 additions and 12268 deletions
|
@ -10,13 +10,13 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
{
|
||||
class IAccountService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAccountService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetUserCount },
|
||||
{ 1, GetUserExistence },
|
||||
|
@ -32,131 +32,131 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
}
|
||||
|
||||
// GetUserCount() -> i32
|
||||
public long GetUserCount(ServiceCtx context)
|
||||
public long GetUserCount(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(context.Device.System.State.GetUserCount());
|
||||
Context.ResponseData.Write(Context.Device.System.State.GetUserCount());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetUserExistence(nn::account::Uid) -> bool
|
||||
public long GetUserExistence(ServiceCtx context)
|
||||
public long GetUserExistence(ServiceCtx Context)
|
||||
{
|
||||
UInt128 uuid = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
context.ResponseData.Write(context.Device.System.State.TryGetUser(uuid, out _));
|
||||
Context.ResponseData.Write(Context.Device.System.State.TryGetUser(Uuid, out _));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ListAllUsers() -> array<nn::account::Uid, 0xa>
|
||||
public long ListAllUsers(ServiceCtx context)
|
||||
public long ListAllUsers(ServiceCtx Context)
|
||||
{
|
||||
return WriteUserList(context, context.Device.System.State.GetAllUsers());
|
||||
return WriteUserList(Context, Context.Device.System.State.GetAllUsers());
|
||||
}
|
||||
|
||||
// ListOpenUsers() -> array<nn::account::Uid, 0xa>
|
||||
public long ListOpenUsers(ServiceCtx context)
|
||||
public long ListOpenUsers(ServiceCtx Context)
|
||||
{
|
||||
return WriteUserList(context, context.Device.System.State.GetOpenUsers());
|
||||
return WriteUserList(Context, Context.Device.System.State.GetOpenUsers());
|
||||
}
|
||||
|
||||
private long WriteUserList(ServiceCtx context, IEnumerable<UserProfile> profiles)
|
||||
private long WriteUserList(ServiceCtx Context, IEnumerable<UserProfile> Profiles)
|
||||
{
|
||||
long outputPosition = context.Request.RecvListBuff[0].Position;
|
||||
long outputSize = context.Request.RecvListBuff[0].Size;
|
||||
long OutputPosition = Context.Request.RecvListBuff[0].Position;
|
||||
long OutputSize = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
long offset = 0;
|
||||
long Offset = 0;
|
||||
|
||||
foreach (UserProfile profile in profiles)
|
||||
foreach (UserProfile Profile in Profiles)
|
||||
{
|
||||
if ((ulong)offset + 16 > (ulong)outputSize)
|
||||
if ((ulong)Offset + 16 > (ulong)OutputSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
context.Memory.WriteInt64(outputPosition, profile.Uuid.Low);
|
||||
context.Memory.WriteInt64(outputPosition + 8, profile.Uuid.High);
|
||||
Context.Memory.WriteInt64(OutputPosition, Profile.Uuid.Low);
|
||||
Context.Memory.WriteInt64(OutputPosition + 8, Profile.Uuid.High);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetLastOpenedUser() -> nn::account::Uid
|
||||
public long GetLastOpenedUser(ServiceCtx context)
|
||||
public long GetLastOpenedUser(ServiceCtx Context)
|
||||
{
|
||||
UserProfile lastOpened = context.Device.System.State.LastOpenUser;
|
||||
UserProfile LastOpened = Context.Device.System.State.LastOpenUser;
|
||||
|
||||
lastOpened.Uuid.Write(context.ResponseData);
|
||||
LastOpened.Uuid.Write(Context.ResponseData);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetProfile(nn::account::Uid) -> object<nn::account::profile::IProfile>
|
||||
public long GetProfile(ServiceCtx context)
|
||||
public long GetProfile(ServiceCtx Context)
|
||||
{
|
||||
UInt128 uuid = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
if (!context.Device.System.State.TryGetUser(uuid, out UserProfile profile))
|
||||
if (!Context.Device.System.State.TryGetUser(Uuid, out UserProfile Profile))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceAcc, $"User 0x{uuid} not found!");
|
||||
Logger.PrintWarning(LogClass.ServiceAcc, $"User 0x{Uuid} not found!");
|
||||
|
||||
return MakeError(ErrorModule.Account, AccErr.UserNotFound);
|
||||
}
|
||||
|
||||
MakeObject(context, new IProfile(profile));
|
||||
MakeObject(Context, new IProfile(Profile));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// IsUserRegistrationRequestPermitted(u64, pid) -> bool
|
||||
public long IsUserRegistrationRequestPermitted(ServiceCtx context)
|
||||
public long IsUserRegistrationRequestPermitted(ServiceCtx Context)
|
||||
{
|
||||
long unknown = context.RequestData.ReadInt64();
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {unknown}");
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {Unknown}");
|
||||
|
||||
context.ResponseData.Write(false);
|
||||
Context.ResponseData.Write(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TrySelectUserWithoutInteraction(bool) -> nn::account::Uid
|
||||
public long TrySelectUserWithoutInteraction(ServiceCtx context)
|
||||
public long TrySelectUserWithoutInteraction(ServiceCtx Context)
|
||||
{
|
||||
bool unknown = context.RequestData.ReadBoolean();
|
||||
bool Unknown = Context.RequestData.ReadBoolean();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {unknown}");
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {Unknown}");
|
||||
|
||||
UserProfile profile = context.Device.System.State.LastOpenUser;
|
||||
UserProfile Profile = Context.Device.System.State.LastOpenUser;
|
||||
|
||||
profile.Uuid.Write(context.ResponseData);
|
||||
Profile.Uuid.Write(Context.ResponseData);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// InitializeApplicationInfo(u64, pid)
|
||||
public long InitializeApplicationInfo(ServiceCtx context)
|
||||
public long InitializeApplicationInfo(ServiceCtx Context)
|
||||
{
|
||||
long unknown = context.RequestData.ReadInt64();
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {unknown}");
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {Unknown}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetBaasAccountManagerForApplication(nn::account::Uid) -> object<nn::account::baas::IManagerForApplication>
|
||||
public long GetBaasAccountManagerForApplication(ServiceCtx context)
|
||||
public long GetBaasAccountManagerForApplication(ServiceCtx Context)
|
||||
{
|
||||
UInt128 uuid = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
MakeObject(context, new IManagerForApplication(uuid));
|
||||
MakeObject(Context, new IManagerForApplication(Uuid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,25 +7,25 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
{
|
||||
class IManagerForApplication : IpcService
|
||||
{
|
||||
private UInt128 _uuid;
|
||||
private UInt128 Uuid;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IManagerForApplication(UInt128 uuid)
|
||||
public IManagerForApplication(UInt128 Uuid)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CheckAvailability },
|
||||
{ 1, GetAccountId }
|
||||
};
|
||||
|
||||
_uuid = uuid;
|
||||
this.Uuid = Uuid;
|
||||
}
|
||||
|
||||
// CheckAvailability()
|
||||
public long CheckAvailability(ServiceCtx context)
|
||||
public long CheckAvailability(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
|
||||
|
@ -33,13 +33,13 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
}
|
||||
|
||||
// GetAccountId() -> nn::account::NetworkServiceAccountId
|
||||
public long GetAccountId(ServiceCtx context)
|
||||
public long GetAccountId(ServiceCtx Context)
|
||||
{
|
||||
long networkServiceAccountId = 0xcafe;
|
||||
long NetworkServiceAccountId = 0xcafe;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. NetworkServiceAccountId: {networkServiceAccountId}");
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. NetworkServiceAccountId: {NetworkServiceAccountId}");
|
||||
|
||||
context.ResponseData.Write(networkServiceAccountId);
|
||||
Context.ResponseData.Write(NetworkServiceAccountId);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,76 +12,76 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
{
|
||||
class IProfile : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private UserProfile _profile;
|
||||
private UserProfile Profile;
|
||||
|
||||
private Stream _profilePictureStream;
|
||||
private Stream ProfilePictureStream;
|
||||
|
||||
public IProfile(UserProfile profile)
|
||||
public IProfile(UserProfile Profile)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Get },
|
||||
{ 1, GetBase },
|
||||
{ 10, GetImageSize },
|
||||
{ 11, LoadImage }
|
||||
{ 11, LoadImage },
|
||||
};
|
||||
|
||||
_profile = profile;
|
||||
this.Profile = Profile;
|
||||
|
||||
_profilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg");
|
||||
ProfilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg");
|
||||
}
|
||||
|
||||
public long Get(ServiceCtx context)
|
||||
public long Get(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
|
||||
long position = context.Request.ReceiveBuff[0].Position;
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, position, 0x80);
|
||||
MemoryHelper.FillWithZeros(Context.Memory, Position, 0x80);
|
||||
|
||||
context.Memory.WriteInt32(position, 0);
|
||||
context.Memory.WriteInt32(position + 4, 1);
|
||||
context.Memory.WriteInt64(position + 8, 1);
|
||||
Context.Memory.WriteInt32(Position, 0);
|
||||
Context.Memory.WriteInt32(Position + 4, 1);
|
||||
Context.Memory.WriteInt64(Position + 8, 1);
|
||||
|
||||
return GetBase(context);
|
||||
return GetBase(Context);
|
||||
}
|
||||
|
||||
public long GetBase(ServiceCtx context)
|
||||
public long GetBase(ServiceCtx Context)
|
||||
{
|
||||
_profile.Uuid.Write(context.ResponseData);
|
||||
Profile.Uuid.Write(Context.ResponseData);
|
||||
|
||||
context.ResponseData.Write(_profile.LastModifiedTimestamp);
|
||||
Context.ResponseData.Write(Profile.LastModifiedTimestamp);
|
||||
|
||||
byte[] username = StringUtils.GetFixedLengthBytes(_profile.Name, 0x20, Encoding.UTF8);
|
||||
byte[] Username = StringUtils.GetFixedLengthBytes(Profile.Name, 0x20, Encoding.UTF8);
|
||||
|
||||
context.ResponseData.Write(username);
|
||||
Context.ResponseData.Write(Username);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long LoadImage(ServiceCtx context)
|
||||
private long LoadImage(ServiceCtx Context)
|
||||
{
|
||||
long bufferPosition = context.Request.ReceiveBuff[0].Position;
|
||||
long bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||
long BufferPosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long BufferLen = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
byte[] profilePictureData = new byte[bufferLen];
|
||||
byte[] ProfilePictureData = new byte[BufferLen];
|
||||
|
||||
_profilePictureStream.Read(profilePictureData, 0, profilePictureData.Length);
|
||||
ProfilePictureStream.Read(ProfilePictureData, 0, ProfilePictureData.Length);
|
||||
|
||||
context.Memory.WriteBytes(bufferPosition, profilePictureData);
|
||||
Context.Memory.WriteBytes(BufferPosition, ProfilePictureData);
|
||||
|
||||
context.ResponseData.Write(_profilePictureStream.Length);
|
||||
Context.ResponseData.Write(ProfilePictureStream.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long GetImageSize(ServiceCtx context)
|
||||
private long GetImageSize(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(_profilePictureStream.Length);
|
||||
Context.ResponseData.Write(ProfilePictureStream.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IAllSystemAppletProxiesService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAllSystemAppletProxiesService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 100, OpenSystemAppletProxy }
|
||||
};
|
||||
}
|
||||
|
||||
public long OpenSystemAppletProxy(ServiceCtx context)
|
||||
public long OpenSystemAppletProxy(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ISystemAppletProxy());
|
||||
MakeObject(Context, new ISystemAppletProxy());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IApplicationCreator : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationCreator()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -6,13 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IApplicationFunctions : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationFunctions()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, PopLaunchParameter },
|
||||
{ 20, EnsureSaveData },
|
||||
|
@ -26,88 +26,88 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
};
|
||||
}
|
||||
|
||||
public long PopLaunchParameter(ServiceCtx context)
|
||||
public long PopLaunchParameter(ServiceCtx Context)
|
||||
{
|
||||
//Only the first 0x18 bytes of the Data seems to be actually used.
|
||||
MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams()));
|
||||
MakeObject(Context, new IStorage(StorageHelper.MakeLaunchParams()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long EnsureSaveData(ServiceCtx context)
|
||||
public long EnsureSaveData(ServiceCtx Context)
|
||||
{
|
||||
long uIdLow = context.RequestData.ReadInt64();
|
||||
long uIdHigh = context.RequestData.ReadInt64();
|
||||
long UIdLow = Context.RequestData.ReadInt64();
|
||||
long UIdHigh = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDesiredLanguage(ServiceCtx context)
|
||||
public long GetDesiredLanguage(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode);
|
||||
Context.ResponseData.Write(Context.Device.System.State.DesiredLanguageCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetTerminateResult(ServiceCtx context)
|
||||
public long SetTerminateResult(ServiceCtx Context)
|
||||
{
|
||||
int errorCode = context.RequestData.ReadInt32();
|
||||
int ErrorCode = Context.RequestData.ReadInt32();
|
||||
|
||||
string result = GetFormattedErrorCode(errorCode);
|
||||
string Result = GetFormattedErrorCode(ErrorCode);
|
||||
|
||||
Logger.PrintInfo(LogClass.ServiceAm, $"Result = 0x{errorCode:x8} ({result}).");
|
||||
Logger.PrintInfo(LogClass.ServiceAm, $"Result = 0x{ErrorCode:x8} ({Result}).");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private string GetFormattedErrorCode(int errorCode)
|
||||
private string GetFormattedErrorCode(int ErrorCode)
|
||||
{
|
||||
int module = (errorCode >> 0) & 0x1ff;
|
||||
int description = (errorCode >> 9) & 0x1fff;
|
||||
int Module = (ErrorCode >> 0) & 0x1ff;
|
||||
int Description = (ErrorCode >> 9) & 0x1fff;
|
||||
|
||||
return $"{(2000 + module):d4}-{description:d4}";
|
||||
return $"{(2000 + Module):d4}-{Description:d4}";
|
||||
}
|
||||
|
||||
public long GetDisplayVersion(ServiceCtx context)
|
||||
public long GetDisplayVersion(ServiceCtx Context)
|
||||
{
|
||||
//FIXME: Need to check correct version on a switch.
|
||||
context.ResponseData.Write(1L);
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(1L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long NotifyRunning(ServiceCtx context)
|
||||
public long NotifyRunning(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(1);
|
||||
Context.ResponseData.Write(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPseudoDeviceId(ServiceCtx context)
|
||||
public long GetPseudoDeviceId(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
context.ResponseData.Write(0L);
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long InitializeGamePlayRecording(ServiceCtx context)
|
||||
public long InitializeGamePlayRecording(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetGamePlayRecordingState(ServiceCtx context)
|
||||
public long SetGamePlayRecordingState(ServiceCtx Context)
|
||||
{
|
||||
int state = context.RequestData.ReadInt32();
|
||||
int State = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IApplicationProxy : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationProxy()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetCommonStateGetter },
|
||||
{ 1, GetSelfController },
|
||||
|
@ -24,58 +24,58 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
};
|
||||
}
|
||||
|
||||
public long GetCommonStateGetter(ServiceCtx context)
|
||||
public long GetCommonStateGetter(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ICommonStateGetter(context.Device.System));
|
||||
MakeObject(Context, new ICommonStateGetter(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSelfController(ServiceCtx context)
|
||||
public long GetSelfController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context.Device.System));
|
||||
MakeObject(Context, new ISelfController(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetWindowController(ServiceCtx context)
|
||||
public long GetWindowController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IWindowController());
|
||||
MakeObject(Context, new IWindowController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetAudioController(ServiceCtx context)
|
||||
public long GetAudioController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IAudioController());
|
||||
MakeObject(Context, new IAudioController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDisplayController(ServiceCtx context)
|
||||
public long GetDisplayController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IDisplayController());
|
||||
MakeObject(Context, new IDisplayController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetLibraryAppletCreator(ServiceCtx context)
|
||||
public long GetLibraryAppletCreator(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ILibraryAppletCreator());
|
||||
MakeObject(Context, new ILibraryAppletCreator());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetApplicationFunctions(ServiceCtx context)
|
||||
public long GetApplicationFunctions(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IApplicationFunctions());
|
||||
MakeObject(Context, new IApplicationFunctions());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDebugFunctions(ServiceCtx context)
|
||||
public long GetDebugFunctions(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IDebugFunctions());
|
||||
MakeObject(Context, new IDebugFunctions());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IApplicationProxyService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationProxyService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, OpenApplicationProxy }
|
||||
};
|
||||
}
|
||||
|
||||
public long OpenApplicationProxy(ServiceCtx context)
|
||||
public long OpenApplicationProxy(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IApplicationProxy());
|
||||
MakeObject(Context, new IApplicationProxy());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IAudioController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioController()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, SetExpectedMasterVolume },
|
||||
{ 1, GetMainAppletExpectedMasterVolume },
|
||||
|
@ -22,47 +22,47 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
};
|
||||
}
|
||||
|
||||
public long SetExpectedMasterVolume(ServiceCtx context)
|
||||
public long SetExpectedMasterVolume(ServiceCtx Context)
|
||||
{
|
||||
float appletVolume = context.RequestData.ReadSingle();
|
||||
float libraryAppletVolume = context.RequestData.ReadSingle();
|
||||
float AppletVolume = Context.RequestData.ReadSingle();
|
||||
float LibraryAppletVolume = Context.RequestData.ReadSingle();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetMainAppletExpectedMasterVolume(ServiceCtx context)
|
||||
public long GetMainAppletExpectedMasterVolume(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(1f);
|
||||
Context.ResponseData.Write(1f);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetLibraryAppletExpectedMasterVolume(ServiceCtx context)
|
||||
public long GetLibraryAppletExpectedMasterVolume(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(1f);
|
||||
Context.ResponseData.Write(1f);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ChangeMainAppletMasterVolume(ServiceCtx context)
|
||||
public long ChangeMainAppletMasterVolume(ServiceCtx Context)
|
||||
{
|
||||
float unknown0 = context.RequestData.ReadSingle();
|
||||
long unknown1 = context.RequestData.ReadInt64();
|
||||
float Unknown0 = Context.RequestData.ReadSingle();
|
||||
long Unknown1 = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetTransparentVolumeRate(ServiceCtx context)
|
||||
public long SetTransparentVolumeRate(ServiceCtx Context)
|
||||
{
|
||||
float unknown0 = context.RequestData.ReadSingle();
|
||||
float Unknown0 = Context.RequestData.ReadSingle();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class ICommonStateGetter : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _displayResolutionChangeEvent;
|
||||
private KEvent DisplayResolutionChangeEvent;
|
||||
|
||||
public ICommonStateGetter(Horizon system)
|
||||
public ICommonStateGetter(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetEventHandle },
|
||||
{ 1, ReceiveMessage },
|
||||
|
@ -30,89 +30,89 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{ 61, GetDefaultDisplayResolutionChangeEvent }
|
||||
};
|
||||
|
||||
_displayResolutionChangeEvent = new KEvent(system);
|
||||
DisplayResolutionChangeEvent = new KEvent(System);
|
||||
}
|
||||
|
||||
public long GetEventHandle(ServiceCtx context)
|
||||
public long GetEventHandle(ServiceCtx Context)
|
||||
{
|
||||
KEvent Event = context.Device.System.AppletState.MessageEvent;
|
||||
KEvent Event = Context.Device.System.AppletState.MessageEvent;
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ReceiveMessage(ServiceCtx context)
|
||||
public long ReceiveMessage(ServiceCtx Context)
|
||||
{
|
||||
if (!context.Device.System.AppletState.TryDequeueMessage(out MessageInfo message))
|
||||
if (!Context.Device.System.AppletState.TryDequeueMessage(out MessageInfo Message))
|
||||
{
|
||||
return MakeError(ErrorModule.Am, AmErr.NoMessages);
|
||||
}
|
||||
|
||||
context.ResponseData.Write((int)message);
|
||||
Context.ResponseData.Write((int)Message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetOperationMode(ServiceCtx context)
|
||||
public long GetOperationMode(ServiceCtx Context)
|
||||
{
|
||||
OperationMode mode = context.Device.System.State.DockedMode
|
||||
OperationMode Mode = Context.Device.System.State.DockedMode
|
||||
? OperationMode.Docked
|
||||
: OperationMode.Handheld;
|
||||
|
||||
context.ResponseData.Write((byte)mode);
|
||||
Context.ResponseData.Write((byte)Mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPerformanceMode(ServiceCtx context)
|
||||
public long GetPerformanceMode(ServiceCtx Context)
|
||||
{
|
||||
Apm.PerformanceMode mode = context.Device.System.State.DockedMode
|
||||
Apm.PerformanceMode Mode = Context.Device.System.State.DockedMode
|
||||
? Apm.PerformanceMode.Docked
|
||||
: Apm.PerformanceMode.Handheld;
|
||||
|
||||
context.ResponseData.Write((int)mode);
|
||||
Context.ResponseData.Write((int)Mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetBootMode(ServiceCtx context)
|
||||
public long GetBootMode(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((byte)0); //Unknown value.
|
||||
Context.ResponseData.Write((byte)0); //Unknown value.
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetCurrentFocusState(ServiceCtx context)
|
||||
public long GetCurrentFocusState(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((byte)context.Device.System.AppletState.FocusState);
|
||||
Context.ResponseData.Write((byte)Context.Device.System.AppletState.FocusState);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDefaultDisplayResolution(ServiceCtx context)
|
||||
public long GetDefaultDisplayResolution(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(1280);
|
||||
context.ResponseData.Write(720);
|
||||
Context.ResponseData.Write(1280);
|
||||
Context.ResponseData.Write(720);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx context)
|
||||
public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_displayResolutionChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(DisplayResolutionChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IDebugFunctions : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IDebugFunctions()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IDisplayController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IDisplayController()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IGlobalStateController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IGlobalStateController()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -8,39 +8,39 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IHomeMenuFunctions : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _channelEvent;
|
||||
private KEvent ChannelEvent;
|
||||
|
||||
public IHomeMenuFunctions(Horizon system)
|
||||
public IHomeMenuFunctions(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 10, RequestToGetForeground },
|
||||
{ 21, GetPopFromGeneralChannelEvent }
|
||||
};
|
||||
|
||||
//ToDo: Signal this Event somewhere in future.
|
||||
_channelEvent = new KEvent(system);
|
||||
ChannelEvent = new KEvent(System);
|
||||
}
|
||||
|
||||
public long RequestToGetForeground(ServiceCtx context)
|
||||
public long RequestToGetForeground(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPopFromGeneralChannelEvent(ServiceCtx context)
|
||||
public long GetPopFromGeneralChannelEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_channelEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(ChannelEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -8,15 +8,15 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class ILibraryAppletAccessor : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _stateChangedEvent;
|
||||
private KEvent StateChangedEvent;
|
||||
|
||||
public ILibraryAppletAccessor(Horizon system)
|
||||
public ILibraryAppletAccessor(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetAppletStateChangedEvent },
|
||||
{ 10, Start },
|
||||
|
@ -25,49 +25,49 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{ 101, PopOutData }
|
||||
};
|
||||
|
||||
_stateChangedEvent = new KEvent(system);
|
||||
StateChangedEvent = new KEvent(System);
|
||||
}
|
||||
|
||||
public long GetAppletStateChangedEvent(ServiceCtx context)
|
||||
public long GetAppletStateChangedEvent(ServiceCtx Context)
|
||||
{
|
||||
_stateChangedEvent.ReadableEvent.Signal();
|
||||
StateChangedEvent.ReadableEvent.Signal();
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(StateChangedEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Start(ServiceCtx context)
|
||||
public long Start(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetResult(ServiceCtx context)
|
||||
public long GetResult(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long PushInData(ServiceCtx context)
|
||||
public long PushInData(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long PopOutData(ServiceCtx context)
|
||||
public long PopOutData(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams()));
|
||||
MakeObject(Context, new IStorage(StorageHelper.MakeLaunchParams()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,31 +5,31 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class ILibraryAppletCreator : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILibraryAppletCreator()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CreateLibraryApplet },
|
||||
{ 10, CreateStorage }
|
||||
};
|
||||
}
|
||||
|
||||
public long CreateLibraryApplet(ServiceCtx context)
|
||||
public long CreateLibraryApplet(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ILibraryAppletAccessor(context.Device.System));
|
||||
MakeObject(Context, new ILibraryAppletAccessor(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateStorage(ServiceCtx context)
|
||||
public long CreateStorage(ServiceCtx Context)
|
||||
{
|
||||
long size = context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
MakeObject(context, new IStorage(new byte[size]));
|
||||
MakeObject(Context, new IStorage(new byte[Size]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,17 +8,17 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class ISelfController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _launchableEvent;
|
||||
private KEvent LaunchableEvent;
|
||||
|
||||
private int _idleTimeDetectionExtension;
|
||||
private int IdleTimeDetectionExtension;
|
||||
|
||||
public ISelfController(Horizon system)
|
||||
public ISelfController(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Exit },
|
||||
{ 1, LockExit },
|
||||
|
@ -36,114 +36,114 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{ 63, GetIdleTimeDetectionExtension }
|
||||
};
|
||||
|
||||
_launchableEvent = new KEvent(system);
|
||||
LaunchableEvent = new KEvent(System);
|
||||
}
|
||||
|
||||
public long Exit(ServiceCtx context)
|
||||
public long Exit(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long LockExit(ServiceCtx context)
|
||||
public long LockExit(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long UnlockExit(ServiceCtx context)
|
||||
public long UnlockExit(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetLibraryAppletLaunchableEvent(ServiceCtx context)
|
||||
public long GetLibraryAppletLaunchableEvent(ServiceCtx Context)
|
||||
{
|
||||
_launchableEvent.ReadableEvent.Signal();
|
||||
LaunchableEvent.ReadableEvent.Signal();
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_launchableEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(LaunchableEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetScreenShotPermission(ServiceCtx context)
|
||||
public long SetScreenShotPermission(ServiceCtx Context)
|
||||
{
|
||||
bool enable = context.RequestData.ReadByte() != 0;
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetOperationModeChangedNotification(ServiceCtx context)
|
||||
public long SetOperationModeChangedNotification(ServiceCtx Context)
|
||||
{
|
||||
bool enable = context.RequestData.ReadByte() != 0;
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetPerformanceModeChangedNotification(ServiceCtx context)
|
||||
public long SetPerformanceModeChangedNotification(ServiceCtx Context)
|
||||
{
|
||||
bool enable = context.RequestData.ReadByte() != 0;
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetFocusHandlingMode(ServiceCtx context)
|
||||
public long SetFocusHandlingMode(ServiceCtx Context)
|
||||
{
|
||||
bool flag1 = context.RequestData.ReadByte() != 0;
|
||||
bool flag2 = context.RequestData.ReadByte() != 0;
|
||||
bool flag3 = context.RequestData.ReadByte() != 0;
|
||||
bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetRestartMessageEnabled(ServiceCtx context)
|
||||
public long SetRestartMessageEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool enable = context.RequestData.ReadByte() != 0;
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetOutOfFocusSuspendingEnabled(ServiceCtx context)
|
||||
public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool enable = context.RequestData.ReadByte() != 0;
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetScreenShotImageOrientation(ServiceCtx context)
|
||||
public long SetScreenShotImageOrientation(ServiceCtx Context)
|
||||
{
|
||||
int orientation = context.RequestData.ReadInt32();
|
||||
int Orientation = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetHandlesRequestToDisplay(ServiceCtx context)
|
||||
public long SetHandlesRequestToDisplay(ServiceCtx Context)
|
||||
{
|
||||
bool enable = context.RequestData.ReadByte() != 0;
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
|
@ -151,21 +151,21 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
}
|
||||
|
||||
// SetIdleTimeDetectionExtension(u32)
|
||||
public long SetIdleTimeDetectionExtension(ServiceCtx context)
|
||||
public long SetIdleTimeDetectionExtension(ServiceCtx Context)
|
||||
{
|
||||
_idleTimeDetectionExtension = context.RequestData.ReadInt32();
|
||||
IdleTimeDetectionExtension = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, $"Stubbed. IdleTimeDetectionExtension: {_idleTimeDetectionExtension}");
|
||||
Logger.PrintStub(LogClass.ServiceAm, $"Stubbed. IdleTimeDetectionExtension: {IdleTimeDetectionExtension}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetIdleTimeDetectionExtension() -> u32
|
||||
public long GetIdleTimeDetectionExtension(ServiceCtx context)
|
||||
public long GetIdleTimeDetectionExtension(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(_idleTimeDetectionExtension);
|
||||
Context.ResponseData.Write(IdleTimeDetectionExtension);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, $"Stubbed. IdleTimeDetectionExtension: {_idleTimeDetectionExtension}");
|
||||
Logger.PrintStub(LogClass.ServiceAm, $"Stubbed. IdleTimeDetectionExtension: {IdleTimeDetectionExtension}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,25 +5,25 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IStorage : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public byte[] Data { get; }
|
||||
public byte[] Data { get; private set; }
|
||||
|
||||
public IStorage(byte[] data)
|
||||
public IStorage(byte[] Data)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Open }
|
||||
};
|
||||
|
||||
Data = data;
|
||||
this.Data = Data;
|
||||
}
|
||||
|
||||
public long Open(ServiceCtx context)
|
||||
public long Open(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IStorageAccessor(this));
|
||||
MakeObject(Context, new IStorageAccessor(this));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,76 +6,76 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IStorageAccessor : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private IStorage _storage;
|
||||
private IStorage Storage;
|
||||
|
||||
public IStorageAccessor(IStorage storage)
|
||||
public IStorageAccessor(IStorage Storage)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetSize },
|
||||
{ 10, Write },
|
||||
{ 11, Read }
|
||||
};
|
||||
|
||||
_storage = storage;
|
||||
this.Storage = Storage;
|
||||
}
|
||||
|
||||
public long GetSize(ServiceCtx context)
|
||||
public long GetSize(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((long)_storage.Data.Length);
|
||||
Context.ResponseData.Write((long)Storage.Data.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Write(ServiceCtx context)
|
||||
public long Write(ServiceCtx Context)
|
||||
{
|
||||
//TODO: Error conditions.
|
||||
long writePosition = context.RequestData.ReadInt64();
|
||||
long WritePosition = Context.RequestData.ReadInt64();
|
||||
|
||||
(long position, long size) = context.Request.GetBufferType0x21();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x21();
|
||||
|
||||
if (size > 0)
|
||||
if (Size > 0)
|
||||
{
|
||||
long maxSize = _storage.Data.Length - writePosition;
|
||||
long MaxSize = Storage.Data.Length - WritePosition;
|
||||
|
||||
if (size > maxSize)
|
||||
if (Size > MaxSize)
|
||||
{
|
||||
size = maxSize;
|
||||
Size = MaxSize;
|
||||
}
|
||||
|
||||
byte[] data = context.Memory.ReadBytes(position, size);
|
||||
byte[] Data = Context.Memory.ReadBytes(Position, Size);
|
||||
|
||||
Buffer.BlockCopy(data, 0, _storage.Data, (int)writePosition, (int)size);
|
||||
Buffer.BlockCopy(Data, 0, Storage.Data, (int)WritePosition, (int)Size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Read(ServiceCtx context)
|
||||
public long Read(ServiceCtx Context)
|
||||
{
|
||||
//TODO: Error conditions.
|
||||
long readPosition = context.RequestData.ReadInt64();
|
||||
long ReadPosition = Context.RequestData.ReadInt64();
|
||||
|
||||
(long position, long size) = context.Request.GetBufferType0x22();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x22();
|
||||
|
||||
byte[] data;
|
||||
byte[] Data;
|
||||
|
||||
if (_storage.Data.Length > size)
|
||||
if (Storage.Data.Length > Size)
|
||||
{
|
||||
data = new byte[size];
|
||||
Data = new byte[Size];
|
||||
|
||||
Buffer.BlockCopy(_storage.Data, 0, data, 0, (int)size);
|
||||
Buffer.BlockCopy(Storage.Data, 0, Data, 0, (int)Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = _storage.Data;
|
||||
Data = Storage.Data;
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, data);
|
||||
Context.Memory.WriteBytes(Position, Data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class ISystemAppletProxy : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISystemAppletProxy()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetCommonStateGetter },
|
||||
{ 1, GetSelfController },
|
||||
|
@ -26,72 +26,72 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
};
|
||||
}
|
||||
|
||||
public long GetCommonStateGetter(ServiceCtx context)
|
||||
public long GetCommonStateGetter(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ICommonStateGetter(context.Device.System));
|
||||
MakeObject(Context, new ICommonStateGetter(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSelfController(ServiceCtx context)
|
||||
public long GetSelfController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context.Device.System));
|
||||
MakeObject(Context, new ISelfController(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetWindowController(ServiceCtx context)
|
||||
public long GetWindowController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IWindowController());
|
||||
MakeObject(Context, new IWindowController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetAudioController(ServiceCtx context)
|
||||
public long GetAudioController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IAudioController());
|
||||
MakeObject(Context, new IAudioController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDisplayController(ServiceCtx context)
|
||||
public long GetDisplayController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IDisplayController());
|
||||
MakeObject(Context, new IDisplayController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetLibraryAppletCreator(ServiceCtx context)
|
||||
public long GetLibraryAppletCreator(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ILibraryAppletCreator());
|
||||
MakeObject(Context, new ILibraryAppletCreator());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetHomeMenuFunctions(ServiceCtx context)
|
||||
public long GetHomeMenuFunctions(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IHomeMenuFunctions(context.Device.System));
|
||||
MakeObject(Context, new IHomeMenuFunctions(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetGlobalStateController(ServiceCtx context)
|
||||
public long GetGlobalStateController(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IGlobalStateController());
|
||||
MakeObject(Context, new IGlobalStateController());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetApplicationCreator(ServiceCtx context)
|
||||
public long GetApplicationCreator(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IApplicationCreator());
|
||||
MakeObject(Context, new IApplicationCreator());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDebugFunctions(ServiceCtx context)
|
||||
public long GetDebugFunctions(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IDebugFunctions());
|
||||
MakeObject(Context, new IDebugFunctions());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,29 +6,29 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
class IWindowController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IWindowController()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, GetAppletResourceUserId },
|
||||
{ 10, AcquireForegroundRights }
|
||||
};
|
||||
}
|
||||
|
||||
public long GetAppletResourceUserId(ServiceCtx context)
|
||||
public long GetAppletResourceUserId(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AcquireForegroundRights(ServiceCtx context)
|
||||
public long AcquireForegroundRights(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -9,18 +9,18 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
public static byte[] MakeLaunchParams()
|
||||
{
|
||||
//Size needs to be at least 0x88 bytes otherwise application errors.
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
ms.SetLength(0x88);
|
||||
MS.SetLength(0x88);
|
||||
|
||||
writer.Write(LaunchParamsMagic);
|
||||
writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used.
|
||||
writer.Write(1L); //User Id Low (note: User Id needs to be != 0)
|
||||
writer.Write(0L); //User Id High
|
||||
Writer.Write(LaunchParamsMagic);
|
||||
Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used.
|
||||
Writer.Write(1L); //User Id Low (note: User Id needs to be != 0)
|
||||
Writer.Write(0L); //User Id High
|
||||
|
||||
return ms.ToArray();
|
||||
return MS.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Apm
|
|||
{
|
||||
class IManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, OpenSession }
|
||||
};
|
||||
}
|
||||
|
||||
public long OpenSession(ServiceCtx context)
|
||||
public long OpenSession(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ISession());
|
||||
MakeObject(Context, new ISession());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,32 +6,32 @@ namespace Ryujinx.HLE.HOS.Services.Apm
|
|||
{
|
||||
class ISession : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISession()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, SetPerformanceConfiguration },
|
||||
{ 1, GetPerformanceConfiguration }
|
||||
};
|
||||
}
|
||||
|
||||
public long SetPerformanceConfiguration(ServiceCtx context)
|
||||
public long SetPerformanceConfiguration(ServiceCtx Context)
|
||||
{
|
||||
PerformanceMode perfMode = (PerformanceMode)context.RequestData.ReadInt32();
|
||||
PerformanceConfiguration perfConfig = (PerformanceConfiguration)context.RequestData.ReadInt32();
|
||||
PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32();
|
||||
PerformanceConfiguration PerfConfig = (PerformanceConfiguration)Context.RequestData.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPerformanceConfiguration(ServiceCtx context)
|
||||
public long GetPerformanceConfiguration(ServiceCtx Context)
|
||||
{
|
||||
PerformanceMode perfMode = (PerformanceMode)context.RequestData.ReadInt32();
|
||||
PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32();
|
||||
|
||||
context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1);
|
||||
Context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceApm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -9,19 +9,19 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
|
|||
{
|
||||
class IAudioOut : IpcService, IDisposable
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private IAalOutput _audioOut;
|
||||
private IAalOutput AudioOut;
|
||||
|
||||
private KEvent _releaseEvent;
|
||||
private KEvent ReleaseEvent;
|
||||
|
||||
private int _track;
|
||||
private int Track;
|
||||
|
||||
public IAudioOut(IAalOutput audioOut, KEvent releaseEvent, int track)
|
||||
public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetAudioOutState },
|
||||
{ 1, StartAudioOut },
|
||||
|
@ -34,116 +34,116 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
|
|||
{ 8, GetReleasedAudioOutBufferAuto }
|
||||
};
|
||||
|
||||
_audioOut = audioOut;
|
||||
_releaseEvent = releaseEvent;
|
||||
_track = track;
|
||||
this.AudioOut = AudioOut;
|
||||
this.ReleaseEvent = ReleaseEvent;
|
||||
this.Track = Track;
|
||||
}
|
||||
|
||||
public long GetAudioOutState(ServiceCtx context)
|
||||
public long GetAudioOutState(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)_audioOut.GetState(_track));
|
||||
Context.ResponseData.Write((int)AudioOut.GetState(Track));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StartAudioOut(ServiceCtx context)
|
||||
public long StartAudioOut(ServiceCtx Context)
|
||||
{
|
||||
_audioOut.Start(_track);
|
||||
AudioOut.Start(Track);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StopAudioOut(ServiceCtx context)
|
||||
public long StopAudioOut(ServiceCtx Context)
|
||||
{
|
||||
_audioOut.Stop(_track);
|
||||
AudioOut.Stop(Track);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AppendAudioOutBuffer(ServiceCtx context)
|
||||
public long AppendAudioOutBuffer(ServiceCtx Context)
|
||||
{
|
||||
return AppendAudioOutBufferImpl(context, context.Request.SendBuff[0].Position);
|
||||
return AppendAudioOutBufferImpl(Context, Context.Request.SendBuff[0].Position);
|
||||
}
|
||||
|
||||
public long RegisterBufferEvent(ServiceCtx context)
|
||||
public long RegisterBufferEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_releaseEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(ReleaseEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetReleasedAudioOutBuffer(ServiceCtx context)
|
||||
public long GetReleasedAudioOutBuffer(ServiceCtx Context)
|
||||
{
|
||||
long position = context.Request.ReceiveBuff[0].Position;
|
||||
long size = context.Request.ReceiveBuff[0].Size;
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
long Size = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
return GetReleasedAudioOutBufferImpl(context, position, size);
|
||||
return GetReleasedAudioOutBufferImpl(Context, Position, Size);
|
||||
}
|
||||
|
||||
public long ContainsAudioOutBuffer(ServiceCtx context)
|
||||
public long ContainsAudioOutBuffer(ServiceCtx Context)
|
||||
{
|
||||
long tag = context.RequestData.ReadInt64();
|
||||
long Tag = Context.RequestData.ReadInt64();
|
||||
|
||||
context.ResponseData.Write(_audioOut.ContainsBuffer(_track, tag) ? 1 : 0);
|
||||
Context.ResponseData.Write(AudioOut.ContainsBuffer(Track, Tag) ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AppendAudioOutBufferAuto(ServiceCtx context)
|
||||
public long AppendAudioOutBufferAuto(ServiceCtx Context)
|
||||
{
|
||||
(long position, long size) = context.Request.GetBufferType0x21();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x21();
|
||||
|
||||
return AppendAudioOutBufferImpl(context, position);
|
||||
return AppendAudioOutBufferImpl(Context, Position);
|
||||
}
|
||||
|
||||
public long AppendAudioOutBufferImpl(ServiceCtx context, long position)
|
||||
public long AppendAudioOutBufferImpl(ServiceCtx Context, long Position)
|
||||
{
|
||||
long tag = context.RequestData.ReadInt64();
|
||||
long Tag = Context.RequestData.ReadInt64();
|
||||
|
||||
AudioOutData data = MemoryHelper.Read<AudioOutData>(
|
||||
context.Memory,
|
||||
position);
|
||||
AudioOutData Data = MemoryHelper.Read<AudioOutData>(
|
||||
Context.Memory,
|
||||
Position);
|
||||
|
||||
byte[] buffer = context.Memory.ReadBytes(
|
||||
data.SampleBufferPtr,
|
||||
data.SampleBufferSize);
|
||||
byte[] Buffer = Context.Memory.ReadBytes(
|
||||
Data.SampleBufferPtr,
|
||||
Data.SampleBufferSize);
|
||||
|
||||
_audioOut.AppendBuffer(_track, tag, buffer);
|
||||
AudioOut.AppendBuffer(Track, Tag, Buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetReleasedAudioOutBufferAuto(ServiceCtx context)
|
||||
public long GetReleasedAudioOutBufferAuto(ServiceCtx Context)
|
||||
{
|
||||
(long position, long size) = context.Request.GetBufferType0x22();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x22();
|
||||
|
||||
return GetReleasedAudioOutBufferImpl(context, position, size);
|
||||
return GetReleasedAudioOutBufferImpl(Context, Position, Size);
|
||||
}
|
||||
|
||||
public long GetReleasedAudioOutBufferImpl(ServiceCtx context, long position, long size)
|
||||
public long GetReleasedAudioOutBufferImpl(ServiceCtx Context, long Position, long Size)
|
||||
{
|
||||
uint count = (uint)((ulong)size >> 3);
|
||||
uint Count = (uint)((ulong)Size >> 3);
|
||||
|
||||
long[] releasedBuffers = _audioOut.GetReleasedBuffers(_track, (int)count);
|
||||
long[] ReleasedBuffers = AudioOut.GetReleasedBuffers(Track, (int)Count);
|
||||
|
||||
for (uint index = 0; index < count; index++)
|
||||
for (uint Index = 0; Index < Count; Index++)
|
||||
{
|
||||
long tag = 0;
|
||||
long Tag = 0;
|
||||
|
||||
if (index < releasedBuffers.Length)
|
||||
if (Index < ReleasedBuffers.Length)
|
||||
{
|
||||
tag = releasedBuffers[index];
|
||||
Tag = ReleasedBuffers[Index];
|
||||
}
|
||||
|
||||
context.Memory.WriteInt64(position + index * 8, tag);
|
||||
Context.Memory.WriteInt64(Position + Index * 8, Tag);
|
||||
}
|
||||
|
||||
context.ResponseData.Write(releasedBuffers.Length);
|
||||
Context.ResponseData.Write(ReleasedBuffers.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -153,11 +153,11 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (disposing)
|
||||
if (Disposing)
|
||||
{
|
||||
_audioOut.CloseTrack(_track);
|
||||
AudioOut.CloseTrack(Track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,33 +22,33 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
//high latency).
|
||||
private const int MixBufferSamplesCount = 960;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _updateEvent;
|
||||
private KEvent UpdateEvent;
|
||||
|
||||
private MemoryManager _memory;
|
||||
private MemoryManager Memory;
|
||||
|
||||
private IAalOutput _audioOut;
|
||||
private IAalOutput AudioOut;
|
||||
|
||||
private AudioRendererParameter _params;
|
||||
private AudioRendererParameter Params;
|
||||
|
||||
private MemoryPoolContext[] _memoryPools;
|
||||
private MemoryPoolContext[] MemoryPools;
|
||||
|
||||
private VoiceContext[] _voices;
|
||||
private VoiceContext[] Voices;
|
||||
|
||||
private int _track;
|
||||
private int Track;
|
||||
|
||||
private PlayState _playState;
|
||||
private PlayState PlayState;
|
||||
|
||||
public IAudioRenderer(
|
||||
Horizon system,
|
||||
MemoryManager memory,
|
||||
IAalOutput audioOut,
|
||||
Horizon System,
|
||||
MemoryManager Memory,
|
||||
IAalOutput AudioOut,
|
||||
AudioRendererParameter Params)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetSampleRate },
|
||||
{ 1, GetSampleCount },
|
||||
|
@ -60,75 +60,75 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
{ 7, QuerySystemEvent }
|
||||
};
|
||||
|
||||
_updateEvent = new KEvent(system);
|
||||
UpdateEvent = new KEvent(System);
|
||||
|
||||
_memory = memory;
|
||||
_audioOut = audioOut;
|
||||
_params = Params;
|
||||
this.Memory = Memory;
|
||||
this.AudioOut = AudioOut;
|
||||
this.Params = Params;
|
||||
|
||||
_track = audioOut.OpenTrack(
|
||||
Track = AudioOut.OpenTrack(
|
||||
AudioConsts.HostSampleRate,
|
||||
AudioConsts.HostChannelsCount,
|
||||
AudioCallback);
|
||||
|
||||
_memoryPools = CreateArray<MemoryPoolContext>(Params.EffectCount + Params.VoiceCount * 4);
|
||||
MemoryPools = CreateArray<MemoryPoolContext>(Params.EffectCount + Params.VoiceCount * 4);
|
||||
|
||||
_voices = CreateArray<VoiceContext>(Params.VoiceCount);
|
||||
Voices = CreateArray<VoiceContext>(Params.VoiceCount);
|
||||
|
||||
InitializeAudioOut();
|
||||
|
||||
_playState = PlayState.Stopped;
|
||||
PlayState = PlayState.Stopped;
|
||||
}
|
||||
|
||||
// GetSampleRate() -> u32
|
||||
public long GetSampleRate(ServiceCtx context)
|
||||
public long GetSampleRate(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(_params.SampleRate);
|
||||
Context.ResponseData.Write(Params.SampleRate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetSampleCount() -> u32
|
||||
public long GetSampleCount(ServiceCtx context)
|
||||
public long GetSampleCount(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(_params.SampleCount);
|
||||
Context.ResponseData.Write(Params.SampleCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetMixBufferCount() -> u32
|
||||
public long GetMixBufferCount(ServiceCtx context)
|
||||
public long GetMixBufferCount(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(_params.MixCount);
|
||||
Context.ResponseData.Write(Params.MixCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetState() -> u32
|
||||
private long GetState(ServiceCtx context)
|
||||
private long GetState(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)_playState);
|
||||
Context.ResponseData.Write((int)PlayState);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, $"Stubbed. Renderer State: {Enum.GetName(typeof(PlayState), _playState)}");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, $"Stubbed. Renderer State: {Enum.GetName(typeof(PlayState), PlayState)}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void AudioCallback()
|
||||
{
|
||||
_updateEvent.ReadableEvent.Signal();
|
||||
UpdateEvent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
private static T[] CreateArray<T>(int size) where T : new()
|
||||
private static T[] CreateArray<T>(int Size) where T : new()
|
||||
{
|
||||
T[] output = new T[size];
|
||||
T[] Output = new T[Size];
|
||||
|
||||
for (int index = 0; index < size; index++)
|
||||
for (int Index = 0; Index < Size; Index++)
|
||||
{
|
||||
output[index] = new T();
|
||||
Output[Index] = new T();
|
||||
}
|
||||
|
||||
return output;
|
||||
return Output;
|
||||
}
|
||||
|
||||
private void InitializeAudioOut()
|
||||
|
@ -137,258 +137,258 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
AppendMixedBuffer(1);
|
||||
AppendMixedBuffer(2);
|
||||
|
||||
_audioOut.Start(_track);
|
||||
AudioOut.Start(Track);
|
||||
}
|
||||
|
||||
public long RequestUpdateAudioRenderer(ServiceCtx context)
|
||||
public long RequestUpdateAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
long outputPosition = context.Request.ReceiveBuff[0].Position;
|
||||
long outputSize = context.Request.ReceiveBuff[0].Size;
|
||||
long OutputPosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long OutputSize = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
|
||||
MemoryHelper.FillWithZeros(Context.Memory, OutputPosition, (int)OutputSize);
|
||||
|
||||
long inputPosition = context.Request.SendBuff[0].Position;
|
||||
long InputPosition = Context.Request.SendBuff[0].Position;
|
||||
|
||||
StructReader reader = new StructReader(context.Memory, inputPosition);
|
||||
StructWriter writer = new StructWriter(context.Memory, outputPosition);
|
||||
StructReader Reader = new StructReader(Context.Memory, InputPosition);
|
||||
StructWriter Writer = new StructWriter(Context.Memory, OutputPosition);
|
||||
|
||||
UpdateDataHeader inputHeader = reader.Read<UpdateDataHeader>();
|
||||
UpdateDataHeader InputHeader = Reader.Read<UpdateDataHeader>();
|
||||
|
||||
reader.Read<BehaviorIn>(inputHeader.BehaviorSize);
|
||||
Reader.Read<BehaviorIn>(InputHeader.BehaviorSize);
|
||||
|
||||
MemoryPoolIn[] memoryPoolsIn = reader.Read<MemoryPoolIn>(inputHeader.MemoryPoolSize);
|
||||
MemoryPoolIn[] MemoryPoolsIn = Reader.Read<MemoryPoolIn>(InputHeader.MemoryPoolSize);
|
||||
|
||||
for (int index = 0; index < memoryPoolsIn.Length; index++)
|
||||
for (int Index = 0; Index < MemoryPoolsIn.Length; Index++)
|
||||
{
|
||||
MemoryPoolIn memoryPool = memoryPoolsIn[index];
|
||||
MemoryPoolIn MemoryPool = MemoryPoolsIn[Index];
|
||||
|
||||
if (memoryPool.State == MemoryPoolState.RequestAttach)
|
||||
if (MemoryPool.State == MemoryPoolState.RequestAttach)
|
||||
{
|
||||
_memoryPools[index].OutStatus.State = MemoryPoolState.Attached;
|
||||
MemoryPools[Index].OutStatus.State = MemoryPoolState.Attached;
|
||||
}
|
||||
else if (memoryPool.State == MemoryPoolState.RequestDetach)
|
||||
else if (MemoryPool.State == MemoryPoolState.RequestDetach)
|
||||
{
|
||||
_memoryPools[index].OutStatus.State = MemoryPoolState.Detached;
|
||||
MemoryPools[Index].OutStatus.State = MemoryPoolState.Detached;
|
||||
}
|
||||
}
|
||||
|
||||
reader.Read<VoiceChannelResourceIn>(inputHeader.VoiceResourceSize);
|
||||
Reader.Read<VoiceChannelResourceIn>(InputHeader.VoiceResourceSize);
|
||||
|
||||
VoiceIn[] voicesIn = reader.Read<VoiceIn>(inputHeader.VoiceSize);
|
||||
VoiceIn[] VoicesIn = Reader.Read<VoiceIn>(InputHeader.VoiceSize);
|
||||
|
||||
for (int index = 0; index < voicesIn.Length; index++)
|
||||
for (int Index = 0; Index < VoicesIn.Length; Index++)
|
||||
{
|
||||
VoiceIn voice = voicesIn[index];
|
||||
VoiceIn Voice = VoicesIn[Index];
|
||||
|
||||
VoiceContext voiceCtx = _voices[index];
|
||||
VoiceContext VoiceCtx = Voices[Index];
|
||||
|
||||
voiceCtx.SetAcquireState(voice.Acquired != 0);
|
||||
VoiceCtx.SetAcquireState(Voice.Acquired != 0);
|
||||
|
||||
if (voice.Acquired == 0)
|
||||
if (Voice.Acquired == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (voice.FirstUpdate != 0)
|
||||
if (Voice.FirstUpdate != 0)
|
||||
{
|
||||
voiceCtx.AdpcmCtx = GetAdpcmDecoderContext(
|
||||
voice.AdpcmCoeffsPosition,
|
||||
voice.AdpcmCoeffsSize);
|
||||
VoiceCtx.AdpcmCtx = GetAdpcmDecoderContext(
|
||||
Voice.AdpcmCoeffsPosition,
|
||||
Voice.AdpcmCoeffsSize);
|
||||
|
||||
voiceCtx.SampleFormat = voice.SampleFormat;
|
||||
voiceCtx.SampleRate = voice.SampleRate;
|
||||
voiceCtx.ChannelsCount = voice.ChannelsCount;
|
||||
VoiceCtx.SampleFormat = Voice.SampleFormat;
|
||||
VoiceCtx.SampleRate = Voice.SampleRate;
|
||||
VoiceCtx.ChannelsCount = Voice.ChannelsCount;
|
||||
|
||||
voiceCtx.SetBufferIndex(voice.BaseWaveBufferIndex);
|
||||
VoiceCtx.SetBufferIndex(Voice.BaseWaveBufferIndex);
|
||||
}
|
||||
|
||||
voiceCtx.WaveBuffers[0] = voice.WaveBuffer0;
|
||||
voiceCtx.WaveBuffers[1] = voice.WaveBuffer1;
|
||||
voiceCtx.WaveBuffers[2] = voice.WaveBuffer2;
|
||||
voiceCtx.WaveBuffers[3] = voice.WaveBuffer3;
|
||||
voiceCtx.Volume = voice.Volume;
|
||||
voiceCtx.PlayState = voice.PlayState;
|
||||
VoiceCtx.WaveBuffers[0] = Voice.WaveBuffer0;
|
||||
VoiceCtx.WaveBuffers[1] = Voice.WaveBuffer1;
|
||||
VoiceCtx.WaveBuffers[2] = Voice.WaveBuffer2;
|
||||
VoiceCtx.WaveBuffers[3] = Voice.WaveBuffer3;
|
||||
VoiceCtx.Volume = Voice.Volume;
|
||||
VoiceCtx.PlayState = Voice.PlayState;
|
||||
}
|
||||
|
||||
UpdateAudio();
|
||||
|
||||
UpdateDataHeader outputHeader = new UpdateDataHeader();
|
||||
UpdateDataHeader OutputHeader = new UpdateDataHeader();
|
||||
|
||||
int updateHeaderSize = Marshal.SizeOf<UpdateDataHeader>();
|
||||
int UpdateHeaderSize = Marshal.SizeOf<UpdateDataHeader>();
|
||||
|
||||
outputHeader.Revision = IAudioRendererManager.RevMagic;
|
||||
outputHeader.BehaviorSize = 0xb0;
|
||||
outputHeader.MemoryPoolSize = (_params.EffectCount + _params.VoiceCount * 4) * 0x10;
|
||||
outputHeader.VoiceSize = _params.VoiceCount * 0x10;
|
||||
outputHeader.EffectSize = _params.EffectCount * 0x10;
|
||||
outputHeader.SinkSize = _params.SinkCount * 0x20;
|
||||
outputHeader.PerformanceManagerSize = 0x10;
|
||||
outputHeader.TotalSize = updateHeaderSize +
|
||||
outputHeader.BehaviorSize +
|
||||
outputHeader.MemoryPoolSize +
|
||||
outputHeader.VoiceSize +
|
||||
outputHeader.EffectSize +
|
||||
outputHeader.SinkSize +
|
||||
outputHeader.PerformanceManagerSize;
|
||||
OutputHeader.Revision = IAudioRendererManager.RevMagic;
|
||||
OutputHeader.BehaviorSize = 0xb0;
|
||||
OutputHeader.MemoryPoolSize = (Params.EffectCount + Params.VoiceCount * 4) * 0x10;
|
||||
OutputHeader.VoiceSize = Params.VoiceCount * 0x10;
|
||||
OutputHeader.EffectSize = Params.EffectCount * 0x10;
|
||||
OutputHeader.SinkSize = Params.SinkCount * 0x20;
|
||||
OutputHeader.PerformanceManagerSize = 0x10;
|
||||
OutputHeader.TotalSize = UpdateHeaderSize +
|
||||
OutputHeader.BehaviorSize +
|
||||
OutputHeader.MemoryPoolSize +
|
||||
OutputHeader.VoiceSize +
|
||||
OutputHeader.EffectSize +
|
||||
OutputHeader.SinkSize +
|
||||
OutputHeader.PerformanceManagerSize;
|
||||
|
||||
writer.Write(outputHeader);
|
||||
Writer.Write(OutputHeader);
|
||||
|
||||
foreach (MemoryPoolContext memoryPool in _memoryPools)
|
||||
foreach (MemoryPoolContext MemoryPool in MemoryPools)
|
||||
{
|
||||
writer.Write(memoryPool.OutStatus);
|
||||
Writer.Write(MemoryPool.OutStatus);
|
||||
}
|
||||
|
||||
foreach (VoiceContext voice in _voices)
|
||||
foreach (VoiceContext Voice in Voices)
|
||||
{
|
||||
writer.Write(voice.OutStatus);
|
||||
Writer.Write(Voice.OutStatus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StartAudioRenderer(ServiceCtx context)
|
||||
public long StartAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
_playState = PlayState.Playing;
|
||||
PlayState = PlayState.Playing;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StopAudioRenderer(ServiceCtx context)
|
||||
public long StopAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
_playState = PlayState.Stopped;
|
||||
PlayState = PlayState.Stopped;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QuerySystemEvent(ServiceCtx context)
|
||||
public long QuerySystemEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_updateEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(UpdateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private AdpcmDecoderContext GetAdpcmDecoderContext(long position, long size)
|
||||
private AdpcmDecoderContext GetAdpcmDecoderContext(long Position, long Size)
|
||||
{
|
||||
if (size == 0)
|
||||
if (Size == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AdpcmDecoderContext context = new AdpcmDecoderContext();
|
||||
AdpcmDecoderContext Context = new AdpcmDecoderContext();
|
||||
|
||||
context.Coefficients = new short[size >> 1];
|
||||
Context.Coefficients = new short[Size >> 1];
|
||||
|
||||
for (int offset = 0; offset < size; offset += 2)
|
||||
for (int Offset = 0; Offset < Size; Offset += 2)
|
||||
{
|
||||
context.Coefficients[offset >> 1] = _memory.ReadInt16(position + offset);
|
||||
Context.Coefficients[Offset >> 1] = Memory.ReadInt16(Position + Offset);
|
||||
}
|
||||
|
||||
return context;
|
||||
return Context;
|
||||
}
|
||||
|
||||
private void UpdateAudio()
|
||||
{
|
||||
long[] released = _audioOut.GetReleasedBuffers(_track, 2);
|
||||
long[] Released = AudioOut.GetReleasedBuffers(Track, 2);
|
||||
|
||||
for (int index = 0; index < released.Length; index++)
|
||||
for (int Index = 0; Index < Released.Length; Index++)
|
||||
{
|
||||
AppendMixedBuffer(released[index]);
|
||||
AppendMixedBuffer(Released[Index]);
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendMixedBuffer(long tag)
|
||||
private unsafe void AppendMixedBuffer(long Tag)
|
||||
{
|
||||
int[] mixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount];
|
||||
int[] MixBuffer = new int[MixBufferSamplesCount * AudioConsts.HostChannelsCount];
|
||||
|
||||
foreach (VoiceContext voice in _voices)
|
||||
foreach (VoiceContext Voice in Voices)
|
||||
{
|
||||
if (!voice.Playing)
|
||||
if (!Voice.Playing)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int outOffset = 0;
|
||||
int pendingSamples = MixBufferSamplesCount;
|
||||
float volume = voice.Volume;
|
||||
int OutOffset = 0;
|
||||
int PendingSamples = MixBufferSamplesCount;
|
||||
float Volume = Voice.Volume;
|
||||
|
||||
while (pendingSamples > 0)
|
||||
while (PendingSamples > 0)
|
||||
{
|
||||
int[] samples = voice.GetBufferData(_memory, pendingSamples, out int returnedSamples);
|
||||
int[] Samples = Voice.GetBufferData(Memory, PendingSamples, out int ReturnedSamples);
|
||||
|
||||
if (returnedSamples == 0)
|
||||
if (ReturnedSamples == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pendingSamples -= returnedSamples;
|
||||
PendingSamples -= ReturnedSamples;
|
||||
|
||||
for (int offset = 0; offset < samples.Length; offset++)
|
||||
for (int Offset = 0; Offset < Samples.Length; Offset++)
|
||||
{
|
||||
mixBuffer[outOffset++] += (int)(samples[offset] * voice.Volume);
|
||||
MixBuffer[OutOffset++] += (int)(Samples[Offset] * Voice.Volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_audioOut.AppendBuffer(_track, tag, GetFinalBuffer(mixBuffer));
|
||||
AudioOut.AppendBuffer(Track, Tag, GetFinalBuffer(MixBuffer));
|
||||
}
|
||||
|
||||
private static unsafe short[] GetFinalBuffer(int[] buffer)
|
||||
private unsafe static short[] GetFinalBuffer(int[] Buffer)
|
||||
{
|
||||
short[] output = new short[buffer.Length];
|
||||
short[] Output = new short[Buffer.Length];
|
||||
|
||||
int offset = 0;
|
||||
int Offset = 0;
|
||||
|
||||
// Perform Saturation using SSE2 if supported
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
fixed (int* inptr = buffer)
|
||||
fixed (short* outptr = output)
|
||||
fixed (int* inptr = Buffer)
|
||||
fixed (short* outptr = Output)
|
||||
{
|
||||
for (; offset + 32 <= buffer.Length; offset += 32)
|
||||
for (; Offset + 32 <= Buffer.Length; Offset += 32)
|
||||
{
|
||||
// Unroll the loop a little to ensure the CPU pipeline
|
||||
// is always full.
|
||||
Vector128<int> block1A = Sse2.LoadVector128(inptr + offset + 0);
|
||||
Vector128<int> block1B = Sse2.LoadVector128(inptr + offset + 4);
|
||||
Vector128<int> block1A = Sse2.LoadVector128(inptr + Offset + 0);
|
||||
Vector128<int> block1B = Sse2.LoadVector128(inptr + Offset + 4);
|
||||
|
||||
Vector128<int> block2A = Sse2.LoadVector128(inptr + offset + 8);
|
||||
Vector128<int> block2B = Sse2.LoadVector128(inptr + offset + 12);
|
||||
Vector128<int> block2A = Sse2.LoadVector128(inptr + Offset + 8);
|
||||
Vector128<int> block2B = Sse2.LoadVector128(inptr + Offset + 12);
|
||||
|
||||
Vector128<int> block3A = Sse2.LoadVector128(inptr + offset + 16);
|
||||
Vector128<int> block3B = Sse2.LoadVector128(inptr + offset + 20);
|
||||
Vector128<int> block3A = Sse2.LoadVector128(inptr + Offset + 16);
|
||||
Vector128<int> block3B = Sse2.LoadVector128(inptr + Offset + 20);
|
||||
|
||||
Vector128<int> block4A = Sse2.LoadVector128(inptr + offset + 24);
|
||||
Vector128<int> block4B = Sse2.LoadVector128(inptr + offset + 28);
|
||||
Vector128<int> block4A = Sse2.LoadVector128(inptr + Offset + 24);
|
||||
Vector128<int> block4B = Sse2.LoadVector128(inptr + Offset + 28);
|
||||
|
||||
Vector128<short> output1 = Sse2.PackSignedSaturate(block1A, block1B);
|
||||
Vector128<short> output2 = Sse2.PackSignedSaturate(block2A, block2B);
|
||||
Vector128<short> output3 = Sse2.PackSignedSaturate(block3A, block3B);
|
||||
Vector128<short> output4 = Sse2.PackSignedSaturate(block4A, block4B);
|
||||
|
||||
Sse2.Store(outptr + offset + 0, output1);
|
||||
Sse2.Store(outptr + offset + 8, output2);
|
||||
Sse2.Store(outptr + offset + 16, output3);
|
||||
Sse2.Store(outptr + offset + 24, output4);
|
||||
Sse2.Store(outptr + Offset + 0, output1);
|
||||
Sse2.Store(outptr + Offset + 8, output2);
|
||||
Sse2.Store(outptr + Offset + 16, output3);
|
||||
Sse2.Store(outptr + Offset + 24, output4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process left overs
|
||||
for (; offset < buffer.Length; offset++)
|
||||
for (; Offset < Buffer.Length; Offset++)
|
||||
{
|
||||
output[offset] = DspUtils.Saturate(buffer[offset]);
|
||||
Output[Offset] = DspUtils.Saturate(Buffer[Offset]);
|
||||
}
|
||||
|
||||
return output;
|
||||
return Output;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -396,11 +396,11 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (disposing)
|
||||
if (Disposing)
|
||||
{
|
||||
_audioOut.CloseTrack(_track);
|
||||
AudioOut.CloseTrack(Track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
||||
{
|
||||
enum MemoryPoolState
|
||||
enum MemoryPoolState : int
|
||||
{
|
||||
Invalid = 0,
|
||||
Unknown = 1,
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
static class Resampler
|
||||
{
|
||||
#region "LookUp Tables"
|
||||
private static short[] _curveLut0 = new short[]
|
||||
private static short[] CurveLut0 = new short[]
|
||||
{
|
||||
6600, 19426, 6722, 3, 6479, 19424, 6845, 9, 6359, 19419, 6968, 15, 6239, 19412, 7093, 22,
|
||||
6121, 19403, 7219, 28, 6004, 19391, 7345, 34, 5888, 19377, 7472, 41, 5773, 19361, 7600, 48,
|
||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
22, 7093, 19412, 6239, 15, 6968, 19419, 6359, 9, 6845, 19424, 6479, 3, 6722, 19426, 6600
|
||||
};
|
||||
|
||||
private static short[] _curveLut1 = new short[]
|
||||
private static short[] CurveLut1 = new short[]
|
||||
{
|
||||
-68, 32639, 69, -5, -200, 32630, 212, -15, -328, 32613, 359, -26, -450, 32586, 512, -36,
|
||||
-568, 32551, 669, -47, -680, 32507, 832, -58, -788, 32454, 1000, -69, -891, 32393, 1174, -80,
|
||||
|
@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
-36, 512, 32586, -450, -26, 359, 32613, -328, -15, 212, 32630, -200, -5, 69, 32639, -68
|
||||
};
|
||||
|
||||
private static short[] _curveLut2 = new short[]
|
||||
private static short[] CurveLut2 = new short[]
|
||||
{
|
||||
3195, 26287, 3329, -32, 3064, 26281, 3467, -34, 2936, 26270, 3608, -38, 2811, 26253, 3751, -42,
|
||||
2688, 26230, 3897, -46, 2568, 26202, 4046, -50, 2451, 26169, 4199, -54, 2338, 26130, 4354, -58,
|
||||
|
@ -115,77 +115,77 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
#endregion
|
||||
|
||||
public static int[] Resample2Ch(
|
||||
int[] buffer,
|
||||
int srcSampleRate,
|
||||
int dstSampleRate,
|
||||
int samplesCount,
|
||||
ref int fracPart)
|
||||
int[] Buffer,
|
||||
int SrcSampleRate,
|
||||
int DstSampleRate,
|
||||
int SamplesCount,
|
||||
ref int FracPart)
|
||||
{
|
||||
if (buffer == null)
|
||||
if (Buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
throw new ArgumentNullException(nameof(Buffer));
|
||||
}
|
||||
|
||||
if (srcSampleRate <= 0)
|
||||
if (SrcSampleRate <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(srcSampleRate));
|
||||
throw new ArgumentOutOfRangeException(nameof(SrcSampleRate));
|
||||
}
|
||||
|
||||
if (dstSampleRate <= 0)
|
||||
if (DstSampleRate <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(dstSampleRate));
|
||||
throw new ArgumentOutOfRangeException(nameof(DstSampleRate));
|
||||
}
|
||||
|
||||
double ratio = (double)srcSampleRate / dstSampleRate;
|
||||
double Ratio = (double)SrcSampleRate / DstSampleRate;
|
||||
|
||||
int newSamplesCount = (int)(samplesCount / ratio);
|
||||
int NewSamplesCount = (int)(SamplesCount / Ratio);
|
||||
|
||||
int step = (int)(ratio * 0x8000);
|
||||
int Step = (int)(Ratio * 0x8000);
|
||||
|
||||
int[] output = new int[newSamplesCount * 2];
|
||||
int[] Output = new int[NewSamplesCount * 2];
|
||||
|
||||
short[] lut;
|
||||
short[] Lut;
|
||||
|
||||
if (step > 0xaaaa)
|
||||
if (Step > 0xaaaa)
|
||||
{
|
||||
lut = _curveLut0;
|
||||
Lut = CurveLut0;
|
||||
}
|
||||
else if (step <= 0x8000)
|
||||
else if (Step <= 0x8000)
|
||||
{
|
||||
lut = _curveLut1;
|
||||
Lut = CurveLut1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lut = _curveLut2;
|
||||
Lut = CurveLut2;
|
||||
}
|
||||
|
||||
int inOffs = 0;
|
||||
int InOffs = 0;
|
||||
|
||||
for (int outOffs = 0; outOffs < output.Length; outOffs += 2)
|
||||
for (int OutOffs = 0; OutOffs < Output.Length; OutOffs += 2)
|
||||
{
|
||||
int lutIndex = (fracPart >> 8) * 4;
|
||||
int LutIndex = (FracPart >> 8) * 4;
|
||||
|
||||
int sample0 = buffer[(inOffs + 0) * 2 + 0] * lut[lutIndex + 0] +
|
||||
buffer[(inOffs + 1) * 2 + 0] * lut[lutIndex + 1] +
|
||||
buffer[(inOffs + 2) * 2 + 0] * lut[lutIndex + 2] +
|
||||
buffer[(inOffs + 3) * 2 + 0] * lut[lutIndex + 3];
|
||||
int Sample0 = Buffer[(InOffs + 0) * 2 + 0] * Lut[LutIndex + 0] +
|
||||
Buffer[(InOffs + 1) * 2 + 0] * Lut[LutIndex + 1] +
|
||||
Buffer[(InOffs + 2) * 2 + 0] * Lut[LutIndex + 2] +
|
||||
Buffer[(InOffs + 3) * 2 + 0] * Lut[LutIndex + 3];
|
||||
|
||||
int sample1 = buffer[(inOffs + 0) * 2 + 1] * lut[lutIndex + 0] +
|
||||
buffer[(inOffs + 1) * 2 + 1] * lut[lutIndex + 1] +
|
||||
buffer[(inOffs + 2) * 2 + 1] * lut[lutIndex + 2] +
|
||||
buffer[(inOffs + 3) * 2 + 1] * lut[lutIndex + 3];
|
||||
int Sample1 = Buffer[(InOffs + 0) * 2 + 1] * Lut[LutIndex + 0] +
|
||||
Buffer[(InOffs + 1) * 2 + 1] * Lut[LutIndex + 1] +
|
||||
Buffer[(InOffs + 2) * 2 + 1] * Lut[LutIndex + 2] +
|
||||
Buffer[(InOffs + 3) * 2 + 1] * Lut[LutIndex + 3];
|
||||
|
||||
int newOffset = fracPart + step;
|
||||
int NewOffset = FracPart + Step;
|
||||
|
||||
inOffs += newOffset >> 15;
|
||||
InOffs += NewOffset >> 15;
|
||||
|
||||
fracPart = newOffset & 0x7fff;
|
||||
FracPart = NewOffset & 0x7fff;
|
||||
|
||||
output[outOffs + 0] = sample0 >> 15;
|
||||
output[outOffs + 1] = sample1 >> 15;
|
||||
Output[OutOffs + 0] = Sample0 >> 15;
|
||||
Output[OutOffs + 1] = Sample1 >> 15;
|
||||
}
|
||||
|
||||
return output;
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,13 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
{
|
||||
class VoiceContext
|
||||
{
|
||||
private bool _acquired;
|
||||
private bool _bufferReload;
|
||||
private bool Acquired;
|
||||
private bool BufferReload;
|
||||
|
||||
private int _resamplerFracPart;
|
||||
private int ResamplerFracPart;
|
||||
|
||||
private int _bufferIndex;
|
||||
private int _offset;
|
||||
private int BufferIndex;
|
||||
private int Offset;
|
||||
|
||||
public int SampleRate;
|
||||
public int ChannelsCount;
|
||||
|
@ -29,138 +29,138 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
|
||||
public VoiceOut OutStatus;
|
||||
|
||||
private int[] _samples;
|
||||
private int[] Samples;
|
||||
|
||||
public bool Playing => _acquired && PlayState == PlayState.Playing;
|
||||
public bool Playing => Acquired && PlayState == PlayState.Playing;
|
||||
|
||||
public VoiceContext()
|
||||
{
|
||||
WaveBuffers = new WaveBuffer[4];
|
||||
}
|
||||
|
||||
public void SetAcquireState(bool newState)
|
||||
public void SetAcquireState(bool NewState)
|
||||
{
|
||||
if (_acquired && !newState)
|
||||
if (Acquired && !NewState)
|
||||
{
|
||||
//Release.
|
||||
Reset();
|
||||
}
|
||||
|
||||
_acquired = newState;
|
||||
Acquired = NewState;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_bufferReload = true;
|
||||
BufferReload = true;
|
||||
|
||||
_bufferIndex = 0;
|
||||
_offset = 0;
|
||||
BufferIndex = 0;
|
||||
Offset = 0;
|
||||
|
||||
OutStatus.PlayedSamplesCount = 0;
|
||||
OutStatus.PlayedWaveBuffersCount = 0;
|
||||
OutStatus.VoiceDropsCount = 0;
|
||||
}
|
||||
|
||||
public int[] GetBufferData(MemoryManager memory, int maxSamples, out int samplesCount)
|
||||
public int[] GetBufferData(MemoryManager Memory, int MaxSamples, out int SamplesCount)
|
||||
{
|
||||
if (!Playing)
|
||||
{
|
||||
samplesCount = 0;
|
||||
SamplesCount = 0;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_bufferReload)
|
||||
if (BufferReload)
|
||||
{
|
||||
_bufferReload = false;
|
||||
BufferReload = false;
|
||||
|
||||
UpdateBuffer(memory);
|
||||
UpdateBuffer(Memory);
|
||||
}
|
||||
|
||||
WaveBuffer wb = WaveBuffers[_bufferIndex];
|
||||
WaveBuffer Wb = WaveBuffers[BufferIndex];
|
||||
|
||||
int maxSize = _samples.Length - _offset;
|
||||
int MaxSize = Samples.Length - Offset;
|
||||
|
||||
int size = maxSamples * AudioConsts.HostChannelsCount;
|
||||
int Size = MaxSamples * AudioConsts.HostChannelsCount;
|
||||
|
||||
if (size > maxSize)
|
||||
if (Size > MaxSize)
|
||||
{
|
||||
size = maxSize;
|
||||
Size = MaxSize;
|
||||
}
|
||||
|
||||
int[] output = new int[size];
|
||||
int[] Output = new int[Size];
|
||||
|
||||
Array.Copy(_samples, _offset, output, 0, size);
|
||||
Array.Copy(Samples, Offset, Output, 0, Size);
|
||||
|
||||
samplesCount = size / AudioConsts.HostChannelsCount;
|
||||
SamplesCount = Size / AudioConsts.HostChannelsCount;
|
||||
|
||||
OutStatus.PlayedSamplesCount += samplesCount;
|
||||
OutStatus.PlayedSamplesCount += SamplesCount;
|
||||
|
||||
_offset += size;
|
||||
Offset += Size;
|
||||
|
||||
if (_offset == _samples.Length)
|
||||
if (Offset == Samples.Length)
|
||||
{
|
||||
_offset = 0;
|
||||
Offset = 0;
|
||||
|
||||
if (wb.Looping == 0)
|
||||
if (Wb.Looping == 0)
|
||||
{
|
||||
SetBufferIndex((_bufferIndex + 1) & 3);
|
||||
SetBufferIndex((BufferIndex + 1) & 3);
|
||||
}
|
||||
|
||||
OutStatus.PlayedWaveBuffersCount++;
|
||||
|
||||
if (wb.LastBuffer != 0)
|
||||
if (Wb.LastBuffer != 0)
|
||||
{
|
||||
PlayState = PlayState.Paused;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
return Output;
|
||||
}
|
||||
|
||||
private void UpdateBuffer(MemoryManager memory)
|
||||
private void UpdateBuffer(MemoryManager Memory)
|
||||
{
|
||||
//TODO: Implement conversion for formats other
|
||||
//than interleaved stereo (2 channels).
|
||||
//As of now, it assumes that HostChannelsCount == 2.
|
||||
WaveBuffer wb = WaveBuffers[_bufferIndex];
|
||||
WaveBuffer Wb = WaveBuffers[BufferIndex];
|
||||
|
||||
if (wb.Position == 0)
|
||||
if (Wb.Position == 0)
|
||||
{
|
||||
_samples = new int[0];
|
||||
Samples = new int[0];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SampleFormat == SampleFormat.PcmInt16)
|
||||
{
|
||||
int samplesCount = (int)(wb.Size / (sizeof(short) * ChannelsCount));
|
||||
int SamplesCount = (int)(Wb.Size / (sizeof(short) * ChannelsCount));
|
||||
|
||||
_samples = new int[samplesCount * AudioConsts.HostChannelsCount];
|
||||
Samples = new int[SamplesCount * AudioConsts.HostChannelsCount];
|
||||
|
||||
if (ChannelsCount == 1)
|
||||
{
|
||||
for (int index = 0; index < samplesCount; index++)
|
||||
for (int Index = 0; Index < SamplesCount; Index++)
|
||||
{
|
||||
short sample = memory.ReadInt16(wb.Position + index * 2);
|
||||
short Sample = Memory.ReadInt16(Wb.Position + Index * 2);
|
||||
|
||||
_samples[index * 2 + 0] = sample;
|
||||
_samples[index * 2 + 1] = sample;
|
||||
Samples[Index * 2 + 0] = Sample;
|
||||
Samples[Index * 2 + 1] = Sample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < samplesCount * 2; index++)
|
||||
for (int Index = 0; Index < SamplesCount * 2; Index++)
|
||||
{
|
||||
_samples[index] = memory.ReadInt16(wb.Position + index * 2);
|
||||
Samples[Index] = Memory.ReadInt16(Wb.Position + Index * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (SampleFormat == SampleFormat.Adpcm)
|
||||
{
|
||||
byte[] buffer = memory.ReadBytes(wb.Position, wb.Size);
|
||||
byte[] Buffer = Memory.ReadBytes(Wb.Position, Wb.Size);
|
||||
|
||||
_samples = AdpcmDecoder.Decode(buffer, AdpcmCtx);
|
||||
Samples = AdpcmDecoder.Decode(Buffer, AdpcmCtx);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -172,24 +172,24 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
//TODO: We should keep the frames being discarded (see the 4 below)
|
||||
//on a buffer and include it on the next samples buffer, to allow
|
||||
//the resampler to do seamless interpolation between wave buffers.
|
||||
int samplesCount = _samples.Length / AudioConsts.HostChannelsCount;
|
||||
int SamplesCount = Samples.Length / AudioConsts.HostChannelsCount;
|
||||
|
||||
samplesCount = Math.Max(samplesCount - 4, 0);
|
||||
SamplesCount = Math.Max(SamplesCount - 4, 0);
|
||||
|
||||
_samples = Resampler.Resample2Ch(
|
||||
_samples,
|
||||
Samples = Resampler.Resample2Ch(
|
||||
Samples,
|
||||
SampleRate,
|
||||
AudioConsts.HostSampleRate,
|
||||
samplesCount,
|
||||
ref _resamplerFracPart);
|
||||
SamplesCount,
|
||||
ref ResamplerFracPart);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBufferIndex(int index)
|
||||
public void SetBufferIndex(int Index)
|
||||
{
|
||||
_bufferIndex = index & 3;
|
||||
BufferIndex = Index & 3;
|
||||
|
||||
_bufferReload = true;
|
||||
BufferReload = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
class IAudioDevice : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _systemEvent;
|
||||
private KEvent SystemEvent;
|
||||
|
||||
public IAudioDevice(Horizon system)
|
||||
public IAudioDevice(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, ListAudioDeviceName },
|
||||
{ 1, SetAudioDeviceOutputVolume },
|
||||
|
@ -33,197 +33,197 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{ 12, QueryAudioDeviceOutputEvent }
|
||||
};
|
||||
|
||||
_systemEvent = new KEvent(system);
|
||||
SystemEvent = new KEvent(System);
|
||||
|
||||
//TODO: We shouldn't be signaling this here.
|
||||
_systemEvent.ReadableEvent.Signal();
|
||||
SystemEvent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
public long ListAudioDeviceName(ServiceCtx context)
|
||||
public long ListAudioDeviceName(ServiceCtx Context)
|
||||
{
|
||||
string[] deviceNames = SystemStateMgr.AudioOutputs;
|
||||
string[] DeviceNames = SystemStateMgr.AudioOutputs;
|
||||
|
||||
context.ResponseData.Write(deviceNames.Length);
|
||||
Context.ResponseData.Write(DeviceNames.Length);
|
||||
|
||||
long position = context.Request.ReceiveBuff[0].Position;
|
||||
long size = context.Request.ReceiveBuff[0].Size;
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
long Size = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
long basePosition = position;
|
||||
long BasePosition = Position;
|
||||
|
||||
foreach (string name in deviceNames)
|
||||
foreach (string Name in DeviceNames)
|
||||
{
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(name + "\0");
|
||||
byte[] Buffer = Encoding.ASCII.GetBytes(Name + "\0");
|
||||
|
||||
if ((position - basePosition) + buffer.Length > size)
|
||||
if ((Position - BasePosition) + Buffer.Length > Size)
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, buffer);
|
||||
Context.Memory.WriteBytes(Position, Buffer);
|
||||
|
||||
position += buffer.Length;
|
||||
Position += Buffer.Length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetAudioDeviceOutputVolume(ServiceCtx context)
|
||||
public long SetAudioDeviceOutputVolume(ServiceCtx Context)
|
||||
{
|
||||
float volume = context.RequestData.ReadSingle();
|
||||
float Volume = Context.RequestData.ReadSingle();
|
||||
|
||||
long position = context.Request.SendBuff[0].Position;
|
||||
long size = context.Request.SendBuff[0].Size;
|
||||
long Position = Context.Request.SendBuff[0].Position;
|
||||
long Size = Context.Request.SendBuff[0].Size;
|
||||
|
||||
byte[] deviceNameBuffer = context.Memory.ReadBytes(position, size);
|
||||
byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size);
|
||||
|
||||
string deviceName = Encoding.ASCII.GetString(deviceNameBuffer);
|
||||
string DeviceName = Encoding.ASCII.GetString(DeviceNameBuffer);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetActiveAudioDeviceName(ServiceCtx context)
|
||||
public long GetActiveAudioDeviceName(ServiceCtx Context)
|
||||
{
|
||||
string name = context.Device.System.State.ActiveAudioOutput;
|
||||
string Name = Context.Device.System.State.ActiveAudioOutput;
|
||||
|
||||
long position = context.Request.ReceiveBuff[0].Position;
|
||||
long size = context.Request.ReceiveBuff[0].Size;
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
long Size = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(name + "\0");
|
||||
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(Name + "\0");
|
||||
|
||||
if ((ulong)deviceNameBuffer.Length <= (ulong)size)
|
||||
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
|
||||
{
|
||||
context.Memory.WriteBytes(position, deviceNameBuffer);
|
||||
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QueryAudioDeviceSystemEvent(ServiceCtx context)
|
||||
public long QueryAudioDeviceSystemEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetActiveChannelCount(ServiceCtx context)
|
||||
public long GetActiveChannelCount(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(2);
|
||||
Context.ResponseData.Write(2);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ListAudioDeviceNameAuto(ServiceCtx context)
|
||||
public long ListAudioDeviceNameAuto(ServiceCtx Context)
|
||||
{
|
||||
string[] deviceNames = SystemStateMgr.AudioOutputs;
|
||||
string[] DeviceNames = SystemStateMgr.AudioOutputs;
|
||||
|
||||
context.ResponseData.Write(deviceNames.Length);
|
||||
Context.ResponseData.Write(DeviceNames.Length);
|
||||
|
||||
(long position, long size) = context.Request.GetBufferType0x22();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x22();
|
||||
|
||||
long basePosition = position;
|
||||
long BasePosition = Position;
|
||||
|
||||
foreach (string name in deviceNames)
|
||||
foreach (string Name in DeviceNames)
|
||||
{
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(name + '\0');
|
||||
byte[] Buffer = Encoding.UTF8.GetBytes(Name + '\0');
|
||||
|
||||
if ((position - basePosition) + buffer.Length > size)
|
||||
if ((Position - BasePosition) + Buffer.Length > Size)
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, buffer);
|
||||
Context.Memory.WriteBytes(Position, Buffer);
|
||||
|
||||
position += buffer.Length;
|
||||
Position += Buffer.Length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetAudioDeviceOutputVolumeAuto(ServiceCtx context)
|
||||
public long SetAudioDeviceOutputVolumeAuto(ServiceCtx Context)
|
||||
{
|
||||
float volume = context.RequestData.ReadSingle();
|
||||
float Volume = Context.RequestData.ReadSingle();
|
||||
|
||||
(long position, long size) = context.Request.GetBufferType0x21();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x21();
|
||||
|
||||
byte[] deviceNameBuffer = context.Memory.ReadBytes(position, size);
|
||||
byte[] DeviceNameBuffer = Context.Memory.ReadBytes(Position, Size);
|
||||
|
||||
string deviceName = Encoding.UTF8.GetString(deviceNameBuffer);
|
||||
string DeviceName = Encoding.UTF8.GetString(DeviceNameBuffer);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetAudioDeviceOutputVolumeAuto(ServiceCtx context)
|
||||
public long GetAudioDeviceOutputVolumeAuto(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(1f);
|
||||
Context.ResponseData.Write(1f);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetActiveAudioDeviceNameAuto(ServiceCtx context)
|
||||
public long GetActiveAudioDeviceNameAuto(ServiceCtx Context)
|
||||
{
|
||||
string name = context.Device.System.State.ActiveAudioOutput;
|
||||
string Name = Context.Device.System.State.ActiveAudioOutput;
|
||||
|
||||
(long position, long size) = context.Request.GetBufferType0x22();
|
||||
(long Position, long Size) = Context.Request.GetBufferType0x22();
|
||||
|
||||
byte[] deviceNameBuffer = Encoding.UTF8.GetBytes(name + '\0');
|
||||
byte[] DeviceNameBuffer = Encoding.UTF8.GetBytes(Name + '\0');
|
||||
|
||||
if ((ulong)deviceNameBuffer.Length <= (ulong)size)
|
||||
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
|
||||
{
|
||||
context.Memory.WriteBytes(position, deviceNameBuffer);
|
||||
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QueryAudioDeviceInputEvent(ServiceCtx context)
|
||||
public long QueryAudioDeviceInputEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QueryAudioDeviceOutputEvent(ServiceCtx context)
|
||||
public long QueryAudioDeviceOutputEvent(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_systemEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
private const int DefaultChannelsCount = 2;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioOutManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, ListAudioOuts },
|
||||
{ 1, OpenAudioOut },
|
||||
|
@ -34,135 +34,135 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
};
|
||||
}
|
||||
|
||||
public long ListAudioOuts(ServiceCtx context)
|
||||
public long ListAudioOuts(ServiceCtx Context)
|
||||
{
|
||||
return ListAudioOutsImpl(
|
||||
context,
|
||||
context.Request.ReceiveBuff[0].Position,
|
||||
context.Request.ReceiveBuff[0].Size);
|
||||
Context,
|
||||
Context.Request.ReceiveBuff[0].Position,
|
||||
Context.Request.ReceiveBuff[0].Size);
|
||||
}
|
||||
|
||||
public long OpenAudioOut(ServiceCtx context)
|
||||
public long OpenAudioOut(ServiceCtx Context)
|
||||
{
|
||||
return OpenAudioOutImpl(
|
||||
context,
|
||||
context.Request.SendBuff[0].Position,
|
||||
context.Request.SendBuff[0].Size,
|
||||
context.Request.ReceiveBuff[0].Position,
|
||||
context.Request.ReceiveBuff[0].Size);
|
||||
Context,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size,
|
||||
Context.Request.ReceiveBuff[0].Position,
|
||||
Context.Request.ReceiveBuff[0].Size);
|
||||
}
|
||||
|
||||
public long ListAudioOutsAuto(ServiceCtx context)
|
||||
public long ListAudioOutsAuto(ServiceCtx Context)
|
||||
{
|
||||
(long recvPosition, long recvSize) = context.Request.GetBufferType0x22();
|
||||
(long RecvPosition, long RecvSize) = Context.Request.GetBufferType0x22();
|
||||
|
||||
return ListAudioOutsImpl(context, recvPosition, recvSize);
|
||||
return ListAudioOutsImpl(Context, RecvPosition, RecvSize);
|
||||
}
|
||||
|
||||
public long OpenAudioOutAuto(ServiceCtx context)
|
||||
public long OpenAudioOutAuto(ServiceCtx Context)
|
||||
{
|
||||
(long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
|
||||
(long recvPosition, long recvSize) = context.Request.GetBufferType0x22();
|
||||
(long SendPosition, long SendSize) = Context.Request.GetBufferType0x21();
|
||||
(long RecvPosition, long RecvSize) = Context.Request.GetBufferType0x22();
|
||||
|
||||
return OpenAudioOutImpl(
|
||||
context,
|
||||
sendPosition,
|
||||
sendSize,
|
||||
recvPosition,
|
||||
recvSize);
|
||||
Context,
|
||||
SendPosition,
|
||||
SendSize,
|
||||
RecvPosition,
|
||||
RecvSize);
|
||||
}
|
||||
|
||||
private long ListAudioOutsImpl(ServiceCtx context, long position, long size)
|
||||
private long ListAudioOutsImpl(ServiceCtx Context, long Position, long Size)
|
||||
{
|
||||
int nameCount = 0;
|
||||
int NameCount = 0;
|
||||
|
||||
byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0");
|
||||
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DefaultAudioOutput + "\0");
|
||||
|
||||
if ((ulong)deviceNameBuffer.Length <= (ulong)size)
|
||||
if ((ulong)DeviceNameBuffer.Length <= (ulong)Size)
|
||||
{
|
||||
context.Memory.WriteBytes(position, deviceNameBuffer);
|
||||
Context.Memory.WriteBytes(Position, DeviceNameBuffer);
|
||||
|
||||
nameCount++;
|
||||
NameCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
}
|
||||
|
||||
context.ResponseData.Write(nameCount);
|
||||
Context.ResponseData.Write(NameCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long OpenAudioOutImpl(ServiceCtx context, long sendPosition, long sendSize, long receivePosition, long receiveSize)
|
||||
private long OpenAudioOutImpl(ServiceCtx Context, long SendPosition, long SendSize, long ReceivePosition, long ReceiveSize)
|
||||
{
|
||||
string deviceName = MemoryHelper.ReadAsciiString(
|
||||
context.Memory,
|
||||
sendPosition,
|
||||
sendSize);
|
||||
string DeviceName = MemoryHelper.ReadAsciiString(
|
||||
Context.Memory,
|
||||
SendPosition,
|
||||
SendSize);
|
||||
|
||||
if (deviceName == string.Empty)
|
||||
if (DeviceName == string.Empty)
|
||||
{
|
||||
deviceName = DefaultAudioOutput;
|
||||
DeviceName = DefaultAudioOutput;
|
||||
}
|
||||
|
||||
if (deviceName != DefaultAudioOutput)
|
||||
if (DeviceName != DefaultAudioOutput)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Audio, "Invalid device name!");
|
||||
|
||||
return MakeError(ErrorModule.Audio, AudErr.DeviceNotFound);
|
||||
}
|
||||
|
||||
byte[] deviceNameBuffer = Encoding.ASCII.GetBytes(deviceName + "\0");
|
||||
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DeviceName + "\0");
|
||||
|
||||
if ((ulong)deviceNameBuffer.Length <= (ulong)receiveSize)
|
||||
if ((ulong)DeviceNameBuffer.Length <= (ulong)ReceiveSize)
|
||||
{
|
||||
context.Memory.WriteBytes(receivePosition, deviceNameBuffer);
|
||||
Context.Memory.WriteBytes(ReceivePosition, DeviceNameBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {receiveSize} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {ReceiveSize} too small!");
|
||||
}
|
||||
|
||||
int sampleRate = context.RequestData.ReadInt32();
|
||||
int channels = context.RequestData.ReadInt32();
|
||||
int SampleRate = Context.RequestData.ReadInt32();
|
||||
int Channels = Context.RequestData.ReadInt32();
|
||||
|
||||
if (sampleRate == 0)
|
||||
if (SampleRate == 0)
|
||||
{
|
||||
sampleRate = DefaultSampleRate;
|
||||
SampleRate = DefaultSampleRate;
|
||||
}
|
||||
|
||||
if (sampleRate != DefaultSampleRate)
|
||||
if (SampleRate != DefaultSampleRate)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Audio, "Invalid sample rate!");
|
||||
|
||||
return MakeError(ErrorModule.Audio, AudErr.UnsupportedSampleRate);
|
||||
}
|
||||
|
||||
channels = (ushort)channels;
|
||||
Channels = (ushort)Channels;
|
||||
|
||||
if (channels == 0)
|
||||
if (Channels == 0)
|
||||
{
|
||||
channels = DefaultChannelsCount;
|
||||
Channels = DefaultChannelsCount;
|
||||
}
|
||||
|
||||
KEvent releaseEvent = new KEvent(context.Device.System);
|
||||
KEvent ReleaseEvent = new KEvent(Context.Device.System);
|
||||
|
||||
ReleaseCallback callback = () =>
|
||||
ReleaseCallback Callback = () =>
|
||||
{
|
||||
releaseEvent.ReadableEvent.Signal();
|
||||
ReleaseEvent.ReadableEvent.Signal();
|
||||
};
|
||||
|
||||
IAalOutput audioOut = context.Device.AudioOut;
|
||||
IAalOutput AudioOut = Context.Device.AudioOut;
|
||||
|
||||
int track = audioOut.OpenTrack(sampleRate, channels, callback);
|
||||
int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback);
|
||||
|
||||
MakeObject(context, new IAudioOut(audioOut, releaseEvent, track));
|
||||
MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));
|
||||
|
||||
context.ResponseData.Write(sampleRate);
|
||||
context.ResponseData.Write(channels);
|
||||
context.ResponseData.Write((int)SampleFormat.PcmInt16);
|
||||
context.ResponseData.Write((int)PlaybackState.Stopped);
|
||||
Context.ResponseData.Write(SampleRate);
|
||||
Context.ResponseData.Write(Channels);
|
||||
Context.ResponseData.Write((int)SampleFormat.PcmInt16);
|
||||
Context.ResponseData.Write((int)PlaybackState.Stopped);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
public const int RevMagic = Rev0Magic + (Rev << 24);
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioRendererManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, OpenAudioRenderer },
|
||||
{ 1, GetAudioRendererWorkBufferSize },
|
||||
|
@ -35,81 +35,81 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
};
|
||||
}
|
||||
|
||||
public long OpenAudioRenderer(ServiceCtx context)
|
||||
public long OpenAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
IAalOutput audioOut = context.Device.AudioOut;
|
||||
IAalOutput AudioOut = Context.Device.AudioOut;
|
||||
|
||||
AudioRendererParameter Params = GetAudioRendererParameter(context);
|
||||
AudioRendererParameter Params = GetAudioRendererParameter(Context);
|
||||
|
||||
MakeObject(context, new IAudioRenderer(
|
||||
context.Device.System,
|
||||
context.Memory,
|
||||
audioOut,
|
||||
MakeObject(Context, new IAudioRenderer(
|
||||
Context.Device.System,
|
||||
Context.Memory,
|
||||
AudioOut,
|
||||
Params));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetAudioRendererWorkBufferSize(ServiceCtx context)
|
||||
public long GetAudioRendererWorkBufferSize(ServiceCtx Context)
|
||||
{
|
||||
AudioRendererParameter Params = GetAudioRendererParameter(context);
|
||||
AudioRendererParameter Params = GetAudioRendererParameter(Context);
|
||||
|
||||
int revision = (Params.Revision - Rev0Magic) >> 24;
|
||||
int Revision = (Params.Revision - Rev0Magic) >> 24;
|
||||
|
||||
if (revision <= Rev)
|
||||
if (Revision <= Rev)
|
||||
{
|
||||
bool isSplitterSupported = revision >= 3;
|
||||
bool IsSplitterSupported = Revision >= 3;
|
||||
|
||||
long size;
|
||||
long Size;
|
||||
|
||||
size = IntUtils.AlignUp(Params.Unknown8 * 4, 64);
|
||||
size += Params.MixCount * 0x400;
|
||||
size += (Params.MixCount + 1) * 0x940;
|
||||
size += Params.VoiceCount * 0x3F0;
|
||||
size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16);
|
||||
size += IntUtils.AlignUp(Params.VoiceCount * 8, 16);
|
||||
size += IntUtils.AlignUp(
|
||||
Size = IntUtils.AlignUp(Params.Unknown8 * 4, 64);
|
||||
Size += Params.MixCount * 0x400;
|
||||
Size += (Params.MixCount + 1) * 0x940;
|
||||
Size += Params.VoiceCount * 0x3F0;
|
||||
Size += IntUtils.AlignUp((Params.MixCount + 1) * 8, 16);
|
||||
Size += IntUtils.AlignUp(Params.VoiceCount * 8, 16);
|
||||
Size += IntUtils.AlignUp(
|
||||
((Params.SinkCount + Params.MixCount) * 0x3C0 + Params.SampleCount * 4) *
|
||||
(Params.Unknown8 + 6), 64);
|
||||
size += (Params.SinkCount + Params.MixCount) * 0x2C0;
|
||||
size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50;
|
||||
Size += (Params.SinkCount + Params.MixCount) * 0x2C0;
|
||||
Size += (Params.EffectCount + Params.VoiceCount * 4) * 0x30 + 0x50;
|
||||
|
||||
if (isSplitterSupported)
|
||||
if (IsSplitterSupported)
|
||||
{
|
||||
size += IntUtils.AlignUp((
|
||||
Size += IntUtils.AlignUp((
|
||||
NodeStatesGetWorkBufferSize(Params.MixCount + 1) +
|
||||
EdgeMatrixGetWorkBufferSize(Params.MixCount + 1)), 16);
|
||||
|
||||
size += Params.SplitterDestinationDataCount * 0xE0;
|
||||
size += Params.SplitterCount * 0x20;
|
||||
size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16);
|
||||
Size += Params.SplitterDestinationDataCount * 0xE0;
|
||||
Size += Params.SplitterCount * 0x20;
|
||||
Size += IntUtils.AlignUp(Params.SplitterDestinationDataCount * 4, 16);
|
||||
}
|
||||
|
||||
size = Params.EffectCount * 0x4C0 +
|
||||
Size = Params.EffectCount * 0x4C0 +
|
||||
Params.SinkCount * 0x170 +
|
||||
Params.VoiceCount * 0x100 +
|
||||
IntUtils.AlignUp(size, 64) + 0x40;
|
||||
IntUtils.AlignUp(Size, 64) + 0x40;
|
||||
|
||||
if (Params.PerformanceManagerCount >= 1)
|
||||
{
|
||||
size += (((Params.EffectCount +
|
||||
Size += (((Params.EffectCount +
|
||||
Params.SinkCount +
|
||||
Params.VoiceCount +
|
||||
Params.MixCount + 1) * 16 + 0x658) *
|
||||
(Params.PerformanceManagerCount + 1) + 0x13F) & ~0x3FL;
|
||||
}
|
||||
|
||||
size = (size + 0x1907D) & ~0xFFFL;
|
||||
Size = (Size + 0x1907D) & ~0xFFFL;
|
||||
|
||||
context.ResponseData.Write(size);
|
||||
Context.ResponseData.Write(Size);
|
||||
|
||||
Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}.");
|
||||
Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{Size:x16}.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!");
|
||||
|
||||
|
@ -117,71 +117,71 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
}
|
||||
}
|
||||
|
||||
private AudioRendererParameter GetAudioRendererParameter(ServiceCtx context)
|
||||
private AudioRendererParameter GetAudioRendererParameter(ServiceCtx Context)
|
||||
{
|
||||
AudioRendererParameter Params = new AudioRendererParameter();
|
||||
|
||||
Params.SampleRate = context.RequestData.ReadInt32();
|
||||
Params.SampleCount = context.RequestData.ReadInt32();
|
||||
Params.Unknown8 = context.RequestData.ReadInt32();
|
||||
Params.MixCount = context.RequestData.ReadInt32();
|
||||
Params.VoiceCount = context.RequestData.ReadInt32();
|
||||
Params.SinkCount = context.RequestData.ReadInt32();
|
||||
Params.EffectCount = context.RequestData.ReadInt32();
|
||||
Params.PerformanceManagerCount = context.RequestData.ReadInt32();
|
||||
Params.VoiceDropEnable = context.RequestData.ReadInt32();
|
||||
Params.SplitterCount = context.RequestData.ReadInt32();
|
||||
Params.SplitterDestinationDataCount = context.RequestData.ReadInt32();
|
||||
Params.Unknown2C = context.RequestData.ReadInt32();
|
||||
Params.Revision = context.RequestData.ReadInt32();
|
||||
Params.SampleRate = Context.RequestData.ReadInt32();
|
||||
Params.SampleCount = Context.RequestData.ReadInt32();
|
||||
Params.Unknown8 = Context.RequestData.ReadInt32();
|
||||
Params.MixCount = Context.RequestData.ReadInt32();
|
||||
Params.VoiceCount = Context.RequestData.ReadInt32();
|
||||
Params.SinkCount = Context.RequestData.ReadInt32();
|
||||
Params.EffectCount = Context.RequestData.ReadInt32();
|
||||
Params.PerformanceManagerCount = Context.RequestData.ReadInt32();
|
||||
Params.VoiceDropEnable = Context.RequestData.ReadInt32();
|
||||
Params.SplitterCount = Context.RequestData.ReadInt32();
|
||||
Params.SplitterDestinationDataCount = Context.RequestData.ReadInt32();
|
||||
Params.Unknown2C = Context.RequestData.ReadInt32();
|
||||
Params.Revision = Context.RequestData.ReadInt32();
|
||||
|
||||
return Params;
|
||||
}
|
||||
|
||||
private static int NodeStatesGetWorkBufferSize(int value)
|
||||
private static int NodeStatesGetWorkBufferSize(int Value)
|
||||
{
|
||||
int result = IntUtils.AlignUp(value, 64);
|
||||
int Result = IntUtils.AlignUp(Value, 64);
|
||||
|
||||
if (result < 0)
|
||||
if (Result < 0)
|
||||
{
|
||||
result |= 7;
|
||||
Result |= 7;
|
||||
}
|
||||
|
||||
return 4 * (value * value) + 0x12 * value + 2 * (result / 8);
|
||||
return 4 * (Value * Value) + 0x12 * Value + 2 * (Result / 8);
|
||||
}
|
||||
|
||||
private static int EdgeMatrixGetWorkBufferSize(int value)
|
||||
private static int EdgeMatrixGetWorkBufferSize(int Value)
|
||||
{
|
||||
int result = IntUtils.AlignUp(value * value, 64);
|
||||
int Result = IntUtils.AlignUp(Value * Value, 64);
|
||||
|
||||
if (result < 0)
|
||||
if (Result < 0)
|
||||
{
|
||||
result |= 7;
|
||||
Result |= 7;
|
||||
}
|
||||
|
||||
return result / 8;
|
||||
return Result / 8;
|
||||
}
|
||||
|
||||
// GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
|
||||
public long GetAudioDeviceService(ServiceCtx context)
|
||||
public long GetAudioDeviceService(ServiceCtx Context)
|
||||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
MakeObject(context, new IAudioDevice(context.Device.System));
|
||||
MakeObject(Context, new IAudioDevice(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object<nn::audio::detail::IAudioDevice>
|
||||
private long GetAudioDeviceServiceWithRevisionInfo(ServiceCtx context)
|
||||
private long GetAudioDeviceServiceWithRevisionInfo(ServiceCtx Context)
|
||||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
int revisionInfo = context.RequestData.ReadInt32();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
int RevisionInfo = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, $"Stubbed. AppletResourceUserId: {appletResourceUserId} - " +
|
||||
$"RevisionInfo: {revisionInfo}");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, $"Stubbed. AppletResourceUserId: {AppletResourceUserId} - " +
|
||||
$"RevisionInfo: {RevisionInfo}");
|
||||
|
||||
return GetAudioDeviceService(context);
|
||||
return GetAudioDeviceService(Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,80 +10,80 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
private const int FixedSampleRate = 48000;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private int _sampleRate;
|
||||
private int _channelsCount;
|
||||
private int SampleRate;
|
||||
private int ChannelsCount;
|
||||
|
||||
private OpusDecoder _decoder;
|
||||
private OpusDecoder Decoder;
|
||||
|
||||
public IHardwareOpusDecoder(int sampleRate, int channelsCount)
|
||||
public IHardwareOpusDecoder(int SampleRate, int ChannelsCount)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, DecodeInterleaved },
|
||||
{ 4, DecodeInterleavedWithPerf }
|
||||
};
|
||||
|
||||
_sampleRate = sampleRate;
|
||||
_channelsCount = channelsCount;
|
||||
this.SampleRate = SampleRate;
|
||||
this.ChannelsCount = ChannelsCount;
|
||||
|
||||
_decoder = new OpusDecoder(FixedSampleRate, channelsCount);
|
||||
Decoder = new OpusDecoder(FixedSampleRate, ChannelsCount);
|
||||
}
|
||||
|
||||
public long DecodeInterleavedWithPerf(ServiceCtx context)
|
||||
public long DecodeInterleavedWithPerf(ServiceCtx Context)
|
||||
{
|
||||
long result = DecodeInterleaved(context);
|
||||
long Result = DecodeInterleaved(Context);
|
||||
|
||||
//TODO: Figure out what this value is.
|
||||
//According to switchbrew, it is now used.
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
public long DecodeInterleaved(ServiceCtx context)
|
||||
public long DecodeInterleaved(ServiceCtx Context)
|
||||
{
|
||||
long inPosition = context.Request.SendBuff[0].Position;
|
||||
long inSize = context.Request.SendBuff[0].Size;
|
||||
long InPosition = Context.Request.SendBuff[0].Position;
|
||||
long InSize = Context.Request.SendBuff[0].Size;
|
||||
|
||||
if (inSize < 8)
|
||||
if (InSize < 8)
|
||||
{
|
||||
return MakeError(ErrorModule.Audio, AudErr.OpusInvalidInput);
|
||||
}
|
||||
|
||||
long outPosition = context.Request.ReceiveBuff[0].Position;
|
||||
long outSize = context.Request.ReceiveBuff[0].Size;
|
||||
long OutPosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long OutSize = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
byte[] opusData = context.Memory.ReadBytes(inPosition, inSize);
|
||||
byte[] OpusData = Context.Memory.ReadBytes(InPosition, InSize);
|
||||
|
||||
int processed = ((opusData[0] << 24) |
|
||||
(opusData[1] << 16) |
|
||||
(opusData[2] << 8) |
|
||||
(opusData[3] << 0)) + 8;
|
||||
int Processed = ((OpusData[0] << 24) |
|
||||
(OpusData[1] << 16) |
|
||||
(OpusData[2] << 8) |
|
||||
(OpusData[3] << 0)) + 8;
|
||||
|
||||
if ((uint)processed > (ulong)inSize)
|
||||
if ((uint)Processed > (ulong)InSize)
|
||||
{
|
||||
return MakeError(ErrorModule.Audio, AudErr.OpusInvalidInput);
|
||||
}
|
||||
|
||||
short[] pcm = new short[outSize / 2];
|
||||
short[] Pcm = new short[OutSize / 2];
|
||||
|
||||
int frameSize = pcm.Length / (_channelsCount * 2);
|
||||
int FrameSize = Pcm.Length / (ChannelsCount * 2);
|
||||
|
||||
int samples = _decoder.Decode(opusData, 0, opusData.Length, pcm, 0, frameSize);
|
||||
int Samples = Decoder.Decode(OpusData, 0, OpusData.Length, Pcm, 0, FrameSize);
|
||||
|
||||
foreach (short sample in pcm)
|
||||
foreach (short Sample in Pcm)
|
||||
{
|
||||
context.Memory.WriteInt16(outPosition, sample);
|
||||
Context.Memory.WriteInt16(OutPosition, Sample);
|
||||
|
||||
outPosition += 2;
|
||||
OutPosition += 2;
|
||||
}
|
||||
|
||||
context.ResponseData.Write(processed);
|
||||
context.ResponseData.Write(samples);
|
||||
Context.ResponseData.Write(Processed);
|
||||
Context.ResponseData.Write(Samples);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,68 +5,68 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
class IHardwareOpusDecoderManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IHardwareOpusDecoderManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Initialize },
|
||||
{ 1, GetWorkBufferSize }
|
||||
};
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
int sampleRate = context.RequestData.ReadInt32();
|
||||
int channelsCount = context.RequestData.ReadInt32();
|
||||
int SampleRate = Context.RequestData.ReadInt32();
|
||||
int ChannelsCount = Context.RequestData.ReadInt32();
|
||||
|
||||
MakeObject(context, new IHardwareOpusDecoder(sampleRate, channelsCount));
|
||||
MakeObject(Context, new IHardwareOpusDecoder(SampleRate, ChannelsCount));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetWorkBufferSize(ServiceCtx context)
|
||||
public long GetWorkBufferSize(ServiceCtx Context)
|
||||
{
|
||||
//Note: The sample rate is ignored because it is fixed to 48KHz.
|
||||
int sampleRate = context.RequestData.ReadInt32();
|
||||
int channelsCount = context.RequestData.ReadInt32();
|
||||
int SampleRate = Context.RequestData.ReadInt32();
|
||||
int ChannelsCount = Context.RequestData.ReadInt32();
|
||||
|
||||
context.ResponseData.Write(GetOpusDecoderSize(channelsCount));
|
||||
Context.ResponseData.Write(GetOpusDecoderSize(ChannelsCount));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int GetOpusDecoderSize(int channelsCount)
|
||||
private static int GetOpusDecoderSize(int ChannelsCount)
|
||||
{
|
||||
const int silkDecoderSize = 0x2198;
|
||||
const int SilkDecoderSize = 0x2198;
|
||||
|
||||
if (channelsCount < 1 || channelsCount > 2)
|
||||
if (ChannelsCount < 1 || ChannelsCount > 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int celtDecoderSize = GetCeltDecoderSize(channelsCount);
|
||||
int CeltDecoderSize = GetCeltDecoderSize(ChannelsCount);
|
||||
|
||||
int opusDecoderSize = (channelsCount * 0x800 + 0x4807) & -0x800 | 0x50;
|
||||
int OpusDecoderSize = (ChannelsCount * 0x800 + 0x4807) & -0x800 | 0x50;
|
||||
|
||||
return opusDecoderSize + silkDecoderSize + celtDecoderSize;
|
||||
return OpusDecoderSize + SilkDecoderSize + CeltDecoderSize;
|
||||
}
|
||||
|
||||
private static int GetCeltDecoderSize(int channelsCount)
|
||||
private static int GetCeltDecoderSize(int ChannelsCount)
|
||||
{
|
||||
const int decodeBufferSize = 0x2030;
|
||||
const int celtDecoderSize = 0x58;
|
||||
const int celtSigSize = 0x4;
|
||||
const int overlap = 120;
|
||||
const int eBandsCount = 21;
|
||||
const int DecodeBufferSize = 0x2030;
|
||||
const int CeltDecoderSize = 0x58;
|
||||
const int CeltSigSize = 0x4;
|
||||
const int Overlap = 120;
|
||||
const int EBandsCount = 21;
|
||||
|
||||
return (decodeBufferSize + overlap * 4) * channelsCount +
|
||||
eBandsCount * 16 +
|
||||
celtDecoderSize +
|
||||
celtSigSize;
|
||||
return (DecodeBufferSize + Overlap * 4) * ChannelsCount +
|
||||
EBandsCount * 16 +
|
||||
CeltDecoderSize +
|
||||
CeltSigSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Bcat
|
|||
{
|
||||
class IBcatService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IBcatService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Bcat
|
|||
{
|
||||
class IDeliveryCacheStorageService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IDeliveryCacheStorageService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,33 +5,33 @@ namespace Ryujinx.HLE.HOS.Services.Bcat
|
|||
{
|
||||
class IServiceCreator : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IServiceCreator()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CreateBcatService },
|
||||
{ 1, CreateDeliveryCacheStorageService }
|
||||
};
|
||||
}
|
||||
|
||||
public long CreateBcatService(ServiceCtx context)
|
||||
public long CreateBcatService(ServiceCtx Context)
|
||||
{
|
||||
long id = context.RequestData.ReadInt64();
|
||||
long Id = Context.RequestData.ReadInt64();
|
||||
|
||||
MakeObject(context, new IBcatService());
|
||||
MakeObject(Context, new IBcatService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateDeliveryCacheStorageService(ServiceCtx context)
|
||||
public long CreateDeliveryCacheStorageService(ServiceCtx Context)
|
||||
{
|
||||
long id = context.RequestData.ReadInt64();
|
||||
long Id = Context.RequestData.ReadInt64();
|
||||
|
||||
MakeObject(context, new IDeliveryCacheStorageService());
|
||||
MakeObject(Context, new IDeliveryCacheStorageService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
{
|
||||
enum BsdIoctl
|
||||
{
|
||||
AtMark = 0x40047307
|
||||
AtMark = 0x40047307,
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,20 +9,20 @@
|
|||
Output = 4,
|
||||
Error = 8,
|
||||
Disconnected = 0x10,
|
||||
Invalid = 0x20
|
||||
Invalid = 0x20,
|
||||
}
|
||||
|
||||
public int SocketFd { get; }
|
||||
public BsdSocket Socket { get; }
|
||||
public EventTypeMask InputEvents { get; }
|
||||
public EventTypeMask OutputEvents { get; }
|
||||
public int SocketFd { get; private set; }
|
||||
public BsdSocket Socket { get; private set; }
|
||||
public EventTypeMask InputEvents { get; private set; }
|
||||
public EventTypeMask OutputEvents { get; private set; }
|
||||
|
||||
public PollEvent(int socketFd, BsdSocket socket, EventTypeMask inputEvents, EventTypeMask outputEvents)
|
||||
public PollEvent(int SocketFd, BsdSocket Socket, EventTypeMask InputEvents, EventTypeMask OutputEvents)
|
||||
{
|
||||
SocketFd = socketFd;
|
||||
Socket = socket;
|
||||
InputEvents = inputEvents;
|
||||
OutputEvents = outputEvents;
|
||||
this.SocketFd = SocketFd;
|
||||
this.Socket = Socket;
|
||||
this.InputEvents = InputEvents;
|
||||
this.OutputEvents = OutputEvents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
|||
{
|
||||
class IAlbumAccessorService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAlbumAccessorService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
|||
{
|
||||
class IScreenshotService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IScreenshotService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Es
|
||||
{
|
||||
class IeTicketService : IpcService
|
||||
class IETicketService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private bool _isInitialized;
|
||||
private bool IsInitialized;
|
||||
|
||||
public IeTicketService()
|
||||
public IETicketService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
||||
};
|
||||
|
|
|
@ -8,13 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Friend
|
|||
{
|
||||
class IFriendService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IFriendService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 10101, GetFriendList },
|
||||
{ 10601, DeclareCloseOnlinePlaySession },
|
||||
|
@ -23,76 +23,76 @@ namespace Ryujinx.HLE.HOS.Services.Friend
|
|||
}
|
||||
|
||||
// nn::friends::GetFriendListGetFriendListIds(nn::account::Uid, int Unknown0, nn::friends::detail::ipc::SizedFriendFilter, ulong Unknown1) -> int CounterIds, array<nn::account::NetworkServiceAccountId>
|
||||
public long GetFriendList(ServiceCtx context)
|
||||
public long GetFriendList(ServiceCtx Context)
|
||||
{
|
||||
UInt128 uuid = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
int unknown0 = context.RequestData.ReadInt32();
|
||||
int Unknown0 = Context.RequestData.ReadInt32();
|
||||
|
||||
FriendFilter filter = new FriendFilter
|
||||
FriendFilter Filter = new FriendFilter()
|
||||
{
|
||||
PresenceStatus = (PresenceStatusFilter)context.RequestData.ReadInt32(),
|
||||
IsFavoriteOnly = context.RequestData.ReadBoolean(),
|
||||
IsSameAppPresenceOnly = context.RequestData.ReadBoolean(),
|
||||
IsSameAppPlayedOnly = context.RequestData.ReadBoolean(),
|
||||
IsArbitraryAppPlayedOnly = context.RequestData.ReadBoolean(),
|
||||
PresenceGroupId = context.RequestData.ReadInt64()
|
||||
PresenceStatus = (PresenceStatusFilter)Context.RequestData.ReadInt32(),
|
||||
IsFavoriteOnly = Context.RequestData.ReadBoolean(),
|
||||
IsSameAppPresenceOnly = Context.RequestData.ReadBoolean(),
|
||||
IsSameAppPlayedOnly = Context.RequestData.ReadBoolean(),
|
||||
IsArbitraryAppPlayedOnly = Context.RequestData.ReadBoolean(),
|
||||
PresenceGroupId = Context.RequestData.ReadInt64()
|
||||
};
|
||||
|
||||
long unknown1 = context.RequestData.ReadInt64();
|
||||
long Unknown1 = Context.RequestData.ReadInt64();
|
||||
|
||||
// There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty.
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. UserId: {uuid.ToString()} - " +
|
||||
$"Unknown0: {unknown0} - " +
|
||||
$"PresenceStatus: {filter.PresenceStatus} - " +
|
||||
$"IsFavoriteOnly: {filter.IsFavoriteOnly} - " +
|
||||
$"IsSameAppPresenceOnly: {filter.IsSameAppPresenceOnly} - " +
|
||||
$"IsSameAppPlayedOnly: {filter.IsSameAppPlayedOnly} - " +
|
||||
$"IsArbitraryAppPlayedOnly: {filter.IsArbitraryAppPlayedOnly} - " +
|
||||
$"PresenceGroupId: {filter.PresenceGroupId} - " +
|
||||
$"Unknown1: {unknown1}");
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. UserId: {Uuid.ToString()} - " +
|
||||
$"Unknown0: {Unknown0} - " +
|
||||
$"PresenceStatus: {Filter.PresenceStatus} - " +
|
||||
$"IsFavoriteOnly: {Filter.IsFavoriteOnly} - " +
|
||||
$"IsSameAppPresenceOnly: {Filter.IsSameAppPresenceOnly} - " +
|
||||
$"IsSameAppPlayedOnly: {Filter.IsSameAppPlayedOnly} - " +
|
||||
$"IsArbitraryAppPlayedOnly: {Filter.IsArbitraryAppPlayedOnly} - " +
|
||||
$"PresenceGroupId: {Filter.PresenceGroupId} - " +
|
||||
$"Unknown1: {Unknown1}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeclareCloseOnlinePlaySession(nn::account::Uid)
|
||||
public long DeclareCloseOnlinePlaySession(ServiceCtx context)
|
||||
public long DeclareCloseOnlinePlaySession(ServiceCtx Context)
|
||||
{
|
||||
UInt128 uuid = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
if (context.Device.System.State.TryGetUser(uuid, out UserProfile profile))
|
||||
if (Context.Device.System.State.TryGetUser(Uuid, out UserProfile Profile))
|
||||
{
|
||||
profile.OnlinePlayState = OpenCloseState.Closed;
|
||||
Profile.OnlinePlayState = OpenCloseState.Closed;
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {uuid.ToString()} - " +
|
||||
$"OnlinePlayState: {profile.OnlinePlayState}");
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.ToString()} - " +
|
||||
$"OnlinePlayState: {Profile.OnlinePlayState}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// UpdateUserPresence(nn::account::Uid, ulong Unknown0) -> buffer<Unknown1, type: 0x19, size: 0xe0>
|
||||
public long UpdateUserPresence(ServiceCtx context)
|
||||
public long UpdateUserPresence(ServiceCtx Context)
|
||||
{
|
||||
UInt128 uuid = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
long unknown0 = context.RequestData.ReadInt64();
|
||||
long Unknown0 = Context.RequestData.ReadInt64();
|
||||
|
||||
long position = context.Request.PtrBuff[0].Position;
|
||||
long size = context.Request.PtrBuff[0].Size;
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
long Size = Context.Request.PtrBuff[0].Size;
|
||||
|
||||
//Todo: Write the buffer content.
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {uuid.ToString()} - " +
|
||||
$"Unknown0: {unknown0}");
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.ToString()} - " +
|
||||
$"Unknown0: {Unknown0}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Friend
|
|||
{
|
||||
class IServiceCreator : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IServiceCreator()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CreateFriendService }
|
||||
};
|
||||
}
|
||||
|
||||
public static long CreateFriendService(ServiceCtx context)
|
||||
public static long CreateFriendService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IFriendService());
|
||||
MakeObject(Context, new IFriendService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
{
|
||||
public struct DirectoryEntry
|
||||
{
|
||||
public string Path { get; }
|
||||
public long Size { get; }
|
||||
public string Path { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
public DirectoryEntryType EntryType { get; set; }
|
||||
|
||||
public DirectoryEntry(string path, DirectoryEntryType directoryEntryType, long size = 0)
|
||||
public DirectoryEntry(string Path, DirectoryEntryType DirectoryEntryType, long Size = 0)
|
||||
{
|
||||
Path = path;
|
||||
EntryType = directoryEntryType;
|
||||
Size = size;
|
||||
this.Path = Path;
|
||||
EntryType = DirectoryEntryType;
|
||||
this.Size = Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
{
|
||||
enum FileSystemType
|
||||
enum FileSystemType : int
|
||||
{
|
||||
Logo = 2,
|
||||
ContentControl = 3,
|
||||
|
|
|
@ -11,88 +11,88 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{
|
||||
private const int DirectoryEntrySize = 0x310;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private List<DirectoryEntry> _directoryEntries;
|
||||
private List<DirectoryEntry> DirectoryEntries;
|
||||
|
||||
private int _currentItemIndex;
|
||||
private int CurrentItemIndex;
|
||||
|
||||
public event EventHandler<EventArgs> Disposed;
|
||||
|
||||
public string DirectoryPath { get; }
|
||||
public string DirectoryPath { get; private set; }
|
||||
|
||||
private IFileSystemProvider _provider;
|
||||
private IFileSystemProvider Provider;
|
||||
|
||||
public IDirectory(string directoryPath, int flags, IFileSystemProvider provider)
|
||||
public IDirectory(string DirectoryPath, int Flags, IFileSystemProvider Provider)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Read },
|
||||
{ 1, GetEntryCount }
|
||||
};
|
||||
|
||||
_provider = provider;
|
||||
DirectoryPath = directoryPath;
|
||||
this.Provider = Provider;
|
||||
this.DirectoryPath = DirectoryPath;
|
||||
|
||||
_directoryEntries = new List<DirectoryEntry>();
|
||||
DirectoryEntries = new List<DirectoryEntry>();
|
||||
|
||||
if ((flags & 1) != 0)
|
||||
if ((Flags & 1) != 0)
|
||||
{
|
||||
_directoryEntries.AddRange(provider.GetDirectories(directoryPath));
|
||||
DirectoryEntries.AddRange(Provider.GetDirectories(DirectoryPath));
|
||||
}
|
||||
|
||||
if ((flags & 2) != 0)
|
||||
if ((Flags & 2) != 0)
|
||||
{
|
||||
_directoryEntries.AddRange(provider.GetFiles(directoryPath));
|
||||
DirectoryEntries.AddRange(Provider.GetFiles(DirectoryPath));
|
||||
}
|
||||
|
||||
_currentItemIndex = 0;
|
||||
CurrentItemIndex = 0;
|
||||
}
|
||||
|
||||
// Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
|
||||
public long Read(ServiceCtx context)
|
||||
public long Read(ServiceCtx Context)
|
||||
{
|
||||
long bufferPosition = context.Request.ReceiveBuff[0].Position;
|
||||
long bufferLen = context.Request.ReceiveBuff[0].Size;
|
||||
long BufferPosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long BufferLen = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
int maxReadCount = (int)(bufferLen / DirectoryEntrySize);
|
||||
int MaxReadCount = (int)(BufferLen / DirectoryEntrySize);
|
||||
|
||||
int count = Math.Min(_directoryEntries.Count - _currentItemIndex, maxReadCount);
|
||||
int Count = Math.Min(DirectoryEntries.Count - CurrentItemIndex, MaxReadCount);
|
||||
|
||||
for (int index = 0; index < count; index++)
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
long position = bufferPosition + index * DirectoryEntrySize;
|
||||
long Position = BufferPosition + Index * DirectoryEntrySize;
|
||||
|
||||
WriteDirectoryEntry(context, position, _directoryEntries[_currentItemIndex++]);
|
||||
WriteDirectoryEntry(Context, Position, DirectoryEntries[CurrentItemIndex++]);
|
||||
}
|
||||
|
||||
context.ResponseData.Write((long)count);
|
||||
Context.ResponseData.Write((long)Count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void WriteDirectoryEntry(ServiceCtx context, long position, DirectoryEntry entry)
|
||||
private void WriteDirectoryEntry(ServiceCtx Context, long Position, DirectoryEntry Entry)
|
||||
{
|
||||
for (int offset = 0; offset < 0x300; offset += 8)
|
||||
for (int Offset = 0; Offset < 0x300; Offset += 8)
|
||||
{
|
||||
context.Memory.WriteInt64(position + offset, 0);
|
||||
Context.Memory.WriteInt64(Position + Offset, 0);
|
||||
}
|
||||
|
||||
byte[] nameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(entry.Path));
|
||||
byte[] NameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(Entry.Path));
|
||||
|
||||
context.Memory.WriteBytes(position, nameBuffer);
|
||||
Context.Memory.WriteBytes(Position, NameBuffer);
|
||||
|
||||
context.Memory.WriteInt32(position + 0x300, 0); //Padding?
|
||||
context.Memory.WriteInt32(position + 0x304, (byte)entry.EntryType);
|
||||
context.Memory.WriteInt64(position + 0x308, entry.Size);
|
||||
Context.Memory.WriteInt32(Position + 0x300, 0); //Padding?
|
||||
Context.Memory.WriteInt32(Position + 0x304, (byte)Entry.EntryType);
|
||||
Context.Memory.WriteInt64(Position + 0x308, Entry.Size);
|
||||
}
|
||||
|
||||
// GetEntryCount() -> u64
|
||||
public long GetEntryCount(ServiceCtx context)
|
||||
public long GetEntryCount(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((long)_directoryEntries.Count);
|
||||
Context.ResponseData.Write((long)DirectoryEntries.Count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,19 +7,19 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{
|
||||
class IFile : IpcService, IDisposable
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private Stream _baseStream;
|
||||
private Stream BaseStream;
|
||||
|
||||
public event EventHandler<EventArgs> Disposed;
|
||||
|
||||
public string HostPath { get; }
|
||||
public string HostPath { get; private set; }
|
||||
|
||||
public IFile(Stream baseStream, string hostPath)
|
||||
public IFile(Stream BaseStream, string HostPath)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Read },
|
||||
{ 1, Write },
|
||||
|
@ -28,71 +28,71 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{ 4, GetSize }
|
||||
};
|
||||
|
||||
_baseStream = baseStream;
|
||||
HostPath = hostPath;
|
||||
this.BaseStream = BaseStream;
|
||||
this.HostPath = HostPath;
|
||||
}
|
||||
|
||||
// Read(u32, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
|
||||
public long Read(ServiceCtx context)
|
||||
public long Read(ServiceCtx Context)
|
||||
{
|
||||
long position = context.Request.ReceiveBuff[0].Position;
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
long zero = context.RequestData.ReadInt64();
|
||||
long offset = context.RequestData.ReadInt64();
|
||||
long size = context.RequestData.ReadInt64();
|
||||
long Zero = Context.RequestData.ReadInt64();
|
||||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
byte[] Data = new byte[Size];
|
||||
|
||||
_baseStream.Seek(offset, SeekOrigin.Begin);
|
||||
BaseStream.Seek(Offset, SeekOrigin.Begin);
|
||||
|
||||
int readSize = _baseStream.Read(data, 0, (int)size);
|
||||
int ReadSize = BaseStream.Read(Data, 0, (int)Size);
|
||||
|
||||
context.Memory.WriteBytes(position, data);
|
||||
Context.Memory.WriteBytes(Position, Data);
|
||||
|
||||
context.ResponseData.Write((long)readSize);
|
||||
Context.ResponseData.Write((long)ReadSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write(u32, u64 offset, u64 size, buffer<u8, 0x45, 0>)
|
||||
public long Write(ServiceCtx context)
|
||||
public long Write(ServiceCtx Context)
|
||||
{
|
||||
long position = context.Request.SendBuff[0].Position;
|
||||
long Position = Context.Request.SendBuff[0].Position;
|
||||
|
||||
long zero = context.RequestData.ReadInt64();
|
||||
long offset = context.RequestData.ReadInt64();
|
||||
long size = context.RequestData.ReadInt64();
|
||||
long Zero = Context.RequestData.ReadInt64();
|
||||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
byte[] data = context.Memory.ReadBytes(position, size);
|
||||
byte[] Data = Context.Memory.ReadBytes(Position, Size);
|
||||
|
||||
_baseStream.Seek(offset, SeekOrigin.Begin);
|
||||
_baseStream.Write(data, 0, (int)size);
|
||||
BaseStream.Seek(Offset, SeekOrigin.Begin);
|
||||
BaseStream.Write(Data, 0, (int)Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Flush()
|
||||
public long Flush(ServiceCtx context)
|
||||
public long Flush(ServiceCtx Context)
|
||||
{
|
||||
_baseStream.Flush();
|
||||
BaseStream.Flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SetSize(u64 size)
|
||||
public long SetSize(ServiceCtx context)
|
||||
public long SetSize(ServiceCtx Context)
|
||||
{
|
||||
long size = context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
_baseStream.SetLength(size);
|
||||
BaseStream.SetLength(Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetSize() -> u64 fileSize
|
||||
public long GetSize(ServiceCtx context)
|
||||
public long GetSize(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(_baseStream.Length);
|
||||
Context.ResponseData.Write(BaseStream.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,9 +104,9 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _baseStream != null)
|
||||
if (disposing && BaseStream != null)
|
||||
{
|
||||
_baseStream.Dispose();
|
||||
BaseStream.Dispose();
|
||||
|
||||
Disposed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
|
|
@ -11,19 +11,19 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{
|
||||
class IFileSystem : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private HashSet<string> _openPaths;
|
||||
private HashSet<string> OpenPaths;
|
||||
|
||||
private string _path;
|
||||
private string Path;
|
||||
|
||||
private IFileSystemProvider _provider;
|
||||
private IFileSystemProvider Provider;
|
||||
|
||||
public IFileSystem(string path, IFileSystemProvider provider)
|
||||
public IFileSystem(string Path, IFileSystemProvider Provider)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CreateFile },
|
||||
{ 1, DeleteFile },
|
||||
|
@ -38,196 +38,196 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{ 10, Commit },
|
||||
{ 11, GetFreeSpaceSize },
|
||||
{ 12, GetTotalSpaceSize },
|
||||
{ 13, CleanDirectoryRecursively }
|
||||
{ 13, CleanDirectoryRecursively },
|
||||
//{ 14, GetFileTimeStampRaw }
|
||||
};
|
||||
|
||||
_openPaths = new HashSet<string>();
|
||||
OpenPaths = new HashSet<string>();
|
||||
|
||||
_path = path;
|
||||
_provider = provider;
|
||||
this.Path = Path;
|
||||
this.Provider = Provider;
|
||||
}
|
||||
|
||||
// CreateFile(u32 mode, u64 size, buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
public long CreateFile(ServiceCtx context)
|
||||
public long CreateFile(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
long mode = context.RequestData.ReadInt64();
|
||||
int size = context.RequestData.ReadInt32();
|
||||
long Mode = Context.RequestData.ReadInt64();
|
||||
int Size = Context.RequestData.ReadInt32();
|
||||
|
||||
string fileName = _provider.GetFullPath(name);
|
||||
string FileName = Provider.GetFullPath(Name);
|
||||
|
||||
if (fileName == null)
|
||||
if (FileName == null)
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (_provider.FileExists(fileName))
|
||||
if (Provider.FileExists(FileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(fileName))
|
||||
if (IsPathAlreadyInUse(FileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
return _provider.CreateFile(fileName, size);
|
||||
return Provider.CreateFile(FileName, Size);
|
||||
}
|
||||
|
||||
// DeleteFile(buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
public long DeleteFile(ServiceCtx context)
|
||||
public long DeleteFile(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string fileName = _provider.GetFullPath(name);
|
||||
string FileName = Provider.GetFullPath(Name);
|
||||
|
||||
if (!_provider.FileExists(fileName))
|
||||
if (!Provider.FileExists(FileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(fileName))
|
||||
if (IsPathAlreadyInUse(FileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
return _provider.DeleteFile(fileName);
|
||||
return Provider.DeleteFile(FileName);
|
||||
}
|
||||
|
||||
// CreateDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
public long CreateDirectory(ServiceCtx context)
|
||||
public long CreateDirectory(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string dirName = _provider.GetFullPath(name);
|
||||
string DirName = Provider.GetFullPath(Name);
|
||||
|
||||
if (dirName == null)
|
||||
if (DirName == null)
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (_provider.DirectoryExists(dirName))
|
||||
if (Provider.DirectoryExists(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(dirName))
|
||||
if (IsPathAlreadyInUse(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
_provider.CreateDirectory(dirName);
|
||||
Provider.CreateDirectory(DirName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeleteDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
public long DeleteDirectory(ServiceCtx context)
|
||||
public long DeleteDirectory(ServiceCtx Context)
|
||||
{
|
||||
return DeleteDirectory(context, false);
|
||||
return DeleteDirectory(Context, false);
|
||||
}
|
||||
|
||||
// DeleteDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
public long DeleteDirectoryRecursively(ServiceCtx context)
|
||||
public long DeleteDirectoryRecursively(ServiceCtx Context)
|
||||
{
|
||||
return DeleteDirectory(context, true);
|
||||
return DeleteDirectory(Context, true);
|
||||
}
|
||||
|
||||
private long DeleteDirectory(ServiceCtx context, bool recursive)
|
||||
private long DeleteDirectory(ServiceCtx Context, bool Recursive)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string dirName = _provider.GetFullPath(name);
|
||||
string DirName = Provider.GetFullPath(Name);
|
||||
|
||||
if (!Directory.Exists(dirName))
|
||||
if (!Directory.Exists(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(dirName))
|
||||
if (IsPathAlreadyInUse(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
_provider.DeleteDirectory(dirName, recursive);
|
||||
Provider.DeleteDirectory(DirName, Recursive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RenameFile(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
|
||||
public long RenameFile(ServiceCtx context)
|
||||
public long RenameFile(ServiceCtx Context)
|
||||
{
|
||||
string oldName = ReadUtf8String(context, 0);
|
||||
string newName = ReadUtf8String(context, 1);
|
||||
string OldName = ReadUtf8String(Context, 0);
|
||||
string NewName = ReadUtf8String(Context, 1);
|
||||
|
||||
string oldFileName = _provider.GetFullPath(oldName);
|
||||
string newFileName = _provider.GetFullPath(newName);
|
||||
string OldFileName = Provider.GetFullPath(OldName);
|
||||
string NewFileName = Provider.GetFullPath(NewName);
|
||||
|
||||
if (_provider.FileExists(oldFileName))
|
||||
if (Provider.FileExists(OldFileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (_provider.FileExists(newFileName))
|
||||
if (Provider.FileExists(NewFileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(oldFileName))
|
||||
if (IsPathAlreadyInUse(OldFileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
return _provider.RenameFile(oldFileName, newFileName);
|
||||
return Provider.RenameFile(OldFileName, NewFileName);
|
||||
}
|
||||
|
||||
// RenameDirectory(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
|
||||
public long RenameDirectory(ServiceCtx context)
|
||||
public long RenameDirectory(ServiceCtx Context)
|
||||
{
|
||||
string oldName = ReadUtf8String(context, 0);
|
||||
string newName = ReadUtf8String(context, 1);
|
||||
string OldName = ReadUtf8String(Context, 0);
|
||||
string NewName = ReadUtf8String(Context, 1);
|
||||
|
||||
string oldDirName = _provider.GetFullPath(oldName);
|
||||
string newDirName = _provider.GetFullPath(newName);
|
||||
string OldDirName = Provider.GetFullPath(OldName);
|
||||
string NewDirName = Provider.GetFullPath(NewName);
|
||||
|
||||
if (!_provider.DirectoryExists(oldDirName))
|
||||
if (!Provider.DirectoryExists(OldDirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (!_provider.DirectoryExists(newDirName))
|
||||
if (!Provider.DirectoryExists(NewDirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(oldDirName))
|
||||
if (IsPathAlreadyInUse(OldDirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
return _provider.RenameDirectory(oldDirName, newDirName);
|
||||
return Provider.RenameDirectory(OldDirName, NewDirName);
|
||||
}
|
||||
|
||||
// GetEntryType(buffer<bytes<0x301>, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType
|
||||
public long GetEntryType(ServiceCtx context)
|
||||
public long GetEntryType(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string fileName = _provider.GetFullPath(name);
|
||||
string FileName = Provider.GetFullPath(Name);
|
||||
|
||||
if (_provider.FileExists(fileName))
|
||||
if (Provider.FileExists(FileName))
|
||||
{
|
||||
context.ResponseData.Write(1);
|
||||
Context.ResponseData.Write(1);
|
||||
}
|
||||
else if (_provider.DirectoryExists(fileName))
|
||||
else if (Provider.DirectoryExists(FileName))
|
||||
{
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
@ -236,167 +236,167 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
}
|
||||
|
||||
// OpenFile(u32 mode, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IFile> file
|
||||
public long OpenFile(ServiceCtx context)
|
||||
public long OpenFile(ServiceCtx Context)
|
||||
{
|
||||
int filterFlags = context.RequestData.ReadInt32();
|
||||
int FilterFlags = Context.RequestData.ReadInt32();
|
||||
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string fileName = _provider.GetFullPath(name);
|
||||
string FileName = Provider.GetFullPath(Name);
|
||||
|
||||
if (!_provider.FileExists(fileName))
|
||||
if (!Provider.FileExists(FileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(fileName))
|
||||
if (IsPathAlreadyInUse(FileName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
|
||||
long error = _provider.OpenFile(fileName, out IFile fileInterface);
|
||||
long Error = Provider.OpenFile(FileName, out IFile FileInterface);
|
||||
|
||||
if (error == 0)
|
||||
if (Error == 0)
|
||||
{
|
||||
fileInterface.Disposed += RemoveFileInUse;
|
||||
FileInterface.Disposed += RemoveFileInUse;
|
||||
|
||||
lock (_openPaths)
|
||||
lock (OpenPaths)
|
||||
{
|
||||
_openPaths.Add(fileName);
|
||||
OpenPaths.Add(FileName);
|
||||
}
|
||||
|
||||
MakeObject(context, fileInterface);
|
||||
MakeObject(Context, FileInterface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// OpenDirectory(u32 filter_flags, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IDirectory> directory
|
||||
public long OpenDirectory(ServiceCtx context)
|
||||
public long OpenDirectory(ServiceCtx Context)
|
||||
{
|
||||
int filterFlags = context.RequestData.ReadInt32();
|
||||
int FilterFlags = Context.RequestData.ReadInt32();
|
||||
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string dirName = _provider.GetFullPath(name);
|
||||
string DirName = Provider.GetFullPath(Name);
|
||||
|
||||
if (!_provider.DirectoryExists(dirName))
|
||||
if (!Provider.DirectoryExists(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(dirName))
|
||||
if (IsPathAlreadyInUse(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
long error = _provider.OpenDirectory(dirName, filterFlags, out IDirectory dirInterface);
|
||||
long Error = Provider.OpenDirectory(DirName, FilterFlags, out IDirectory DirInterface);
|
||||
|
||||
if (error == 0)
|
||||
if (Error == 0)
|
||||
{
|
||||
dirInterface.Disposed += RemoveDirectoryInUse;
|
||||
DirInterface.Disposed += RemoveDirectoryInUse;
|
||||
|
||||
lock (_openPaths)
|
||||
lock (OpenPaths)
|
||||
{
|
||||
_openPaths.Add(dirName);
|
||||
OpenPaths.Add(DirName);
|
||||
}
|
||||
|
||||
MakeObject(context, dirInterface);
|
||||
MakeObject(Context, DirInterface);
|
||||
}
|
||||
|
||||
return error;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Commit()
|
||||
public long Commit(ServiceCtx context)
|
||||
public long Commit(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetFreeSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalFreeSpace
|
||||
public long GetFreeSpaceSize(ServiceCtx context)
|
||||
public long GetFreeSpaceSize(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
context.ResponseData.Write(_provider.GetFreeSpace(context));
|
||||
Context.ResponseData.Write(Provider.GetFreeSpace(Context));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetTotalSpaceSize(buffer<bytes<0x301>, 0x19, 0x301> path) -> u64 totalSize
|
||||
public long GetTotalSpaceSize(ServiceCtx context)
|
||||
public long GetTotalSpaceSize(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
context.ResponseData.Write(_provider.GetFreeSpace(context));
|
||||
Context.ResponseData.Write(Provider.GetFreeSpace(Context));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CleanDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
public long CleanDirectoryRecursively(ServiceCtx context)
|
||||
public long CleanDirectoryRecursively(ServiceCtx Context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
string Name = ReadUtf8String(Context);
|
||||
|
||||
string dirName = _provider.GetFullPath(name);
|
||||
string DirName = Provider.GetFullPath(Name);
|
||||
|
||||
if (!_provider.DirectoryExists(dirName))
|
||||
if (!Provider.DirectoryExists(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(dirName))
|
||||
if (IsPathAlreadyInUse(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
foreach (DirectoryEntry entry in _provider.GetEntries(dirName))
|
||||
foreach (DirectoryEntry Entry in Provider.GetEntries(DirName))
|
||||
{
|
||||
if (_provider.DirectoryExists(entry.Path))
|
||||
if (Provider.DirectoryExists(Entry.Path))
|
||||
{
|
||||
_provider.DeleteDirectory(entry.Path, true);
|
||||
Provider.DeleteDirectory(Entry.Path, true);
|
||||
}
|
||||
else if (_provider.FileExists(entry.Path))
|
||||
else if (Provider.FileExists(Entry.Path))
|
||||
{
|
||||
_provider.DeleteFile(entry.Path);
|
||||
Provider.DeleteFile(Entry.Path);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private bool IsPathAlreadyInUse(string path)
|
||||
private bool IsPathAlreadyInUse(string Path)
|
||||
{
|
||||
lock (_openPaths)
|
||||
lock (OpenPaths)
|
||||
{
|
||||
return _openPaths.Contains(path);
|
||||
return OpenPaths.Contains(Path);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveFileInUse(object sender, EventArgs e)
|
||||
{
|
||||
IFile fileInterface = (IFile)sender;
|
||||
IFile FileInterface = (IFile)sender;
|
||||
|
||||
lock (_openPaths)
|
||||
lock (OpenPaths)
|
||||
{
|
||||
fileInterface.Disposed -= RemoveFileInUse;
|
||||
FileInterface.Disposed -= RemoveFileInUse;
|
||||
|
||||
_openPaths.Remove(fileInterface.HostPath);
|
||||
OpenPaths.Remove(FileInterface.HostPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveDirectoryInUse(object sender, EventArgs e)
|
||||
{
|
||||
IDirectory dirInterface = (IDirectory)sender;
|
||||
IDirectory DirInterface = (IDirectory)sender;
|
||||
|
||||
lock (_openPaths)
|
||||
lock (OpenPaths)
|
||||
{
|
||||
dirInterface.Disposed -= RemoveDirectoryInUse;
|
||||
DirInterface.Disposed -= RemoveDirectoryInUse;
|
||||
|
||||
_openPaths.Remove(dirInterface.DirectoryPath);
|
||||
OpenPaths.Remove(DirInterface.DirectoryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{
|
||||
class IFileSystemProxy : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IFileSystemProxy()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, Initialize },
|
||||
{ 8, OpenFileSystemWithId },
|
||||
|
@ -36,246 +36,246 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
}
|
||||
|
||||
// Initialize(u64, pid)
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
// -> object<nn::fssrv::sf::IFileSystem> contentFs
|
||||
public long OpenFileSystemWithId(ServiceCtx context)
|
||||
public long OpenFileSystemWithId(ServiceCtx Context)
|
||||
{
|
||||
FileSystemType fileSystemType = (FileSystemType)context.RequestData.ReadInt32();
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
string switchPath = ReadUtf8String(context);
|
||||
string fullPath = context.Device.FileSystem.SwitchPathToSystemPath(switchPath);
|
||||
FileSystemType FileSystemType = (FileSystemType)Context.RequestData.ReadInt32();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
string SwitchPath = ReadUtf8String(Context);
|
||||
string FullPath = Context.Device.FileSystem.SwitchPathToSystemPath(SwitchPath);
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
if (!File.Exists(FullPath))
|
||||
{
|
||||
if (fullPath.Contains("."))
|
||||
if (FullPath.Contains("."))
|
||||
{
|
||||
return OpenFileSystemFromInternalFile(context, fullPath);
|
||||
return OpenFileSystemFromInternalFile(Context, FullPath);
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read);
|
||||
string extension = Path.GetExtension(fullPath);
|
||||
FileStream FileStream = new FileStream(FullPath, FileMode.Open, FileAccess.Read);
|
||||
string Extension = Path.GetExtension(FullPath);
|
||||
|
||||
if (extension == ".nca")
|
||||
if (Extension == ".nca")
|
||||
{
|
||||
return OpenNcaFs(context, fullPath, fileStream);
|
||||
return OpenNcaFs(Context, FullPath, FileStream);
|
||||
}
|
||||
else if (extension == ".nsp")
|
||||
else if (Extension == ".nsp")
|
||||
{
|
||||
return OpenNsp(context, fullPath);
|
||||
return OpenNsp(Context, FullPath);
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.InvalidInput);
|
||||
}
|
||||
|
||||
// OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer<bytes<0x301>, 0x19, 0x301>) -> object<nn::fssrv::sf::IFileSystem> Bis
|
||||
public long OpenBisFileSystem(ServiceCtx context)
|
||||
public long OpenBisFileSystem(ServiceCtx Context)
|
||||
{
|
||||
int bisPartitionId = context.RequestData.ReadInt32();
|
||||
string partitionString = ReadUtf8String(context);
|
||||
string bisPartitonPath = string.Empty;
|
||||
int BisPartitionId = Context.RequestData.ReadInt32();
|
||||
string PartitionString = ReadUtf8String(Context);
|
||||
string BisPartitonPath = string.Empty;
|
||||
|
||||
switch (bisPartitionId)
|
||||
switch (BisPartitionId)
|
||||
{
|
||||
case 29:
|
||||
bisPartitonPath = SafeNandPath;
|
||||
BisPartitonPath = SafeNandPath;
|
||||
break;
|
||||
case 30:
|
||||
case 31:
|
||||
bisPartitonPath = SystemNandPath;
|
||||
BisPartitonPath = SystemNandPath;
|
||||
break;
|
||||
case 32:
|
||||
bisPartitonPath = UserNandPath;
|
||||
BisPartitonPath = UserNandPath;
|
||||
break;
|
||||
default:
|
||||
return MakeError(ErrorModule.Fs, FsErr.InvalidInput);
|
||||
}
|
||||
|
||||
string fullPath = context.Device.FileSystem.GetFullPartitionPath(bisPartitonPath);
|
||||
string FullPath = Context.Device.FileSystem.GetFullPartitionPath(BisPartitonPath);
|
||||
|
||||
FileSystemProvider fileSystemProvider = new FileSystemProvider(fullPath, context.Device.FileSystem.GetBasePath());
|
||||
FileSystemProvider FileSystemProvider = new FileSystemProvider(FullPath, Context.Device.FileSystem.GetBasePath());
|
||||
|
||||
MakeObject(context, new IFileSystem(fullPath, fileSystemProvider));
|
||||
MakeObject(Context, new IFileSystem(FullPath, FileSystemProvider));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OpenSdCardFileSystem() -> object<nn::fssrv::sf::IFileSystem>
|
||||
public long OpenSdCardFileSystem(ServiceCtx context)
|
||||
public long OpenSdCardFileSystem(ServiceCtx Context)
|
||||
{
|
||||
string sdCardPath = context.Device.FileSystem.GetSdCardPath();
|
||||
string SdCardPath = Context.Device.FileSystem.GetSdCardPath();
|
||||
|
||||
FileSystemProvider fileSystemProvider = new FileSystemProvider(sdCardPath, context.Device.FileSystem.GetBasePath());
|
||||
FileSystemProvider FileSystemProvider = new FileSystemProvider(SdCardPath, Context.Device.FileSystem.GetBasePath());
|
||||
|
||||
MakeObject(context, new IFileSystem(sdCardPath, fileSystemProvider));
|
||||
MakeObject(Context, new IFileSystem(SdCardPath, FileSystemProvider));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OpenSaveDataFileSystem(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> saveDataFs
|
||||
public long OpenSaveDataFileSystem(ServiceCtx context)
|
||||
public long OpenSaveDataFileSystem(ServiceCtx Context)
|
||||
{
|
||||
LoadSaveDataFileSystem(context);
|
||||
LoadSaveDataFileSystem(Context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OpenSaveDataFileSystemBySystemSaveDataId(u8 save_data_space_id, nn::fssrv::sf::SaveStruct saveStruct) -> object<nn::fssrv::sf::IFileSystem> systemSaveDataFs
|
||||
public long OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx context)
|
||||
public long OpenSaveDataFileSystemBySystemSaveDataId(ServiceCtx Context)
|
||||
{
|
||||
LoadSaveDataFileSystem(context);
|
||||
LoadSaveDataFileSystem(Context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
|
||||
public long OpenDataStorageByCurrentProcess(ServiceCtx context)
|
||||
public long OpenDataStorageByCurrentProcess(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IStorage(context.Device.FileSystem.RomFs));
|
||||
MakeObject(Context, new IStorage(Context.Device.FileSystem.RomFs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OpenDataStorageByDataId(u8 storageId, nn::ApplicationId tid) -> object<nn::fssrv::sf::IStorage> dataStorage
|
||||
public long OpenDataStorageByDataId(ServiceCtx context)
|
||||
public long OpenDataStorageByDataId(ServiceCtx Context)
|
||||
{
|
||||
StorageId storageId = (StorageId)context.RequestData.ReadByte();
|
||||
byte[] padding = context.RequestData.ReadBytes(7);
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
StorageId StorageId = (StorageId)Context.RequestData.ReadByte();
|
||||
byte[] Padding = Context.RequestData.ReadBytes(7);
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
StorageId installedStorage =
|
||||
context.Device.System.ContentManager.GetInstalledStorage(titleId, ContentType.Data, storageId);
|
||||
StorageId InstalledStorage =
|
||||
Context.Device.System.ContentManager.GetInstalledStorage(TitleId, ContentType.Data, StorageId);
|
||||
|
||||
if (installedStorage == StorageId.None)
|
||||
if (InstalledStorage == StorageId.None)
|
||||
{
|
||||
installedStorage =
|
||||
context.Device.System.ContentManager.GetInstalledStorage(titleId, ContentType.AocData, storageId);
|
||||
InstalledStorage =
|
||||
Context.Device.System.ContentManager.GetInstalledStorage(TitleId, ContentType.AocData, StorageId);
|
||||
}
|
||||
|
||||
if (installedStorage != StorageId.None)
|
||||
if (InstalledStorage != StorageId.None)
|
||||
{
|
||||
string contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, ContentType.AocData);
|
||||
string ContentPath = Context.Device.System.ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.AocData);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(contentPath))
|
||||
if (string.IsNullOrWhiteSpace(ContentPath))
|
||||
{
|
||||
contentPath = context.Device.System.ContentManager.GetInstalledContentPath(titleId, storageId, ContentType.AocData);
|
||||
ContentPath = Context.Device.System.ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.AocData);
|
||||
}
|
||||
|
||||
string installPath = context.Device.FileSystem.SwitchPathToSystemPath(contentPath);
|
||||
string InstallPath = Context.Device.FileSystem.SwitchPathToSystemPath(ContentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(installPath))
|
||||
if (!string.IsNullOrWhiteSpace(InstallPath))
|
||||
{
|
||||
string ncaPath = installPath;
|
||||
string NcaPath = InstallPath;
|
||||
|
||||
if (File.Exists(ncaPath))
|
||||
if (File.Exists(NcaPath))
|
||||
{
|
||||
FileStream ncaStream = new FileStream(ncaPath, FileMode.Open, FileAccess.Read);
|
||||
Nca nca = new Nca(context.Device.System.KeySet, ncaStream, false);
|
||||
NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel);
|
||||
FileStream NcaStream = new FileStream(NcaPath, FileMode.Open, FileAccess.Read);
|
||||
Nca Nca = new Nca(Context.Device.System.KeySet, NcaStream, false);
|
||||
NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
|
||||
|
||||
MakeObject(context, new IStorage(romfsStream));
|
||||
MakeObject(Context, new IStorage(RomfsStream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`.");
|
||||
throw new FileNotFoundException($"No Nca found in Path `{NcaPath}`.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}.");
|
||||
throw new DirectoryNotFoundException($"Path for title id {TitleId:x16} on Storage {StorageId} was not found in Path {InstallPath}.");
|
||||
}
|
||||
}
|
||||
|
||||
throw new FileNotFoundException($"System archive with titleid {titleId:x16} was not found on Storage {storageId}. Found in {installedStorage}.");
|
||||
throw new FileNotFoundException($"System archive with titleid {TitleId:x16} was not found on Storage {StorageId}. Found in {InstalledStorage}.");
|
||||
}
|
||||
|
||||
// OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
|
||||
public long OpenPatchDataStorageByCurrentProcess(ServiceCtx context)
|
||||
public long OpenPatchDataStorageByCurrentProcess(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IStorage(context.Device.FileSystem.RomFs));
|
||||
MakeObject(Context, new IStorage(Context.Device.FileSystem.RomFs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetGlobalAccessLogMode() -> u32 logMode
|
||||
public long GetGlobalAccessLogMode(ServiceCtx context)
|
||||
public long GetGlobalAccessLogMode(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void LoadSaveDataFileSystem(ServiceCtx context)
|
||||
public void LoadSaveDataFileSystem(ServiceCtx Context)
|
||||
{
|
||||
SaveSpaceId saveSpaceId = (SaveSpaceId)context.RequestData.ReadInt64();
|
||||
SaveSpaceId SaveSpaceId = (SaveSpaceId)Context.RequestData.ReadInt64();
|
||||
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
UInt128 userId = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
UInt128 UserId = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
long saveId = context.RequestData.ReadInt64();
|
||||
SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte();
|
||||
SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, userId, saveSpaceId);
|
||||
string savePath = context.Device.FileSystem.GetGameSavePath(saveInfo, context);
|
||||
FileSystemProvider fileSystemProvider = new FileSystemProvider(savePath, context.Device.FileSystem.GetBasePath());
|
||||
long SaveId = Context.RequestData.ReadInt64();
|
||||
SaveDataType SaveDataType = (SaveDataType)Context.RequestData.ReadByte();
|
||||
SaveInfo SaveInfo = new SaveInfo(TitleId, SaveId, SaveDataType, UserId, SaveSpaceId);
|
||||
string SavePath = Context.Device.FileSystem.GetGameSavePath(SaveInfo, Context);
|
||||
FileSystemProvider FileSystemProvider = new FileSystemProvider(SavePath, Context.Device.FileSystem.GetBasePath());
|
||||
|
||||
MakeObject(context, new IFileSystem(savePath, fileSystemProvider));
|
||||
MakeObject(Context, new IFileSystem(SavePath, FileSystemProvider));
|
||||
}
|
||||
|
||||
private long OpenNsp(ServiceCtx context, string pfsPath)
|
||||
private long OpenNsp(ServiceCtx Context, string PfsPath)
|
||||
{
|
||||
FileStream pfsFile = new FileStream(pfsPath, FileMode.Open, FileAccess.Read);
|
||||
Pfs nsp = new Pfs(pfsFile);
|
||||
PfsFileEntry ticketFile = nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
FileStream PfsFile = new FileStream(PfsPath, FileMode.Open, FileAccess.Read);
|
||||
Pfs Nsp = new Pfs(PfsFile);
|
||||
PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
|
||||
if (ticketFile != null)
|
||||
if (TicketFile != null)
|
||||
{
|
||||
Ticket ticket = new Ticket(nsp.OpenFile(ticketFile));
|
||||
Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile));
|
||||
|
||||
context.Device.System.KeySet.TitleKeys[ticket.RightsId] =
|
||||
ticket.GetTitleKey(context.Device.System.KeySet);
|
||||
Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] =
|
||||
Ticket.GetTitleKey(Context.Device.System.KeySet);
|
||||
}
|
||||
|
||||
IFileSystem nspFileSystem = new IFileSystem(pfsPath, new PFsProvider(nsp));
|
||||
IFileSystem NspFileSystem = new IFileSystem(PfsPath, new PFsProvider(Nsp));
|
||||
|
||||
MakeObject(context, nspFileSystem);
|
||||
MakeObject(Context, NspFileSystem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long OpenNcaFs(ServiceCtx context,string ncaPath, Stream ncaStream)
|
||||
private long OpenNcaFs(ServiceCtx Context,string NcaPath, Stream NcaStream)
|
||||
{
|
||||
Nca nca = new Nca(context.Device.System.KeySet, ncaStream, false);
|
||||
Nca Nca = new Nca(Context.Device.System.KeySet, NcaStream, false);
|
||||
|
||||
NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
NcaSection pfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0);
|
||||
NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
NcaSection PfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0);
|
||||
|
||||
if (romfsSection != null)
|
||||
if (RomfsSection != null)
|
||||
{
|
||||
Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel);
|
||||
IFileSystem ncaFileSystem = new IFileSystem(ncaPath, new RomFsProvider(romfsStream));
|
||||
Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
|
||||
IFileSystem NcaFileSystem = new IFileSystem(NcaPath, new RomFsProvider(RomfsStream));
|
||||
|
||||
MakeObject(context, ncaFileSystem);
|
||||
MakeObject(Context, NcaFileSystem);
|
||||
}
|
||||
else if(pfsSection !=null)
|
||||
else if(PfsSection !=null)
|
||||
{
|
||||
Stream pfsStream = nca.OpenSection(pfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel);
|
||||
Pfs pfs = new Pfs(pfsStream);
|
||||
IFileSystem ncaFileSystem = new IFileSystem(ncaPath, new PFsProvider(pfs));
|
||||
Stream PfsStream = Nca.OpenSection(PfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
|
||||
Pfs Pfs = new Pfs(PfsStream);
|
||||
IFileSystem NcaFileSystem = new IFileSystem(NcaPath, new PFsProvider(Pfs));
|
||||
|
||||
MakeObject(context, ncaFileSystem);
|
||||
MakeObject(Context, NcaFileSystem);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -285,38 +285,38 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
return 0;
|
||||
}
|
||||
|
||||
private long OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath)
|
||||
private long OpenFileSystemFromInternalFile(ServiceCtx Context, string FullPath)
|
||||
{
|
||||
DirectoryInfo archivePath = new DirectoryInfo(fullPath).Parent;
|
||||
DirectoryInfo ArchivePath = new DirectoryInfo(FullPath).Parent;
|
||||
|
||||
while (string.IsNullOrWhiteSpace(archivePath.Extension))
|
||||
while (string.IsNullOrWhiteSpace(ArchivePath.Extension))
|
||||
{
|
||||
archivePath = archivePath.Parent;
|
||||
ArchivePath = ArchivePath.Parent;
|
||||
}
|
||||
|
||||
if (archivePath.Extension == ".nsp" && File.Exists(archivePath.FullName))
|
||||
if (ArchivePath.Extension == ".nsp" && File.Exists(ArchivePath.FullName))
|
||||
{
|
||||
FileStream pfsFile = new FileStream(
|
||||
archivePath.FullName.TrimEnd(Path.DirectorySeparatorChar),
|
||||
FileStream PfsFile = new FileStream(
|
||||
ArchivePath.FullName.TrimEnd(Path.DirectorySeparatorChar),
|
||||
FileMode.Open,
|
||||
FileAccess.Read);
|
||||
|
||||
Pfs nsp = new Pfs(pfsFile);
|
||||
PfsFileEntry ticketFile = nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
Pfs Nsp = new Pfs(PfsFile);
|
||||
PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
|
||||
if (ticketFile != null)
|
||||
if (TicketFile != null)
|
||||
{
|
||||
Ticket ticket = new Ticket(nsp.OpenFile(ticketFile));
|
||||
Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile));
|
||||
|
||||
context.Device.System.KeySet.TitleKeys[ticket.RightsId] =
|
||||
ticket.GetTitleKey(context.Device.System.KeySet);
|
||||
Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] =
|
||||
Ticket.GetTitleKey(Context.Device.System.KeySet);
|
||||
}
|
||||
|
||||
string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\');
|
||||
string Filename = FullPath.Replace(ArchivePath.FullName, string.Empty).TrimStart('\\');
|
||||
|
||||
if (nsp.FileExists(filename))
|
||||
if (Nsp.FileExists(Filename))
|
||||
{
|
||||
return OpenNcaFs(context, fullPath, nsp.OpenFile(filename));
|
||||
return OpenNcaFs(Context, FullPath, Nsp.OpenFile(Filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,47 +6,47 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{
|
||||
class IStorage : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private Stream _baseStream;
|
||||
private Stream BaseStream;
|
||||
|
||||
public IStorage(Stream baseStream)
|
||||
public IStorage(Stream BaseStream)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Read }
|
||||
};
|
||||
|
||||
_baseStream = baseStream;
|
||||
this.BaseStream = BaseStream;
|
||||
}
|
||||
|
||||
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
|
||||
public long Read(ServiceCtx context)
|
||||
public long Read(ServiceCtx Context)
|
||||
{
|
||||
long offset = context.RequestData.ReadInt64();
|
||||
long size = context.RequestData.ReadInt64();
|
||||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
if (context.Request.ReceiveBuff.Count > 0)
|
||||
if (Context.Request.ReceiveBuff.Count > 0)
|
||||
{
|
||||
IpcBuffDesc buffDesc = context.Request.ReceiveBuff[0];
|
||||
IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0];
|
||||
|
||||
//Use smaller length to avoid overflows.
|
||||
if (size > buffDesc.Size)
|
||||
if (Size > BuffDesc.Size)
|
||||
{
|
||||
size = buffDesc.Size;
|
||||
Size = BuffDesc.Size;
|
||||
}
|
||||
|
||||
byte[] data = new byte[size];
|
||||
byte[] Data = new byte[Size];
|
||||
|
||||
lock (_baseStream)
|
||||
lock (BaseStream)
|
||||
{
|
||||
_baseStream.Seek(offset, SeekOrigin.Begin);
|
||||
_baseStream.Read(data, 0, data.Length);
|
||||
BaseStream.Seek(Offset, SeekOrigin.Begin);
|
||||
BaseStream.Read(Data, 0, Data.Length);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(buffDesc.Position, data);
|
||||
Context.Memory.WriteBytes(BuffDesc.Position, Data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -5,26 +5,26 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
public enum HidNpadJoyAssignmentMode
|
||||
{
|
||||
Dual,
|
||||
Single
|
||||
Single,
|
||||
}
|
||||
|
||||
public enum HidNpadHandheldActivationMode
|
||||
{
|
||||
Dual,
|
||||
Single,
|
||||
None
|
||||
None,
|
||||
}
|
||||
|
||||
public enum HidNpadJoyDeviceType
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
Right,
|
||||
}
|
||||
|
||||
public enum HidNpadJoyHoldType
|
||||
{
|
||||
Vertical,
|
||||
Horizontal
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
@ -36,6 +36,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
Dual = 1 << 2,
|
||||
Left = 1 << 3,
|
||||
Right = 1 << 4,
|
||||
Invalid = 1 << 5
|
||||
Invalid = 1 << 5,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{
|
||||
None,
|
||||
Left,
|
||||
Right
|
||||
Right,
|
||||
}
|
||||
|
||||
public struct HidVibrationDeviceValue
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
class IActiveApplicationDeviceList : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IActiveApplicationDeviceList()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, ActivateVibrationDevice }
|
||||
};
|
||||
}
|
||||
|
||||
public long ActivateVibrationDevice(ServiceCtx context)
|
||||
public long ActivateVibrationDevice(ServiceCtx Context)
|
||||
{
|
||||
int vibrationDeviceHandle = context.RequestData.ReadInt32();
|
||||
int VibrationDeviceHandle = Context.RequestData.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,30 +7,30 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
class IAppletResource : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KSharedMemory _hidSharedMem;
|
||||
private KSharedMemory HidSharedMem;
|
||||
|
||||
public IAppletResource(KSharedMemory hidSharedMem)
|
||||
public IAppletResource(KSharedMemory HidSharedMem)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetSharedMemoryHandle }
|
||||
};
|
||||
|
||||
_hidSharedMem = hidSharedMem;
|
||||
this.HidSharedMem = HidSharedMem;
|
||||
}
|
||||
|
||||
public long GetSharedMemoryHandle(ServiceCtx context)
|
||||
public long GetSharedMemoryHandle(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_hidSharedMem, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(HidSharedMem, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,176 +11,176 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
{
|
||||
public abstract IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
|
||||
|
||||
private IdDictionary _domainObjects;
|
||||
private IdDictionary DomainObjects;
|
||||
|
||||
private int _selfId;
|
||||
private int SelfId;
|
||||
|
||||
private bool _isDomain;
|
||||
private bool IsDomain;
|
||||
|
||||
public IpcService()
|
||||
{
|
||||
_domainObjects = new IdDictionary();
|
||||
DomainObjects = new IdDictionary();
|
||||
|
||||
_selfId = -1;
|
||||
SelfId = -1;
|
||||
}
|
||||
|
||||
public int ConvertToDomain()
|
||||
{
|
||||
if (_selfId == -1)
|
||||
if (SelfId == -1)
|
||||
{
|
||||
_selfId = _domainObjects.Add(this);
|
||||
SelfId = DomainObjects.Add(this);
|
||||
}
|
||||
|
||||
_isDomain = true;
|
||||
IsDomain = true;
|
||||
|
||||
return _selfId;
|
||||
return SelfId;
|
||||
}
|
||||
|
||||
public void ConvertToSession()
|
||||
{
|
||||
_isDomain = false;
|
||||
IsDomain = false;
|
||||
}
|
||||
|
||||
public void CallMethod(ServiceCtx context)
|
||||
public void CallMethod(ServiceCtx Context)
|
||||
{
|
||||
IIpcService service = this;
|
||||
IIpcService Service = this;
|
||||
|
||||
if (_isDomain)
|
||||
if (IsDomain)
|
||||
{
|
||||
int domainWord0 = context.RequestData.ReadInt32();
|
||||
int domainObjId = context.RequestData.ReadInt32();
|
||||
int DomainWord0 = Context.RequestData.ReadInt32();
|
||||
int DomainObjId = Context.RequestData.ReadInt32();
|
||||
|
||||
int domainCmd = (domainWord0 >> 0) & 0xff;
|
||||
int inputObjCount = (domainWord0 >> 8) & 0xff;
|
||||
int dataPayloadSize = (domainWord0 >> 16) & 0xffff;
|
||||
int DomainCmd = (DomainWord0 >> 0) & 0xff;
|
||||
int InputObjCount = (DomainWord0 >> 8) & 0xff;
|
||||
int DataPayloadSize = (DomainWord0 >> 16) & 0xffff;
|
||||
|
||||
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
||||
Context.RequestData.BaseStream.Seek(0x10 + DataPayloadSize, SeekOrigin.Begin);
|
||||
|
||||
for (int index = 0; index < inputObjCount; index++)
|
||||
for (int Index = 0; Index < InputObjCount; Index++)
|
||||
{
|
||||
context.Request.ObjectIds.Add(context.RequestData.ReadInt32());
|
||||
Context.Request.ObjectIds.Add(Context.RequestData.ReadInt32());
|
||||
}
|
||||
|
||||
context.RequestData.BaseStream.Seek(0x10, SeekOrigin.Begin);
|
||||
Context.RequestData.BaseStream.Seek(0x10, SeekOrigin.Begin);
|
||||
|
||||
if (domainCmd == 1)
|
||||
if (DomainCmd == 1)
|
||||
{
|
||||
service = GetObject(domainObjId);
|
||||
Service = GetObject(DomainObjId);
|
||||
|
||||
context.ResponseData.Write(0L);
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
}
|
||||
else if (domainCmd == 2)
|
||||
else if (DomainCmd == 2)
|
||||
{
|
||||
Delete(domainObjId);
|
||||
Delete(DomainObjId);
|
||||
|
||||
context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Domain command: {domainCmd}");
|
||||
throw new NotImplementedException($"Domain command: {DomainCmd}");
|
||||
}
|
||||
}
|
||||
|
||||
long sfciMagic = context.RequestData.ReadInt64();
|
||||
int commandId = (int)context.RequestData.ReadInt64();
|
||||
long SfciMagic = Context.RequestData.ReadInt64();
|
||||
int CommandId = (int)Context.RequestData.ReadInt64();
|
||||
|
||||
if (service.Commands.TryGetValue(commandId, out ServiceProcessRequest processRequest))
|
||||
if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest))
|
||||
{
|
||||
context.ResponseData.BaseStream.Seek(_isDomain ? 0x20 : 0x10, SeekOrigin.Begin);
|
||||
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin);
|
||||
|
||||
Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Method.Name}");
|
||||
Logger.PrintDebug(LogClass.KernelIpc, $"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
|
||||
|
||||
long result = processRequest(context);
|
||||
long Result = ProcessRequest(Context);
|
||||
|
||||
if (_isDomain)
|
||||
if (IsDomain)
|
||||
{
|
||||
foreach (int id in context.Response.ObjectIds)
|
||||
foreach (int Id in Context.Response.ObjectIds)
|
||||
{
|
||||
context.ResponseData.Write(id);
|
||||
Context.ResponseData.Write(Id);
|
||||
}
|
||||
|
||||
context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
context.ResponseData.Write(context.Response.ObjectIds.Count);
|
||||
Context.ResponseData.Write(Context.Response.ObjectIds.Count);
|
||||
}
|
||||
|
||||
context.ResponseData.BaseStream.Seek(_isDomain ? 0x10 : 0, SeekOrigin.Begin);
|
||||
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin);
|
||||
|
||||
context.ResponseData.Write(IpcMagic.Sfco);
|
||||
context.ResponseData.Write(result);
|
||||
Context.ResponseData.Write(IpcMagic.Sfco);
|
||||
Context.ResponseData.Write(Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
string dbgMessage = $"{context.Session.ServiceName} {service.GetType().Name}: {commandId}";
|
||||
string DbgMessage = $"{Context.Session.ServiceName} {Service.GetType().Name}: {CommandId}";
|
||||
|
||||
throw new NotImplementedException(dbgMessage);
|
||||
throw new NotImplementedException(DbgMessage);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void MakeObject(ServiceCtx context, IpcService obj)
|
||||
protected static void MakeObject(ServiceCtx Context, IpcService Obj)
|
||||
{
|
||||
IpcService service = context.Session.Service;
|
||||
IpcService Service = Context.Session.Service;
|
||||
|
||||
if (service._isDomain)
|
||||
if (Service.IsDomain)
|
||||
{
|
||||
context.Response.ObjectIds.Add(service.Add(obj));
|
||||
Context.Response.ObjectIds.Add(Service.Add(Obj));
|
||||
}
|
||||
else
|
||||
{
|
||||
KSession session = new KSession(obj, context.Session.ServiceName);
|
||||
KSession Session = new KSession(Obj, Context.Session.ServiceName);
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(session, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeMove(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
protected static T GetObject<T>(ServiceCtx context, int index) where T : IpcService
|
||||
protected static T GetObject<T>(ServiceCtx Context, int Index) where T : IpcService
|
||||
{
|
||||
IpcService service = context.Session.Service;
|
||||
IpcService Service = Context.Session.Service;
|
||||
|
||||
if (!service._isDomain)
|
||||
if (!Service.IsDomain)
|
||||
{
|
||||
int handle = context.Request.HandleDesc.ToMove[index];
|
||||
int Handle = Context.Request.HandleDesc.ToMove[Index];
|
||||
|
||||
KSession session = context.Process.HandleTable.GetObject<KSession>(handle);
|
||||
KSession Session = Context.Process.HandleTable.GetObject<KSession>(Handle);
|
||||
|
||||
return session?.Service is T ? (T)session.Service : null;
|
||||
return Session?.Service is T ? (T)Session.Service : null;
|
||||
}
|
||||
|
||||
int objId = context.Request.ObjectIds[index];
|
||||
int ObjId = Context.Request.ObjectIds[Index];
|
||||
|
||||
IIpcService obj = service.GetObject(objId);
|
||||
IIpcService Obj = Service.GetObject(ObjId);
|
||||
|
||||
return obj is T ? (T)obj : null;
|
||||
return Obj is T ? (T)Obj : null;
|
||||
}
|
||||
|
||||
private int Add(IIpcService obj)
|
||||
private int Add(IIpcService Obj)
|
||||
{
|
||||
return _domainObjects.Add(obj);
|
||||
return DomainObjects.Add(Obj);
|
||||
}
|
||||
|
||||
private bool Delete(int id)
|
||||
private bool Delete(int Id)
|
||||
{
|
||||
object obj = _domainObjects.Delete(id);
|
||||
object Obj = DomainObjects.Delete(Id);
|
||||
|
||||
if (obj is IDisposable disposableObj)
|
||||
if (Obj is IDisposable DisposableObj)
|
||||
{
|
||||
disposableObj.Dispose();
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
|
||||
return obj != null;
|
||||
return Obj != null;
|
||||
}
|
||||
|
||||
private IIpcService GetObject(int id)
|
||||
private IIpcService GetObject(int Id)
|
||||
{
|
||||
return _domainObjects.GetData<IIpcService>(id);
|
||||
return DomainObjects.GetData<IIpcService>(Id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,15 +6,15 @@ namespace Ryujinx.HLE.HOS.Services.Irs
|
|||
{
|
||||
class IIrSensorServer : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private bool _activated;
|
||||
private bool Activated;
|
||||
|
||||
public IIrSensorServer()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 302, ActivateIrsensor },
|
||||
{ 303, DeactivateIrsensor }
|
||||
|
@ -22,21 +22,21 @@ namespace Ryujinx.HLE.HOS.Services.Irs
|
|||
}
|
||||
|
||||
// ActivateIrsensor(nn::applet::AppletResourceUserId, pid)
|
||||
public long ActivateIrsensor(ServiceCtx context)
|
||||
public long ActivateIrsensor(ServiceCtx Context)
|
||||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceIrs, $"Stubbed. AppletResourceUserId: {appletResourceUserId}");
|
||||
Logger.PrintStub(LogClass.ServiceIrs, $"Stubbed. AppletResourceUserId: {AppletResourceUserId}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeactivateIrsensor(nn::applet::AppletResourceUserId, pid)
|
||||
public long DeactivateIrsensor(ServiceCtx context)
|
||||
public long DeactivateIrsensor(ServiceCtx Context)
|
||||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceIrs, $"Stubbed. AppletResourceUserId: {appletResourceUserId}");
|
||||
Logger.PrintStub(LogClass.ServiceIrs, $"Stubbed. AppletResourceUserId: {AppletResourceUserId}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using Ryujinx.HLE.HOS.Ipc;
|
|||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -50,54 +51,54 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
|
||||
class NrrInfo
|
||||
{
|
||||
public NrrHeader Header { get; }
|
||||
public List<byte[]> Hashes { get; }
|
||||
public long NrrAddress { get; }
|
||||
public NrrHeader Header { get; private set; }
|
||||
public List<byte[]> Hashes { get; private set; }
|
||||
public long NrrAddress { get; private set; }
|
||||
|
||||
public NrrInfo(long nrrAddress, NrrHeader header, List<byte[]> hashes)
|
||||
public NrrInfo(long NrrAddress, NrrHeader Header, List<byte[]> Hashes)
|
||||
{
|
||||
NrrAddress = nrrAddress;
|
||||
Header = header;
|
||||
Hashes = hashes;
|
||||
this.NrrAddress = NrrAddress;
|
||||
this.Header = Header;
|
||||
this.Hashes = Hashes;
|
||||
}
|
||||
}
|
||||
|
||||
class NroInfo
|
||||
{
|
||||
public NxRelocatableObject Executable { get; }
|
||||
public NxRelocatableObject Executable { get; private set; }
|
||||
|
||||
public byte[] Hash { get; }
|
||||
public ulong NroAddress { get; }
|
||||
public ulong NroSize { get; }
|
||||
public ulong BssAddress { get; }
|
||||
public ulong BssSize { get; }
|
||||
public ulong TotalSize { get; }
|
||||
public byte[] Hash { get; private set; }
|
||||
public ulong NroAddress { get; private set; }
|
||||
public ulong NroSize { get; private set; }
|
||||
public ulong BssAddress { get; private set; }
|
||||
public ulong BssSize { get; private set; }
|
||||
public ulong TotalSize { get; private set; }
|
||||
public ulong NroMappedAddress { get; set; }
|
||||
|
||||
public NroInfo(
|
||||
NxRelocatableObject executable,
|
||||
byte[] hash,
|
||||
ulong nroAddress,
|
||||
ulong nroSize,
|
||||
ulong bssAddress,
|
||||
ulong bssSize,
|
||||
ulong totalSize)
|
||||
NxRelocatableObject Executable,
|
||||
byte[] Hash,
|
||||
ulong NroAddress,
|
||||
ulong NroSize,
|
||||
ulong BssAddress,
|
||||
ulong BssSize,
|
||||
ulong TotalSize)
|
||||
{
|
||||
Executable = executable;
|
||||
Hash = hash;
|
||||
NroAddress = nroAddress;
|
||||
NroSize = nroSize;
|
||||
BssAddress = bssAddress;
|
||||
BssSize = bssSize;
|
||||
TotalSize = totalSize;
|
||||
this.Executable = Executable;
|
||||
this.Hash = Hash;
|
||||
this.NroAddress = NroAddress;
|
||||
this.NroSize = NroSize;
|
||||
this.BssAddress = BssAddress;
|
||||
this.BssSize = BssSize;
|
||||
this.TotalSize = TotalSize;
|
||||
}
|
||||
}
|
||||
|
||||
class IRoInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private const int MaxNrr = 0x40;
|
||||
private const int MaxNro = 0x40;
|
||||
|
@ -105,70 +106,70 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
private const uint NrrMagic = 0x3052524E;
|
||||
private const uint NroMagic = 0x304F524E;
|
||||
|
||||
private List<NrrInfo> _nrrInfos;
|
||||
private List<NroInfo> _nroInfos;
|
||||
private List<NrrInfo> NrrInfos;
|
||||
private List<NroInfo> NroInfos;
|
||||
|
||||
private bool _isInitialized;
|
||||
private bool IsInitialized;
|
||||
|
||||
public IRoInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, LoadNro },
|
||||
{ 1, UnloadNro },
|
||||
{ 2, LoadNrr },
|
||||
{ 3, UnloadNrr },
|
||||
{ 4, Initialize }
|
||||
{ 4, Initialize },
|
||||
};
|
||||
|
||||
_nrrInfos = new List<NrrInfo>(MaxNrr);
|
||||
_nroInfos = new List<NroInfo>(MaxNro);
|
||||
NrrInfos = new List<NrrInfo>(MaxNrr);
|
||||
NroInfos = new List<NroInfo>(MaxNro);
|
||||
}
|
||||
|
||||
private long ParseNrr(out NrrInfo nrrInfo, ServiceCtx context, long nrrAddress, long nrrSize)
|
||||
private long ParseNrr(out NrrInfo NrrInfo, ServiceCtx Context, long NrrAddress, long NrrSize)
|
||||
{
|
||||
nrrInfo = null;
|
||||
NrrInfo = null;
|
||||
|
||||
if (nrrSize == 0 || nrrAddress + nrrSize <= nrrAddress || (nrrSize & 0xFFF) != 0)
|
||||
if (NrrSize == 0 || NrrAddress + NrrSize <= NrrAddress || (NrrSize & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
|
||||
}
|
||||
else if ((nrrAddress & 0xFFF) != 0)
|
||||
else if ((NrrAddress & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
|
||||
}
|
||||
|
||||
StructReader reader = new StructReader(context.Memory, nrrAddress);
|
||||
NrrHeader header = reader.Read<NrrHeader>();
|
||||
StructReader Reader = new StructReader(Context.Memory, NrrAddress);
|
||||
NrrHeader Header = Reader.Read<NrrHeader>();
|
||||
|
||||
if (header.Magic != NrrMagic)
|
||||
if (Header.Magic != NrrMagic)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNrr);
|
||||
}
|
||||
else if (header.NrrSize != nrrSize)
|
||||
else if (Header.NrrSize != NrrSize)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
|
||||
}
|
||||
|
||||
List<byte[]> hashes = new List<byte[]>();
|
||||
List<byte[]> Hashes = new List<byte[]>();
|
||||
|
||||
for (int i = 0; i < header.HashCount; i++)
|
||||
for (int i = 0; i < Header.HashCount; i++)
|
||||
{
|
||||
hashes.Add(context.Memory.ReadBytes(nrrAddress + header.HashOffset + (i * 0x20), 0x20));
|
||||
Hashes.Add(Context.Memory.ReadBytes(NrrAddress + Header.HashOffset + (i * 0x20), 0x20));
|
||||
}
|
||||
|
||||
nrrInfo = new NrrInfo(nrrAddress, header, hashes);
|
||||
NrrInfo = new NrrInfo(NrrAddress, Header, Hashes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool IsNroHashPresent(byte[] nroHash)
|
||||
public bool IsNroHashPresent(byte[] NroHash)
|
||||
{
|
||||
foreach (NrrInfo info in _nrrInfos)
|
||||
foreach (NrrInfo Info in NrrInfos)
|
||||
{
|
||||
foreach (byte[] hash in info.Hashes)
|
||||
foreach (byte[] Hash in Info.Hashes)
|
||||
{
|
||||
if (hash.SequenceEqual(nroHash))
|
||||
if (Hash.SequenceEqual(NroHash))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -178,11 +179,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
return false;
|
||||
}
|
||||
|
||||
public bool IsNroLoaded(byte[] nroHash)
|
||||
public bool IsNroLoaded(byte[] NroHash)
|
||||
{
|
||||
foreach (NroInfo info in _nroInfos)
|
||||
foreach (NroInfo Info in NroInfos)
|
||||
{
|
||||
if (info.Hash.SequenceEqual(nroHash))
|
||||
if (Info.Hash.SequenceEqual(NroHash))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -191,206 +192,206 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
return false;
|
||||
}
|
||||
|
||||
public long ParseNro(out NroInfo res, ServiceCtx context, ulong nroAddress, ulong nroSize, ulong bssAddress, ulong bssSize)
|
||||
public long ParseNro(out NroInfo Res, ServiceCtx Context, ulong NroAddress, ulong NroSize, ulong BssAddress, ulong BssSize)
|
||||
{
|
||||
res = null;
|
||||
Res = null;
|
||||
|
||||
if (_nroInfos.Count >= MaxNro)
|
||||
if (NroInfos.Count >= MaxNro)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.MaxNro);
|
||||
}
|
||||
else if (nroSize == 0 || nroAddress + nroSize <= nroAddress || (nroSize & 0xFFF) != 0)
|
||||
else if (NroSize == 0 || NroAddress + NroSize <= NroAddress || (NroSize & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
|
||||
}
|
||||
else if (bssSize != 0 && bssAddress + bssSize <= bssAddress)
|
||||
else if (BssSize != 0 && BssAddress + BssSize <= BssAddress)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
|
||||
}
|
||||
else if ((nroAddress & 0xFFF) != 0)
|
||||
else if ((NroAddress & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
|
||||
}
|
||||
|
||||
uint magic = context.Memory.ReadUInt32((long)nroAddress + 0x10);
|
||||
uint nroFileSize = context.Memory.ReadUInt32((long)nroAddress + 0x18);
|
||||
uint Magic = Context.Memory.ReadUInt32((long)NroAddress + 0x10);
|
||||
uint NroFileSize = Context.Memory.ReadUInt32((long)NroAddress + 0x18);
|
||||
|
||||
if (magic != NroMagic || nroSize != nroFileSize)
|
||||
if (Magic != NroMagic || NroSize != NroFileSize)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
|
||||
}
|
||||
|
||||
byte[] nroData = context.Memory.ReadBytes((long)nroAddress, (long)nroSize);
|
||||
byte[] nroHash = null;
|
||||
byte[] NroData = Context.Memory.ReadBytes((long)NroAddress, (long)NroSize);
|
||||
byte[] NroHash = null;
|
||||
|
||||
MemoryStream stream = new MemoryStream(nroData);
|
||||
MemoryStream Stream = new MemoryStream(NroData);
|
||||
|
||||
using (SHA256 hasher = SHA256.Create())
|
||||
using (SHA256 Hasher = SHA256.Create())
|
||||
{
|
||||
nroHash = hasher.ComputeHash(stream);
|
||||
NroHash = Hasher.ComputeHash(Stream);
|
||||
}
|
||||
|
||||
if (!IsNroHashPresent(nroHash))
|
||||
if (!IsNroHashPresent(NroHash))
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.NroHashNotPresent);
|
||||
}
|
||||
|
||||
if (IsNroLoaded(nroHash))
|
||||
if (IsNroLoaded(NroHash))
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.NroAlreadyLoaded);
|
||||
}
|
||||
|
||||
stream.Position = 0;
|
||||
Stream.Position = 0;
|
||||
|
||||
NxRelocatableObject executable = new NxRelocatableObject(stream, nroAddress, bssAddress);
|
||||
NxRelocatableObject Executable = new NxRelocatableObject(Stream, NroAddress, BssAddress);
|
||||
|
||||
// check if everything is page align.
|
||||
if ((executable.Text.Length & 0xFFF) != 0 || (executable.Ro.Length & 0xFFF) != 0 ||
|
||||
(executable.Data.Length & 0xFFF) != 0 || (executable.BssSize & 0xFFF) != 0)
|
||||
if ((Executable.Text.Length & 0xFFF) != 0 || (Executable.RO.Length & 0xFFF) != 0 ||
|
||||
(Executable.Data.Length & 0xFFF) != 0 || (Executable.BssSize & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
|
||||
}
|
||||
|
||||
// check if everything is contiguous.
|
||||
if (executable.RoOffset != executable.TextOffset + executable.Text.Length ||
|
||||
executable.DataOffset != executable.RoOffset + executable.Ro.Length ||
|
||||
nroFileSize != executable.DataOffset + executable.Data.Length)
|
||||
if (Executable.ROOffset != Executable.TextOffset + Executable.Text.Length ||
|
||||
Executable.DataOffset != Executable.ROOffset + Executable.RO.Length ||
|
||||
NroFileSize != Executable.DataOffset + Executable.Data.Length)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
|
||||
}
|
||||
|
||||
// finally check the bss size match.
|
||||
if ((ulong)executable.BssSize != bssSize)
|
||||
if ((ulong)Executable.BssSize != BssSize)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
|
||||
}
|
||||
|
||||
int totalSize = executable.Text.Length + executable.Ro.Length + executable.Data.Length + executable.BssSize;
|
||||
int TotalSize = Executable.Text.Length + Executable.RO.Length + Executable.Data.Length + Executable.BssSize;
|
||||
|
||||
res = new NroInfo(
|
||||
executable,
|
||||
nroHash,
|
||||
nroAddress,
|
||||
nroSize,
|
||||
bssAddress,
|
||||
bssSize,
|
||||
(ulong)totalSize);
|
||||
Res = new NroInfo(
|
||||
Executable,
|
||||
NroHash,
|
||||
NroAddress,
|
||||
NroSize,
|
||||
BssAddress,
|
||||
BssSize,
|
||||
(ulong)TotalSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long MapNro(ServiceCtx context, NroInfo info, out ulong nroMappedAddress)
|
||||
private long MapNro(ServiceCtx Context, NroInfo Info, out ulong NroMappedAddress)
|
||||
{
|
||||
nroMappedAddress = 0;
|
||||
NroMappedAddress = 0;
|
||||
|
||||
KMemoryManager memMgr = context.Process.MemoryManager;
|
||||
KMemoryManager MemMgr = Context.Process.MemoryManager;
|
||||
|
||||
ulong targetAddress = memMgr.GetAddrSpaceBaseAddr();
|
||||
ulong TargetAddress = MemMgr.GetAddrSpaceBaseAddr();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (targetAddress + info.TotalSize >= memMgr.AddrSpaceEnd)
|
||||
if (TargetAddress + Info.TotalSize >= MemMgr.AddrSpaceEnd)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidMemoryState);
|
||||
}
|
||||
|
||||
KMemoryInfo memInfo = memMgr.QueryMemory(targetAddress);
|
||||
KMemoryInfo MemInfo = MemMgr.QueryMemory(TargetAddress);
|
||||
|
||||
if (memInfo.State == MemoryState.Unmapped && memInfo.Size >= info.TotalSize)
|
||||
if (MemInfo.State == MemoryState.Unmapped && MemInfo.Size >= Info.TotalSize)
|
||||
{
|
||||
if (!memMgr.InsideHeapRegion (targetAddress, info.TotalSize) &&
|
||||
!memMgr.InsideAliasRegion(targetAddress, info.TotalSize))
|
||||
if (!MemMgr.InsideHeapRegion (TargetAddress, Info.TotalSize) &&
|
||||
!MemMgr.InsideAliasRegion(TargetAddress, Info.TotalSize))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
targetAddress += memInfo.Size;
|
||||
TargetAddress += MemInfo.Size;
|
||||
}
|
||||
|
||||
KernelResult result = memMgr.MapProcessCodeMemory(targetAddress, info.NroAddress, info.NroSize);
|
||||
KernelResult Result = MemMgr.MapProcessCodeMemory(TargetAddress, Info.NroAddress, Info.NroSize);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidMemoryState);
|
||||
}
|
||||
|
||||
ulong bssTargetAddress = targetAddress + info.NroSize;
|
||||
ulong BssTargetAddress = TargetAddress + Info.NroSize;
|
||||
|
||||
if (info.BssSize != 0)
|
||||
if (Info.BssSize != 0)
|
||||
{
|
||||
result = memMgr.MapProcessCodeMemory(bssTargetAddress, info.BssAddress, info.BssSize);
|
||||
Result = MemMgr.MapProcessCodeMemory(BssTargetAddress, Info.BssAddress, Info.BssSize);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
memMgr.UnmapProcessCodeMemory(targetAddress, info.NroAddress, info.NroSize);
|
||||
MemMgr.UnmapProcessCodeMemory(TargetAddress, Info.NroAddress, Info.NroSize);
|
||||
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.InvalidMemoryState);
|
||||
}
|
||||
}
|
||||
|
||||
result = LoadNroIntoMemory(context.Process, info.Executable, targetAddress);
|
||||
Result = LoadNroIntoMemory(Context.Process, Info.Executable, TargetAddress);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
memMgr.UnmapProcessCodeMemory(targetAddress, info.NroAddress, info.NroSize);
|
||||
MemMgr.UnmapProcessCodeMemory(TargetAddress, Info.NroAddress, Info.NroSize);
|
||||
|
||||
if (info.BssSize != 0)
|
||||
if (Info.BssSize != 0)
|
||||
{
|
||||
memMgr.UnmapProcessCodeMemory(bssTargetAddress, info.BssAddress, info.BssSize);
|
||||
MemMgr.UnmapProcessCodeMemory(BssTargetAddress, Info.BssAddress, Info.BssSize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
info.NroMappedAddress = targetAddress;
|
||||
nroMappedAddress = targetAddress;
|
||||
Info.NroMappedAddress = TargetAddress;
|
||||
NroMappedAddress = TargetAddress;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private KernelResult LoadNroIntoMemory(KProcess process, IExecutable relocatableObject, ulong baseAddress)
|
||||
private KernelResult LoadNroIntoMemory(KProcess Process, IExecutable RelocatableObject, ulong BaseAddress)
|
||||
{
|
||||
ulong textStart = baseAddress + (ulong)relocatableObject.TextOffset;
|
||||
ulong roStart = baseAddress + (ulong)relocatableObject.RoOffset;
|
||||
ulong dataStart = baseAddress + (ulong)relocatableObject.DataOffset;
|
||||
ulong TextStart = BaseAddress + (ulong)RelocatableObject.TextOffset;
|
||||
ulong ROStart = BaseAddress + (ulong)RelocatableObject.ROOffset;
|
||||
ulong DataStart = BaseAddress + (ulong)RelocatableObject.DataOffset;
|
||||
|
||||
ulong bssStart = dataStart + (ulong)relocatableObject.Data.Length;
|
||||
ulong BssStart = DataStart + (ulong)RelocatableObject.Data.Length;
|
||||
|
||||
ulong bssEnd = BitUtils.AlignUp(bssStart + (ulong)relocatableObject.BssSize, KMemoryManager.PageSize);
|
||||
ulong BssEnd = BitUtils.AlignUp(BssStart + (ulong)RelocatableObject.BssSize, KMemoryManager.PageSize);
|
||||
|
||||
process.CpuMemory.WriteBytes((long)textStart, relocatableObject.Text);
|
||||
process.CpuMemory.WriteBytes((long)roStart, relocatableObject.Ro);
|
||||
process.CpuMemory.WriteBytes((long)dataStart, relocatableObject.Data);
|
||||
Process.CpuMemory.WriteBytes((long)TextStart, RelocatableObject.Text);
|
||||
Process.CpuMemory.WriteBytes((long)ROStart, RelocatableObject.RO);
|
||||
Process.CpuMemory.WriteBytes((long)DataStart, RelocatableObject.Data);
|
||||
|
||||
MemoryHelper.FillWithZeros(process.CpuMemory, (long)bssStart, (int)(bssEnd - bssStart));
|
||||
MemoryHelper.FillWithZeros(Process.CpuMemory, (long)BssStart, (int)(BssEnd - BssStart));
|
||||
|
||||
KernelResult result;
|
||||
KernelResult Result;
|
||||
|
||||
result = process.MemoryManager.SetProcessMemoryPermission(textStart, roStart - textStart, MemoryPermission.ReadAndExecute);
|
||||
Result = Process.MemoryManager.SetProcessMemoryPermission(TextStart, ROStart - TextStart, MemoryPermission.ReadAndExecute);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
result = process.MemoryManager.SetProcessMemoryPermission(roStart, dataStart - roStart, MemoryPermission.Read);
|
||||
Result = Process.MemoryManager.SetProcessMemoryPermission(ROStart, DataStart - ROStart, MemoryPermission.Read);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
return process.MemoryManager.SetProcessMemoryPermission(dataStart, bssEnd - dataStart, MemoryPermission.ReadAndWrite);
|
||||
return Process.MemoryManager.SetProcessMemoryPermission(DataStart, BssEnd - DataStart, MemoryPermission.ReadAndWrite);
|
||||
}
|
||||
|
||||
private long RemoveNrrInfo(long nrrAddress)
|
||||
private long RemoveNrrInfo(long NrrAddress)
|
||||
{
|
||||
foreach (NrrInfo info in _nrrInfos)
|
||||
foreach (NrrInfo Info in NrrInfos)
|
||||
{
|
||||
if (info.NrrAddress == nrrAddress)
|
||||
if (Info.NrrAddress == NrrAddress)
|
||||
{
|
||||
_nrrInfos.Remove(info);
|
||||
NrrInfos.Remove(Info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -399,46 +400,46 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
return MakeError(ErrorModule.Loader, LoaderErr.BadNrrAddress);
|
||||
}
|
||||
|
||||
private long RemoveNroInfo(ServiceCtx context, ulong nroMappedAddress)
|
||||
private long RemoveNroInfo(ServiceCtx Context, ulong NroMappedAddress)
|
||||
{
|
||||
foreach (NroInfo info in _nroInfos)
|
||||
foreach (NroInfo Info in NroInfos)
|
||||
{
|
||||
if (info.NroMappedAddress == nroMappedAddress)
|
||||
if (Info.NroMappedAddress == NroMappedAddress)
|
||||
{
|
||||
_nroInfos.Remove(info);
|
||||
NroInfos.Remove(Info);
|
||||
|
||||
ulong textSize = (ulong)info.Executable.Text.Length;
|
||||
ulong roSize = (ulong)info.Executable.Ro.Length;
|
||||
ulong dataSize = (ulong)info.Executable.Data.Length;
|
||||
ulong bssSize = (ulong)info.Executable.BssSize;
|
||||
ulong TextSize = (ulong)Info.Executable.Text.Length;
|
||||
ulong ROSize = (ulong)Info.Executable.RO.Length;
|
||||
ulong DataSize = (ulong)Info.Executable.Data.Length;
|
||||
ulong BssSize = (ulong)Info.Executable.BssSize;
|
||||
|
||||
KernelResult result = KernelResult.Success;
|
||||
KernelResult Result = KernelResult.Success;
|
||||
|
||||
if (info.Executable.BssSize != 0)
|
||||
if (Info.Executable.BssSize != 0)
|
||||
{
|
||||
result = context.Process.MemoryManager.UnmapProcessCodeMemory(
|
||||
info.NroMappedAddress + textSize + roSize + dataSize,
|
||||
info.Executable.BssAddress,
|
||||
bssSize);
|
||||
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(
|
||||
Info.NroMappedAddress + TextSize + ROSize + DataSize,
|
||||
Info.Executable.BssAddress,
|
||||
BssSize);
|
||||
}
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
if (Result == KernelResult.Success)
|
||||
{
|
||||
result = context.Process.MemoryManager.UnmapProcessCodeMemory(
|
||||
info.NroMappedAddress + textSize + roSize,
|
||||
info.Executable.SourceAddress + textSize + roSize,
|
||||
dataSize);
|
||||
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(
|
||||
Info.NroMappedAddress + TextSize + ROSize,
|
||||
Info.Executable.SourceAddress + TextSize + ROSize,
|
||||
DataSize);
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
if (Result == KernelResult.Success)
|
||||
{
|
||||
result = context.Process.MemoryManager.UnmapProcessCodeMemory(
|
||||
info.NroMappedAddress,
|
||||
info.Executable.SourceAddress,
|
||||
textSize + roSize);
|
||||
Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(
|
||||
Info.NroMappedAddress,
|
||||
Info.Executable.SourceAddress,
|
||||
TextSize + ROSize);
|
||||
}
|
||||
}
|
||||
|
||||
return (long)result;
|
||||
return (long)Result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,125 +447,125 @@ namespace Ryujinx.HLE.HOS.Services.Ldr
|
|||
}
|
||||
|
||||
// LoadNro(u64, u64, u64, u64, u64, pid) -> u64
|
||||
public long LoadNro(ServiceCtx context)
|
||||
public long LoadNro(ServiceCtx Context)
|
||||
{
|
||||
long result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
|
||||
// Zero
|
||||
context.RequestData.ReadUInt64();
|
||||
Context.RequestData.ReadUInt64();
|
||||
|
||||
ulong nroHeapAddress = context.RequestData.ReadUInt64();
|
||||
ulong nroSize = context.RequestData.ReadUInt64();
|
||||
ulong bssHeapAddress = context.RequestData.ReadUInt64();
|
||||
ulong bssSize = context.RequestData.ReadUInt64();
|
||||
ulong NroHeapAddress = Context.RequestData.ReadUInt64();
|
||||
ulong NroSize = Context.RequestData.ReadUInt64();
|
||||
ulong BssHeapAddress = Context.RequestData.ReadUInt64();
|
||||
ulong BssSize = Context.RequestData.ReadUInt64();
|
||||
|
||||
ulong nroMappedAddress = 0;
|
||||
ulong NroMappedAddress = 0;
|
||||
|
||||
if (_isInitialized)
|
||||
if (IsInitialized)
|
||||
{
|
||||
NroInfo info;
|
||||
NroInfo Info;
|
||||
|
||||
result = ParseNro(out info, context, nroHeapAddress, nroSize, bssHeapAddress, bssSize);
|
||||
Result = ParseNro(out Info, Context, NroHeapAddress, NroSize, BssHeapAddress, BssSize);
|
||||
|
||||
if (result == 0)
|
||||
if (Result == 0)
|
||||
{
|
||||
result = MapNro(context, info, out nroMappedAddress);
|
||||
Result = MapNro(Context, Info, out NroMappedAddress);
|
||||
|
||||
if (result == 0)
|
||||
if (Result == 0)
|
||||
{
|
||||
_nroInfos.Add(info);
|
||||
NroInfos.Add(Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.ResponseData.Write(nroMappedAddress);
|
||||
Context.ResponseData.Write(NroMappedAddress);
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// UnloadNro(u64, u64, pid)
|
||||
public long UnloadNro(ServiceCtx context)
|
||||
public long UnloadNro(ServiceCtx Context)
|
||||
{
|
||||
long result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
|
||||
// Zero
|
||||
context.RequestData.ReadUInt64();
|
||||
Context.RequestData.ReadUInt64();
|
||||
|
||||
ulong nroMappedAddress = context.RequestData.ReadUInt64();
|
||||
ulong NroMappedAddress = Context.RequestData.ReadUInt64();
|
||||
|
||||
if (_isInitialized)
|
||||
if (IsInitialized)
|
||||
{
|
||||
if ((nroMappedAddress & 0xFFF) != 0)
|
||||
if ((NroMappedAddress & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
|
||||
}
|
||||
|
||||
result = RemoveNroInfo(context, nroMappedAddress);
|
||||
Result = RemoveNroInfo(Context, NroMappedAddress);
|
||||
}
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// LoadNrr(u64, u64, u64, pid)
|
||||
public long LoadNrr(ServiceCtx context)
|
||||
public long LoadNrr(ServiceCtx Context)
|
||||
{
|
||||
long result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
|
||||
// Zero
|
||||
context.RequestData.ReadUInt64();
|
||||
Context.RequestData.ReadUInt64();
|
||||
|
||||
long nrrAddress = context.RequestData.ReadInt64();
|
||||
long nrrSize = context.RequestData.ReadInt64();
|
||||
long NrrAddress = Context.RequestData.ReadInt64();
|
||||
long NrrSize = Context.RequestData.ReadInt64();
|
||||
|
||||
if (_isInitialized)
|
||||
if (IsInitialized)
|
||||
{
|
||||
NrrInfo info;
|
||||
result = ParseNrr(out info, context, nrrAddress, nrrSize);
|
||||
NrrInfo Info;
|
||||
Result = ParseNrr(out Info, Context, NrrAddress, NrrSize);
|
||||
|
||||
if(result == 0)
|
||||
if(Result == 0)
|
||||
{
|
||||
if (_nrrInfos.Count >= MaxNrr)
|
||||
if (NrrInfos.Count >= MaxNrr)
|
||||
{
|
||||
result = MakeError(ErrorModule.Loader, LoaderErr.MaxNrr);
|
||||
Result = MakeError(ErrorModule.Loader, LoaderErr.MaxNrr);
|
||||
}
|
||||
else
|
||||
{
|
||||
_nrrInfos.Add(info);
|
||||
NrrInfos.Add(Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// UnloadNrr(u64, u64, pid)
|
||||
public long UnloadNrr(ServiceCtx context)
|
||||
public long UnloadNrr(ServiceCtx Context)
|
||||
{
|
||||
long result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
|
||||
|
||||
// Zero
|
||||
context.RequestData.ReadUInt64();
|
||||
Context.RequestData.ReadUInt64();
|
||||
|
||||
long nrrHeapAddress = context.RequestData.ReadInt64();
|
||||
long NrrHeapAddress = Context.RequestData.ReadInt64();
|
||||
|
||||
if (_isInitialized)
|
||||
if (IsInitialized)
|
||||
{
|
||||
if ((nrrHeapAddress & 0xFFF) != 0)
|
||||
if ((NrrHeapAddress & 0xFFF) != 0)
|
||||
{
|
||||
return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
|
||||
}
|
||||
|
||||
result = RemoveNrrInfo(nrrHeapAddress);
|
||||
Result = RemoveNrrInfo(NrrHeapAddress);
|
||||
}
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Initialize(u64, pid, KObject)
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
// TODO: we actually ignore the pid and process handle receive, we will need to use them when we will have multi process support.
|
||||
_isInitialized = true;
|
||||
IsInitialized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Lm
|
|||
{
|
||||
class ILogService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILogService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Initialize }
|
||||
};
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new ILogger());
|
||||
MakeObject(Context, new ILogger());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,91 +8,91 @@ namespace Ryujinx.HLE.HOS.Services.Lm
|
|||
{
|
||||
class ILogger : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILogger()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Log }
|
||||
};
|
||||
}
|
||||
|
||||
public long Log(ServiceCtx context)
|
||||
public long Log(ServiceCtx Context)
|
||||
{
|
||||
|
||||
(long bufPos, long bufSize) = context.Request.GetBufferType0x21();
|
||||
byte[] logBuffer = context.Memory.ReadBytes(bufPos, bufSize);
|
||||
(long BufPos, long BufSize) = Context.Request.GetBufferType0x21();
|
||||
byte[] LogBuffer = Context.Memory.ReadBytes(BufPos, BufSize);
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(logBuffer))
|
||||
using (MemoryStream MS = new MemoryStream(LogBuffer))
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(ms);
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
long pid = reader.ReadInt64();
|
||||
long threadContext = reader.ReadInt64();
|
||||
short flags = reader.ReadInt16();
|
||||
byte level = reader.ReadByte();
|
||||
byte verbosity = reader.ReadByte();
|
||||
int payloadLength = reader.ReadInt32();
|
||||
long Pid = Reader.ReadInt64();
|
||||
long ThreadContext = Reader.ReadInt64();
|
||||
short Flags = Reader.ReadInt16();
|
||||
byte Level = Reader.ReadByte();
|
||||
byte Verbosity = Reader.ReadByte();
|
||||
int PayloadLength = Reader.ReadInt32();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder SB = new StringBuilder();
|
||||
|
||||
sb.AppendLine("Guest log:");
|
||||
SB.AppendLine("Guest log:");
|
||||
|
||||
while (ms.Position < ms.Length)
|
||||
while (MS.Position < MS.Length)
|
||||
{
|
||||
byte type = reader.ReadByte();
|
||||
byte size = reader.ReadByte();
|
||||
byte Type = Reader.ReadByte();
|
||||
byte Size = Reader.ReadByte();
|
||||
|
||||
LmLogField field = (LmLogField)type;
|
||||
LmLogField Field = (LmLogField)Type;
|
||||
|
||||
string fieldStr = string.Empty;
|
||||
string FieldStr = string.Empty;
|
||||
|
||||
if (field == LmLogField.Start)
|
||||
if (Field == LmLogField.Start)
|
||||
{
|
||||
reader.ReadBytes(size);
|
||||
Reader.ReadBytes(Size);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (field == LmLogField.Stop)
|
||||
else if (Field == LmLogField.Stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (field == LmLogField.Line)
|
||||
else if (Field == LmLogField.Line)
|
||||
{
|
||||
fieldStr = $"{field}: {reader.ReadInt32()}";
|
||||
FieldStr = $"{Field}: {Reader.ReadInt32()}";
|
||||
}
|
||||
else if (field == LmLogField.DropCount)
|
||||
else if (Field == LmLogField.DropCount)
|
||||
{
|
||||
fieldStr = $"{field}: {reader.ReadInt64()}";
|
||||
FieldStr = $"{Field}: {Reader.ReadInt64()}";
|
||||
}
|
||||
else if (field == LmLogField.Time)
|
||||
else if (Field == LmLogField.Time)
|
||||
{
|
||||
fieldStr = $"{field}: {reader.ReadInt64()}s";
|
||||
FieldStr = $"{Field}: {Reader.ReadInt64()}s";
|
||||
}
|
||||
else if (field < LmLogField.Count)
|
||||
else if (Field < LmLogField.Count)
|
||||
{
|
||||
fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'";
|
||||
FieldStr = $"{Field}: '{Encoding.UTF8.GetString(Reader.ReadBytes(Size)).TrimEnd()}'";
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.ReadBytes(size)).TrimEnd()}'";
|
||||
FieldStr = $"Field{Field}: '{Encoding.UTF8.GetString(Reader.ReadBytes(Size)).TrimEnd()}'";
|
||||
}
|
||||
|
||||
sb.AppendLine(" " + fieldStr);
|
||||
SB.AppendLine(" " + FieldStr);
|
||||
}
|
||||
|
||||
string text = sb.ToString();
|
||||
string Text = SB.ToString();
|
||||
|
||||
switch((LmLogLevel)level)
|
||||
switch((LmLogLevel)Level)
|
||||
{
|
||||
case LmLogLevel.Trace: Logger.PrintDebug (LogClass.ServiceLm, text); break;
|
||||
case LmLogLevel.Info: Logger.PrintInfo (LogClass.ServiceLm, text); break;
|
||||
case LmLogLevel.Warning: Logger.PrintWarning(LogClass.ServiceLm, text); break;
|
||||
case LmLogLevel.Error: Logger.PrintError (LogClass.ServiceLm, text); break;
|
||||
case LmLogLevel.Critical: Logger.PrintError (LogClass.ServiceLm, text); break;
|
||||
case LmLogLevel.Trace: Logger.PrintDebug (LogClass.ServiceLm, Text); break;
|
||||
case LmLogLevel.Info: Logger.PrintInfo (LogClass.ServiceLm, Text); break;
|
||||
case LmLogLevel.Warning: Logger.PrintWarning(LogClass.ServiceLm, Text); break;
|
||||
case LmLogLevel.Error: Logger.PrintError (LogClass.ServiceLm, Text); break;
|
||||
case LmLogLevel.Critical: Logger.PrintError (LogClass.ServiceLm, Text); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,15 +12,15 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
{
|
||||
class ILocationResolver : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private StorageId _storageId;
|
||||
private StorageId StorageId;
|
||||
|
||||
public ILocationResolver(StorageId storageId)
|
||||
public ILocationResolver(StorageId StorageId)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, ResolveProgramPath },
|
||||
{ 1, RedirectProgramPath },
|
||||
|
@ -40,103 +40,103 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
{ 15, DeleteInfoHtmlNcaPath }
|
||||
};
|
||||
|
||||
_storageId = storageId;
|
||||
this.StorageId = StorageId;
|
||||
}
|
||||
|
||||
// DeleteInfoHtmlNcaPath()
|
||||
public long DeleteInfoHtmlNcaPath(ServiceCtx context)
|
||||
public long DeleteInfoHtmlNcaPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
DeleteContentPath(context, titleId, ContentType.Manual);
|
||||
DeleteContentPath(Context, TitleId, ContentType.Manual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeleteDocHtmlNcaPath()
|
||||
public long DeleteDocHtmlNcaPath(ServiceCtx context)
|
||||
public long DeleteDocHtmlNcaPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
DeleteContentPath(context, titleId, ContentType.Manual);
|
||||
DeleteContentPath(Context, TitleId, ContentType.Manual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeleteControlNcaPath()
|
||||
public long DeleteControlNcaPath(ServiceCtx context)
|
||||
public long DeleteControlNcaPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
DeleteContentPath(context, titleId, ContentType.Control);
|
||||
DeleteContentPath(Context, TitleId, ContentType.Control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeleteProgramNcaPath()
|
||||
public long DeleteProgramNcaPath(ServiceCtx context)
|
||||
public long DeleteProgramNcaPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
DeleteContentPath(context, titleId, ContentType.Program);
|
||||
DeleteContentPath(Context, TitleId, ContentType.Program);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ClearLocationResolver2()
|
||||
public long ClearLocationResolver2(ServiceCtx context)
|
||||
public long ClearLocationResolver2(ServiceCtx Context)
|
||||
{
|
||||
context.Device.System.ContentManager.RefreshEntries(_storageId, 1);
|
||||
Context.Device.System.ContentManager.RefreshEntries(StorageId, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SetProgramNcaPath2()
|
||||
public long SetProgramNcaPath2(ServiceCtx context)
|
||||
public long SetProgramNcaPath2(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
RedirectPath(context, titleId, 1, ContentType.Program);
|
||||
RedirectPath(Context, TitleId, 1, ContentType.Program);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RedirectApplicationControlPath()
|
||||
public long RedirectApplicationControlPath(ServiceCtx context)
|
||||
public long RedirectApplicationControlPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
RedirectPath(context, titleId, 1, ContentType.Control);
|
||||
RedirectPath(Context, TitleId, 1, ContentType.Control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RedirectApplicationHtmlDocumentPath()
|
||||
public long RedirectApplicationHtmlDocumentPath(ServiceCtx context)
|
||||
public long RedirectApplicationHtmlDocumentPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
RedirectPath(context, titleId, 1, ContentType.Manual);
|
||||
RedirectPath(Context, TitleId, 1, ContentType.Manual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RedirectApplicationLegalInformationPath()
|
||||
public long RedirectApplicationLegalInformationPath(ServiceCtx context)
|
||||
public long RedirectApplicationLegalInformationPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
RedirectPath(context, titleId, 1, ContentType.Manual);
|
||||
RedirectPath(Context, TitleId, 1, ContentType.Manual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ResolveDataPath()
|
||||
public long ResolveDataPath(ServiceCtx context)
|
||||
public long ResolveDataPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.AocData))
|
||||
if (ResolvePath(Context, TitleId, ContentType.Data) || ResolvePath(Context, TitleId, ContentType.AocData))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -147,11 +147,11 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
}
|
||||
|
||||
// ResolveApplicationHtmlDocumentPath()
|
||||
public long ResolveApplicationHtmlDocumentPath(ServiceCtx context)
|
||||
public long ResolveApplicationHtmlDocumentPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
if (ResolvePath(context, titleId, ContentType.Manual))
|
||||
if (ResolvePath(Context, TitleId, ContentType.Manual))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -162,11 +162,11 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
}
|
||||
|
||||
// ResolveApplicationLegalInformationPath()
|
||||
public long ResolveApplicationLegalInformationPath(ServiceCtx context)
|
||||
public long ResolveApplicationLegalInformationPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
if (ResolvePath(context, titleId, ContentType.Manual))
|
||||
if (ResolvePath(Context, TitleId, ContentType.Manual))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -177,11 +177,11 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
}
|
||||
|
||||
// ResolveApplicationControlPath()
|
||||
public long ResolveApplicationControlPath(ServiceCtx context)
|
||||
public long ResolveApplicationControlPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
if (ResolvePath(context, titleId, ContentType.Control))
|
||||
if (ResolvePath(Context, TitleId, ContentType.Control))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -192,29 +192,29 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
}
|
||||
|
||||
// RedirectProgramPath()
|
||||
public long RedirectProgramPath(ServiceCtx context)
|
||||
public long RedirectProgramPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
RedirectPath(context, titleId, 0, ContentType.Program);
|
||||
RedirectPath(Context, TitleId, 0, ContentType.Program);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Refresh()
|
||||
public long Refresh(ServiceCtx context)
|
||||
public long Refresh(ServiceCtx Context)
|
||||
{
|
||||
context.Device.System.ContentManager.RefreshEntries(_storageId, 1);
|
||||
Context.Device.System.ContentManager.RefreshEntries(StorageId, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ResolveProgramPath()
|
||||
public long ResolveProgramPath(ServiceCtx context)
|
||||
public long ResolveProgramPath(ServiceCtx Context)
|
||||
{
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
if (ResolvePath(context, titleId, ContentType.Program))
|
||||
if (ResolvePath(Context, TitleId, ContentType.Program))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -224,27 +224,27 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
}
|
||||
}
|
||||
|
||||
private void RedirectPath(ServiceCtx context, long titleId, int flag, ContentType contentType)
|
||||
private void RedirectPath(ServiceCtx Context, long TitleId, int Flag, ContentType ContentType)
|
||||
{
|
||||
string contentPath = ReadUtf8String(context);
|
||||
LocationEntry newLocation = new LocationEntry(contentPath, flag, titleId, contentType);
|
||||
string ContentPath = ReadUtf8String(Context);
|
||||
LocationEntry NewLocation = new LocationEntry(ContentPath, Flag, TitleId, ContentType);
|
||||
|
||||
context.Device.System.ContentManager.RedirectLocation(newLocation, _storageId);
|
||||
Context.Device.System.ContentManager.RedirectLocation(NewLocation, StorageId);
|
||||
}
|
||||
|
||||
private bool ResolvePath(ServiceCtx context, long titleId,ContentType contentType)
|
||||
private bool ResolvePath(ServiceCtx Context, long TitleId,ContentType ContentType)
|
||||
{
|
||||
ContentManager contentManager = context.Device.System.ContentManager;
|
||||
string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Program);
|
||||
ContentManager ContentManager = Context.Device.System.ContentManager;
|
||||
string ContentPath = ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.Program);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(contentPath))
|
||||
if (!string.IsNullOrWhiteSpace(ContentPath))
|
||||
{
|
||||
long position = context.Request.RecvListBuff[0].Position;
|
||||
long size = context.Request.RecvListBuff[0].Size;
|
||||
long Position = Context.Request.RecvListBuff[0].Position;
|
||||
long Size = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
byte[] contentPathBuffer = Encoding.UTF8.GetBytes(contentPath);
|
||||
byte[] ContentPathBuffer = Encoding.UTF8.GetBytes(ContentPath);
|
||||
|
||||
context.Memory.WriteBytes(position, contentPathBuffer);
|
||||
Context.Memory.WriteBytes(Position, ContentPathBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -254,12 +254,12 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
return true;
|
||||
}
|
||||
|
||||
private void DeleteContentPath(ServiceCtx context, long titleId, ContentType contentType)
|
||||
private void DeleteContentPath(ServiceCtx Context, long TitleId, ContentType ContentType)
|
||||
{
|
||||
ContentManager contentManager = context.Device.System.ContentManager;
|
||||
string contentPath = contentManager.GetInstalledContentPath(titleId, _storageId, ContentType.Manual);
|
||||
ContentManager ContentManager = Context.Device.System.ContentManager;
|
||||
string ContentPath = ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.Manual);
|
||||
|
||||
contentManager.ClearEntry(titleId, ContentType.Manual, _storageId);
|
||||
ContentManager.ClearEntry(TitleId, ContentType.Manual, StorageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
|
||||
|
@ -6,24 +7,24 @@ namespace Ryujinx.HLE.HOS.Services.Lr
|
|||
{
|
||||
class ILocationResolverManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILocationResolverManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, OpenLocationResolver }
|
||||
{ 0, OpenLocationResolver },
|
||||
};
|
||||
}
|
||||
|
||||
// OpenLocationResolver()
|
||||
private long OpenLocationResolver(ServiceCtx context)
|
||||
private long OpenLocationResolver(ServiceCtx Context)
|
||||
{
|
||||
StorageId storageId = (StorageId)context.RequestData.ReadByte();
|
||||
StorageId StorageId = (StorageId)Context.RequestData.ReadByte();
|
||||
|
||||
MakeObject(context, new ILocationResolver(storageId));
|
||||
MakeObject(Context, new ILocationResolver(StorageId));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Mm
|
|||
{
|
||||
class IRequest : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IRequest()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, InitializeOld },
|
||||
{ 4, Initialize },
|
||||
|
@ -23,43 +23,43 @@ namespace Ryujinx.HLE.HOS.Services.Mm
|
|||
}
|
||||
|
||||
// InitializeOld(u32, u32, u32)
|
||||
public long InitializeOld(ServiceCtx context)
|
||||
public long InitializeOld(ServiceCtx Context)
|
||||
{
|
||||
int unknown0 = context.RequestData.ReadInt32();
|
||||
int unknown1 = context.RequestData.ReadInt32();
|
||||
int unknown2 = context.RequestData.ReadInt32();
|
||||
int Unknown0 = Context.RequestData.ReadInt32();
|
||||
int Unknown1 = Context.RequestData.ReadInt32();
|
||||
int Unknown2 = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceMm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceMm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Finalize(ServiceCtx context)
|
||||
public long Finalize(ServiceCtx Context)
|
||||
{
|
||||
context.Device.Gpu.UninitializeVideoDecoder();
|
||||
Context.Device.Gpu.UninitializeVideoDecoder();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceMm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetAndWait(ServiceCtx context)
|
||||
public long SetAndWait(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceMm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Get(ServiceCtx context)
|
||||
public long Get(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceMm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Ncm
|
|||
{
|
||||
class IContentManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IContentManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Ncm
|
|||
{
|
||||
class IContentStorage : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IContentStorage()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
||||
};
|
||||
|
|
|
@ -9,25 +9,25 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
|
|||
{
|
||||
class IUser : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private const HidControllerId NpadId = HidControllerId.ControllerPlayer1;
|
||||
private const HidControllerId NpadId = HidControllerId.CONTROLLER_PLAYER_1;
|
||||
|
||||
private State _state = State.NonInitialized;
|
||||
private State State = State.NonInitialized;
|
||||
|
||||
private DeviceState _deviceState = DeviceState.Initialized;
|
||||
private DeviceState DeviceState = DeviceState.Initialized;
|
||||
|
||||
private KEvent _activateEvent;
|
||||
private KEvent ActivateEvent;
|
||||
|
||||
private KEvent _deactivateEvent;
|
||||
private KEvent DeactivateEvent;
|
||||
|
||||
private KEvent _availabilityChangeEvent;
|
||||
private KEvent AvailabilityChangeEvent;
|
||||
|
||||
public IUser(Horizon system)
|
||||
public IUser(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Initialize },
|
||||
{ 17, AttachActivateEvent },
|
||||
|
@ -38,85 +38,85 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
|
|||
{ 23, AttachAvailabilityChangeEvent }
|
||||
};
|
||||
|
||||
_activateEvent = new KEvent(system);
|
||||
_deactivateEvent = new KEvent(system);
|
||||
_availabilityChangeEvent = new KEvent(system);
|
||||
ActivateEvent = new KEvent(System);
|
||||
DeactivateEvent = new KEvent(System);
|
||||
AvailabilityChangeEvent = new KEvent(System);
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
_state = State.Initialized;
|
||||
State = State.Initialized;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AttachActivateEvent(ServiceCtx context)
|
||||
public long AttachActivateEvent(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_activateEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(ActivateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AttachDeactivateEvent(ServiceCtx context)
|
||||
public long AttachDeactivateEvent(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_deactivateEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(DeactivateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetState(ServiceCtx context)
|
||||
public long GetState(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)_state);
|
||||
Context.ResponseData.Write((int)State);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetDeviceState(ServiceCtx context)
|
||||
public long GetDeviceState(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)_deviceState);
|
||||
Context.ResponseData.Write((int)DeviceState);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetNpadId(ServiceCtx context)
|
||||
public long GetNpadId(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)NpadId);
|
||||
Context.ResponseData.Write((int)NpadId);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AttachAvailabilityChangeEvent(ServiceCtx context)
|
||||
public long AttachAvailabilityChangeEvent(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNfp, "Stubbed.");
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(AvailabilityChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
|
|||
{
|
||||
class IUserManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IUserManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetUserInterface }
|
||||
};
|
||||
}
|
||||
|
||||
public long GetUserInterface(ServiceCtx context)
|
||||
public long GetUserInterface(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IUser(context.Device.System));
|
||||
MakeObject(Context, new IUser(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -13,44 +13,44 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
|
|||
{
|
||||
class IGeneralService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IGeneralService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 4, CreateRequest },
|
||||
{ 12, GetCurrentIpAddress }
|
||||
};
|
||||
}
|
||||
|
||||
public long CreateRequest(ServiceCtx context)
|
||||
public long CreateRequest(ServiceCtx Context)
|
||||
{
|
||||
int unknown = context.RequestData.ReadInt32();
|
||||
int Unknown = Context.RequestData.ReadInt32();
|
||||
|
||||
MakeObject(context, new IRequest(context.Device.System));
|
||||
MakeObject(Context, new IRequest(Context.Device.System));
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetCurrentIpAddress(ServiceCtx context)
|
||||
public long GetCurrentIpAddress(ServiceCtx Context)
|
||||
{
|
||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||
{
|
||||
return MakeError(ErrorModule.Nifm, NifmErr.NoInternetConnection);
|
||||
}
|
||||
|
||||
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
|
||||
IPHostEntry Host = Dns.GetHostEntry(Dns.GetHostName());
|
||||
|
||||
IPAddress address = host.AddressList.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork);
|
||||
IPAddress Address = Host.AddressList.FirstOrDefault(A => A.AddressFamily == AddressFamily.InterNetwork);
|
||||
|
||||
context.ResponseData.Write(BitConverter.ToUInt32(address.GetAddressBytes()));
|
||||
Context.ResponseData.Write(BitConverter.ToUInt32(Address.GetAddressBytes()));
|
||||
|
||||
Logger.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{address}\".");
|
||||
Logger.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{Address}\".");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,16 +8,16 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
|
|||
{
|
||||
class IRequest : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _event0;
|
||||
private KEvent _event1;
|
||||
private KEvent Event0;
|
||||
private KEvent Event1;
|
||||
|
||||
public IRequest(Horizon system)
|
||||
public IRequest(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetRequestState },
|
||||
{ 1, GetResult },
|
||||
|
@ -27,58 +27,58 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
|
|||
{ 11, SetConnectionConfirmationOption }
|
||||
};
|
||||
|
||||
_event0 = new KEvent(system);
|
||||
_event1 = new KEvent(system);
|
||||
Event0 = new KEvent(System);
|
||||
Event1 = new KEvent(System);
|
||||
}
|
||||
|
||||
public long GetRequestState(ServiceCtx context)
|
||||
public long GetRequestState(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(1);
|
||||
Context.ResponseData.Write(1);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetResult(ServiceCtx context)
|
||||
public long GetResult(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSystemEventReadableHandles(ServiceCtx context)
|
||||
public long GetSystemEventReadableHandles(ServiceCtx Context)
|
||||
{
|
||||
if (context.Process.HandleTable.GenerateHandle(_event0.ReadableEvent, out int handle0) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(Event0.ReadableEvent, out int Handle0) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_event1.ReadableEvent, out int handle1) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(Event1.ReadableEvent, out int Handle1) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle0, handle1);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle0, Handle1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Cancel(ServiceCtx context)
|
||||
public long Cancel(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Submit(ServiceCtx context)
|
||||
public long Submit(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetConnectionConfirmationOption(ServiceCtx context)
|
||||
public long SetConnectionConfirmationOption(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||
|
||||
|
|
|
@ -5,29 +5,29 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
|
|||
{
|
||||
class IStaticService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IStaticService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 4, CreateGeneralServiceOld },
|
||||
{ 5, CreateGeneralService }
|
||||
};
|
||||
}
|
||||
|
||||
public long CreateGeneralServiceOld(ServiceCtx context)
|
||||
public long CreateGeneralServiceOld(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IGeneralService());
|
||||
MakeObject(Context, new IGeneralService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateGeneralService(ServiceCtx context)
|
||||
public long CreateGeneralService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IGeneralService());
|
||||
MakeObject(Context, new IGeneralService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,35 +6,35 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
class IAddOnContentManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAddOnContentManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 2, CountAddOnContent },
|
||||
{ 3, ListAddOnContent }
|
||||
};
|
||||
}
|
||||
|
||||
public static long CountAddOnContent(ServiceCtx context)
|
||||
public static long CountAddOnContent(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNs, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long ListAddOnContent(ServiceCtx context)
|
||||
public static long ListAddOnContent(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNs, "Stubbed.");
|
||||
|
||||
//TODO: This is supposed to write a u32 array aswell.
|
||||
//It's unknown what it contains.
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Ns
|
||||
{
|
||||
class IApplicationManagerInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private bool _isInitialized;
|
||||
private bool IsInitialized;
|
||||
|
||||
public IApplicationManagerInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
class IServiceGetterInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IServiceGetterInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
class ISystemUpdateInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISystemUpdateInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
class IVulnerabilityManagerInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IVulnerabilityManagerInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
};
|
||||
|
|
|
@ -14,15 +14,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
{
|
||||
class INvDrvServices : IpcService
|
||||
{
|
||||
private delegate int IoctlProcessor(ServiceCtx context, int cmd);
|
||||
private delegate int IoctlProcessor(ServiceCtx Context, int Cmd);
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private static Dictionary<string, IoctlProcessor> _ioctlProcessors =
|
||||
new Dictionary<string, IoctlProcessor>
|
||||
{
|
||||
private static Dictionary<string, IoctlProcessor> IoctlProcessors =
|
||||
new Dictionary<string, IoctlProcessor>()
|
||||
{
|
||||
{ "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS },
|
||||
{ "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl },
|
||||
{ "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu },
|
||||
|
@ -32,13 +32,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
{ "/dev/nvmap", ProcessIoctlNvMap }
|
||||
};
|
||||
|
||||
public static GlobalStateTable Fds { get; }
|
||||
public static GlobalStateTable Fds { get; private set; }
|
||||
|
||||
private KEvent _event;
|
||||
private KEvent Event;
|
||||
|
||||
public INvDrvServices(Horizon system)
|
||||
public INvDrvServices(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Open },
|
||||
{ 1, Ioctl },
|
||||
|
@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
{ 13, FinishInitialize }
|
||||
};
|
||||
|
||||
_event = new KEvent(system);
|
||||
Event = new KEvent(System);
|
||||
}
|
||||
|
||||
static INvDrvServices()
|
||||
|
@ -58,166 +58,166 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
Fds = new GlobalStateTable();
|
||||
}
|
||||
|
||||
public long Open(ServiceCtx context)
|
||||
public long Open(ServiceCtx Context)
|
||||
{
|
||||
long namePtr = context.Request.SendBuff[0].Position;
|
||||
long NamePtr = Context.Request.SendBuff[0].Position;
|
||||
|
||||
string name = MemoryHelper.ReadAsciiString(context.Memory, namePtr);
|
||||
string Name = MemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
|
||||
|
||||
int fd = Fds.Add(context.Process, new NvFd(name));
|
||||
int Fd = Fds.Add(Context.Process, new NvFd(Name));
|
||||
|
||||
context.ResponseData.Write(fd);
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(Fd);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Ioctl(ServiceCtx context)
|
||||
public long Ioctl(ServiceCtx Context)
|
||||
{
|
||||
int fd = context.RequestData.ReadInt32();
|
||||
int cmd = context.RequestData.ReadInt32();
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
int Cmd = Context.RequestData.ReadInt32();
|
||||
|
||||
NvFd fdData = Fds.GetData<NvFd>(context.Process, fd);
|
||||
NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
|
||||
|
||||
int result;
|
||||
int Result;
|
||||
|
||||
if (_ioctlProcessors.TryGetValue(fdData.Name, out IoctlProcessor process))
|
||||
if (IoctlProcessors.TryGetValue(FdData.Name, out IoctlProcessor Process))
|
||||
{
|
||||
result = process(context, cmd);
|
||||
Result = Process(Context, Cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"{fdData.Name} {cmd:x4}");
|
||||
throw new NotImplementedException($"{FdData.Name} {Cmd:x4}");
|
||||
}
|
||||
|
||||
//TODO: Verify if the error codes needs to be translated.
|
||||
context.ResponseData.Write(result);
|
||||
Context.ResponseData.Write(Result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Close(ServiceCtx context)
|
||||
public long Close(ServiceCtx Context)
|
||||
{
|
||||
int fd = context.RequestData.ReadInt32();
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
|
||||
Fds.Delete(context.Process, fd);
|
||||
Fds.Delete(Context.Process, Fd);
|
||||
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
long transferMemSize = context.RequestData.ReadInt64();
|
||||
int transferMemHandle = context.Request.HandleDesc.ToCopy[0];
|
||||
long TransferMemSize = Context.RequestData.ReadInt64();
|
||||
int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
|
||||
|
||||
NvMapIoctl.InitializeNvMap(context);
|
||||
NvMapIoctl.InitializeNvMap(Context);
|
||||
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QueryEvent(ServiceCtx context)
|
||||
public long QueryEvent(ServiceCtx Context)
|
||||
{
|
||||
int fd = context.RequestData.ReadInt32();
|
||||
int eventId = context.RequestData.ReadInt32();
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
int EventId = Context.RequestData.ReadInt32();
|
||||
|
||||
//TODO: Use Fd/EventId, different channels have different events.
|
||||
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetClientPid(ServiceCtx context)
|
||||
public long SetClientPid(ServiceCtx Context)
|
||||
{
|
||||
long pid = context.RequestData.ReadInt64();
|
||||
long Pid = Context.RequestData.ReadInt64();
|
||||
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long FinishInitialize(ServiceCtx context)
|
||||
public long FinishInitialize(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int ProcessIoctlNvGpuAS(ServiceCtx context, int cmd)
|
||||
private static int ProcessIoctlNvGpuAS(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
return ProcessIoctl(context, cmd, NvGpuASIoctl.ProcessIoctl);
|
||||
return ProcessIoctl(Context, Cmd, NvGpuASIoctl.ProcessIoctl);
|
||||
}
|
||||
|
||||
private static int ProcessIoctlNvHostCtrl(ServiceCtx context, int cmd)
|
||||
private static int ProcessIoctlNvHostCtrl(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
return ProcessIoctl(context, cmd, NvHostCtrlIoctl.ProcessIoctl);
|
||||
return ProcessIoctl(Context, Cmd, NvHostCtrlIoctl.ProcessIoctl);
|
||||
}
|
||||
|
||||
private static int ProcessIoctlNvGpuGpu(ServiceCtx context, int cmd)
|
||||
private static int ProcessIoctlNvGpuGpu(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
return ProcessIoctl(context, cmd, NvGpuGpuIoctl.ProcessIoctl);
|
||||
return ProcessIoctl(Context, Cmd, NvGpuGpuIoctl.ProcessIoctl);
|
||||
}
|
||||
|
||||
private static int ProcessIoctlNvHostChannel(ServiceCtx context, int cmd)
|
||||
private static int ProcessIoctlNvHostChannel(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
return ProcessIoctl(context, cmd, NvHostChannelIoctl.ProcessIoctl);
|
||||
return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctl);
|
||||
}
|
||||
|
||||
private static int ProcessIoctlNvMap(ServiceCtx context, int cmd)
|
||||
private static int ProcessIoctlNvMap(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
return ProcessIoctl(context, cmd, NvMapIoctl.ProcessIoctl);
|
||||
return ProcessIoctl(Context, Cmd, NvMapIoctl.ProcessIoctl);
|
||||
}
|
||||
|
||||
private static int ProcessIoctl(ServiceCtx context, int cmd, IoctlProcessor processor)
|
||||
private static int ProcessIoctl(ServiceCtx Context, int Cmd, IoctlProcessor Processor)
|
||||
{
|
||||
if (CmdIn(cmd) && context.Request.GetBufferType0x21().Position == 0)
|
||||
if (CmdIn(Cmd) && Context.Request.GetBufferType0x21().Position == 0)
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceNv, "Input buffer is null!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
if (CmdOut(cmd) && context.Request.GetBufferType0x22().Position == 0)
|
||||
if (CmdOut(Cmd) && Context.Request.GetBufferType0x22().Position == 0)
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceNv, "Output buffer is null!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
return processor(context, cmd);
|
||||
return Processor(Context, Cmd);
|
||||
}
|
||||
|
||||
private static bool CmdIn(int cmd)
|
||||
private static bool CmdIn(int Cmd)
|
||||
{
|
||||
return ((cmd >> 30) & 1) != 0;
|
||||
return ((Cmd >> 30) & 1) != 0;
|
||||
}
|
||||
|
||||
private static bool CmdOut(int cmd)
|
||||
private static bool CmdOut(int Cmd)
|
||||
{
|
||||
return ((cmd >> 31) & 1) != 0;
|
||||
return ((Cmd >> 31) & 1) != 0;
|
||||
}
|
||||
|
||||
public static void UnloadProcess(KProcess process)
|
||||
public static void UnloadProcess(KProcess Process)
|
||||
{
|
||||
Fds.DeleteProcess(process);
|
||||
Fds.DeleteProcess(Process);
|
||||
|
||||
NvGpuASIoctl.UnloadProcess(process);
|
||||
NvGpuASIoctl.UnloadProcess(Process);
|
||||
|
||||
NvHostChannelIoctl.UnloadProcess(process);
|
||||
NvHostChannelIoctl.UnloadProcess(Process);
|
||||
|
||||
NvHostCtrlIoctl.UnloadProcess(process);
|
||||
NvHostCtrlIoctl.UnloadProcess(Process);
|
||||
|
||||
NvMapIoctl.UnloadProcess(process);
|
||||
NvMapIoctl.UnloadProcess(Process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
{
|
||||
class NvFd
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
public NvFd(string name)
|
||||
public NvFd(string Name)
|
||||
{
|
||||
Name = name;
|
||||
this.Name = Name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,73 +5,73 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
|||
{
|
||||
class NvGpuASCtx
|
||||
{
|
||||
public NvGpuVmm Vmm { get; }
|
||||
public NvGpuVmm Vmm { get; private set; }
|
||||
|
||||
private class Range
|
||||
{
|
||||
public ulong Start { get; }
|
||||
public ulong End { get; }
|
||||
public ulong Start { get; private set; }
|
||||
public ulong End { get; private set; }
|
||||
|
||||
public Range(long position, long size)
|
||||
public Range(long Position, long Size)
|
||||
{
|
||||
Start = (ulong)position;
|
||||
End = (ulong)size + Start;
|
||||
Start = (ulong)Position;
|
||||
End = (ulong)Size + Start;
|
||||
}
|
||||
}
|
||||
|
||||
private class MappedMemory : Range
|
||||
{
|
||||
public long PhysicalAddress { get; }
|
||||
public bool VaAllocated { get; }
|
||||
public long PhysicalAddress { get; private set; }
|
||||
public bool VaAllocated { get; private set; }
|
||||
|
||||
public MappedMemory(
|
||||
long position,
|
||||
long size,
|
||||
long physicalAddress,
|
||||
bool vaAllocated) : base(position, size)
|
||||
long Position,
|
||||
long Size,
|
||||
long PhysicalAddress,
|
||||
bool VaAllocated) : base(Position, Size)
|
||||
{
|
||||
PhysicalAddress = physicalAddress;
|
||||
VaAllocated = vaAllocated;
|
||||
this.PhysicalAddress = PhysicalAddress;
|
||||
this.VaAllocated = VaAllocated;
|
||||
}
|
||||
}
|
||||
|
||||
private SortedList<long, Range> _maps;
|
||||
private SortedList<long, Range> _reservations;
|
||||
private SortedList<long, Range> Maps;
|
||||
private SortedList<long, Range> Reservations;
|
||||
|
||||
public NvGpuASCtx(ServiceCtx context)
|
||||
public NvGpuASCtx(ServiceCtx Context)
|
||||
{
|
||||
Vmm = new NvGpuVmm(context.Memory);
|
||||
Vmm = new NvGpuVmm(Context.Memory);
|
||||
|
||||
_maps = new SortedList<long, Range>();
|
||||
_reservations = new SortedList<long, Range>();
|
||||
Maps = new SortedList<long, Range>();
|
||||
Reservations = new SortedList<long, Range>();
|
||||
}
|
||||
|
||||
public bool ValidateFixedBuffer(long position, long size)
|
||||
public bool ValidateFixedBuffer(long Position, long Size)
|
||||
{
|
||||
long mapEnd = position + size;
|
||||
long MapEnd = Position + Size;
|
||||
|
||||
//Check if size is valid (0 is also not allowed).
|
||||
if ((ulong)mapEnd <= (ulong)position)
|
||||
if ((ulong)MapEnd <= (ulong)Position)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check if address is page aligned.
|
||||
if ((position & NvGpuVmm.PageMask) != 0)
|
||||
if ((Position & NvGpuVmm.PageMask) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check if region is reserved.
|
||||
if (BinarySearch(_reservations, position) == null)
|
||||
if (BinarySearch(Reservations, Position) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check for overlap with already mapped buffers.
|
||||
Range map = BinarySearchLt(_maps, mapEnd);
|
||||
Range Map = BinarySearchLt(Maps, MapEnd);
|
||||
|
||||
if (map != null && map.End > (ulong)position)
|
||||
if (Map != null && Map.End > (ulong)Position)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -80,25 +80,25 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
|||
}
|
||||
|
||||
public void AddMap(
|
||||
long position,
|
||||
long size,
|
||||
long physicalAddress,
|
||||
bool vaAllocated)
|
||||
long Position,
|
||||
long Size,
|
||||
long PhysicalAddress,
|
||||
bool VaAllocated)
|
||||
{
|
||||
_maps.Add(position, new MappedMemory(position, size, physicalAddress, vaAllocated));
|
||||
Maps.Add(Position, new MappedMemory(Position, Size, PhysicalAddress, VaAllocated));
|
||||
}
|
||||
|
||||
public bool RemoveMap(long position, out long size)
|
||||
public bool RemoveMap(long Position, out long Size)
|
||||
{
|
||||
size = 0;
|
||||
Size = 0;
|
||||
|
||||
if (_maps.Remove(position, out Range value))
|
||||
if (Maps.Remove(Position, out Range Value))
|
||||
{
|
||||
MappedMemory map = (MappedMemory)value;
|
||||
MappedMemory Map = (MappedMemory)Value;
|
||||
|
||||
if (map.VaAllocated)
|
||||
if (Map.VaAllocated)
|
||||
{
|
||||
size = (long)(map.End - map.Start);
|
||||
Size = (long)(Map.End - Map.Start);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -107,94 +107,94 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
|||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetMapPhysicalAddress(long position, out long physicalAddress)
|
||||
public bool TryGetMapPhysicalAddress(long Position, out long PhysicalAddress)
|
||||
{
|
||||
Range map = BinarySearch(_maps, position);
|
||||
Range Map = BinarySearch(Maps, Position);
|
||||
|
||||
if (map != null)
|
||||
if (Map != null)
|
||||
{
|
||||
physicalAddress = ((MappedMemory)map).PhysicalAddress;
|
||||
PhysicalAddress = ((MappedMemory)Map).PhysicalAddress;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
physicalAddress = 0;
|
||||
PhysicalAddress = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddReservation(long position, long size)
|
||||
public void AddReservation(long Position, long Size)
|
||||
{
|
||||
_reservations.Add(position, new Range(position, size));
|
||||
Reservations.Add(Position, new Range(Position, Size));
|
||||
}
|
||||
|
||||
public bool RemoveReservation(long position)
|
||||
public bool RemoveReservation(long Position)
|
||||
{
|
||||
return _reservations.Remove(position);
|
||||
return Reservations.Remove(Position);
|
||||
}
|
||||
|
||||
private Range BinarySearch(SortedList<long, Range> lst, long position)
|
||||
private Range BinarySearch(SortedList<long, Range> Lst, long Position)
|
||||
{
|
||||
int left = 0;
|
||||
int right = lst.Count - 1;
|
||||
int Left = 0;
|
||||
int Right = Lst.Count - 1;
|
||||
|
||||
while (left <= right)
|
||||
while (Left <= Right)
|
||||
{
|
||||
int size = right - left;
|
||||
int Size = Right - Left;
|
||||
|
||||
int middle = left + (size >> 1);
|
||||
int Middle = Left + (Size >> 1);
|
||||
|
||||
Range rg = lst.Values[middle];
|
||||
Range Rg = Lst.Values[Middle];
|
||||
|
||||
if ((ulong)position >= rg.Start && (ulong)position < rg.End)
|
||||
if ((ulong)Position >= Rg.Start && (ulong)Position < Rg.End)
|
||||
{
|
||||
return rg;
|
||||
return Rg;
|
||||
}
|
||||
|
||||
if ((ulong)position < rg.Start)
|
||||
if ((ulong)Position < Rg.Start)
|
||||
{
|
||||
right = middle - 1;
|
||||
Right = Middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
Left = Middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Range BinarySearchLt(SortedList<long, Range> lst, long position)
|
||||
private Range BinarySearchLt(SortedList<long, Range> Lst, long Position)
|
||||
{
|
||||
Range ltRg = null;
|
||||
Range LtRg = null;
|
||||
|
||||
int left = 0;
|
||||
int right = lst.Count - 1;
|
||||
int Left = 0;
|
||||
int Right = Lst.Count - 1;
|
||||
|
||||
while (left <= right)
|
||||
while (Left <= Right)
|
||||
{
|
||||
int size = right - left;
|
||||
int Size = Right - Left;
|
||||
|
||||
int middle = left + (size >> 1);
|
||||
int Middle = Left + (Size >> 1);
|
||||
|
||||
Range rg = lst.Values[middle];
|
||||
Range Rg = Lst.Values[Middle];
|
||||
|
||||
if ((ulong)position < rg.Start)
|
||||
if ((ulong)Position < Rg.Start)
|
||||
{
|
||||
right = middle - 1;
|
||||
Right = Middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
Left = Middle + 1;
|
||||
|
||||
if ((ulong)position > rg.Start)
|
||||
if ((ulong)Position > Rg.Start)
|
||||
{
|
||||
ltRg = rg;
|
||||
LtRg = Rg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ltRg;
|
||||
return LtRg;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,182 +14,182 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
|||
|
||||
private const int FlagRemapSubRange = 0x100;
|
||||
|
||||
private static ConcurrentDictionary<KProcess, NvGpuASCtx> _asCtxs;
|
||||
private static ConcurrentDictionary<KProcess, NvGpuASCtx> ASCtxs;
|
||||
|
||||
static NvGpuASIoctl()
|
||||
{
|
||||
_asCtxs = new ConcurrentDictionary<KProcess, NvGpuASCtx>();
|
||||
ASCtxs = new ConcurrentDictionary<KProcess, NvGpuASCtx>();
|
||||
}
|
||||
|
||||
public static int ProcessIoctl(ServiceCtx context, int cmd)
|
||||
public static int ProcessIoctl(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
switch (cmd & 0xffff)
|
||||
switch (Cmd & 0xffff)
|
||||
{
|
||||
case 0x4101: return BindChannel (context);
|
||||
case 0x4102: return AllocSpace (context);
|
||||
case 0x4103: return FreeSpace (context);
|
||||
case 0x4105: return UnmapBuffer (context);
|
||||
case 0x4106: return MapBufferEx (context);
|
||||
case 0x4108: return GetVaRegions(context);
|
||||
case 0x4109: return InitializeEx(context);
|
||||
case 0x4114: return Remap (context, cmd);
|
||||
case 0x4101: return BindChannel (Context);
|
||||
case 0x4102: return AllocSpace (Context);
|
||||
case 0x4103: return FreeSpace (Context);
|
||||
case 0x4105: return UnmapBuffer (Context);
|
||||
case 0x4106: return MapBufferEx (Context);
|
||||
case 0x4108: return GetVaRegions(Context);
|
||||
case 0x4109: return InitializeEx(Context);
|
||||
case 0x4114: return Remap (Context, Cmd);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(cmd.ToString("x8"));
|
||||
throw new NotImplementedException(Cmd.ToString("x8"));
|
||||
}
|
||||
|
||||
private static int BindChannel(ServiceCtx context)
|
||||
private static int BindChannel(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int AllocSpace(ServiceCtx context)
|
||||
private static int AllocSpace(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuASAllocSpace args = MemoryHelper.Read<NvGpuASAllocSpace>(context.Memory, inputPosition);
|
||||
NvGpuASAllocSpace Args = MemoryHelper.Read<NvGpuASAllocSpace>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuASCtx asCtx = GetASCtx(context);
|
||||
NvGpuASCtx ASCtx = GetASCtx(Context);
|
||||
|
||||
ulong size = (ulong)args.Pages *
|
||||
(ulong)args.PageSize;
|
||||
ulong Size = (ulong)Args.Pages *
|
||||
(ulong)Args.PageSize;
|
||||
|
||||
int result = NvResult.Success;
|
||||
int Result = NvResult.Success;
|
||||
|
||||
lock (asCtx)
|
||||
lock (ASCtx)
|
||||
{
|
||||
//Note: When the fixed offset flag is not set,
|
||||
//the Offset field holds the alignment size instead.
|
||||
if ((args.Flags & FlagFixedOffset) != 0)
|
||||
if ((Args.Flags & FlagFixedOffset) != 0)
|
||||
{
|
||||
args.Offset = asCtx.Vmm.ReserveFixed(args.Offset, (long)size);
|
||||
Args.Offset = ASCtx.Vmm.ReserveFixed(Args.Offset, (long)Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Offset = asCtx.Vmm.Reserve((long)size, args.Offset);
|
||||
Args.Offset = ASCtx.Vmm.Reserve((long)Size, Args.Offset);
|
||||
}
|
||||
|
||||
if (args.Offset < 0)
|
||||
if (Args.Offset < 0)
|
||||
{
|
||||
args.Offset = 0;
|
||||
Args.Offset = 0;
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {Size:x16}!");
|
||||
|
||||
result = NvResult.OutOfMemory;
|
||||
Result = NvResult.OutOfMemory;
|
||||
}
|
||||
else
|
||||
{
|
||||
asCtx.AddReservation(args.Offset, (long)size);
|
||||
ASCtx.AddReservation(Args.Offset, (long)Size);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static int FreeSpace(ServiceCtx context)
|
||||
private static int FreeSpace(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuASAllocSpace args = MemoryHelper.Read<NvGpuASAllocSpace>(context.Memory, inputPosition);
|
||||
NvGpuASAllocSpace Args = MemoryHelper.Read<NvGpuASAllocSpace>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuASCtx asCtx = GetASCtx(context);
|
||||
NvGpuASCtx ASCtx = GetASCtx(Context);
|
||||
|
||||
int result = NvResult.Success;
|
||||
int Result = NvResult.Success;
|
||||
|
||||
lock (asCtx)
|
||||
lock (ASCtx)
|
||||
{
|
||||
ulong size = (ulong)args.Pages *
|
||||
(ulong)args.PageSize;
|
||||
ulong Size = (ulong)Args.Pages *
|
||||
(ulong)Args.PageSize;
|
||||
|
||||
if (asCtx.RemoveReservation(args.Offset))
|
||||
if (ASCtx.RemoveReservation(Args.Offset))
|
||||
{
|
||||
asCtx.Vmm.Free(args.Offset, (long)size);
|
||||
ASCtx.Vmm.Free(Args.Offset, (long)Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv,
|
||||
$"Failed to free offset 0x{args.Offset:x16} size 0x{size:x16}!");
|
||||
$"Failed to free offset 0x{Args.Offset:x16} size 0x{Size:x16}!");
|
||||
|
||||
result = NvResult.InvalidInput;
|
||||
Result = NvResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static int UnmapBuffer(ServiceCtx context)
|
||||
private static int UnmapBuffer(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuASUnmapBuffer args = MemoryHelper.Read<NvGpuASUnmapBuffer>(context.Memory, inputPosition);
|
||||
NvGpuASUnmapBuffer Args = MemoryHelper.Read<NvGpuASUnmapBuffer>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuASCtx asCtx = GetASCtx(context);
|
||||
NvGpuASCtx ASCtx = GetASCtx(Context);
|
||||
|
||||
lock (asCtx)
|
||||
lock (ASCtx)
|
||||
{
|
||||
if (asCtx.RemoveMap(args.Offset, out long size))
|
||||
if (ASCtx.RemoveMap(Args.Offset, out long Size))
|
||||
{
|
||||
if (size != 0)
|
||||
if (Size != 0)
|
||||
{
|
||||
asCtx.Vmm.Free(args.Offset, size);
|
||||
ASCtx.Vmm.Free(Args.Offset, Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {args.Offset:x16}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {Args.Offset:x16}!");
|
||||
}
|
||||
}
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int MapBufferEx(ServiceCtx context)
|
||||
private static int MapBufferEx(ServiceCtx Context)
|
||||
{
|
||||
const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!";
|
||||
const string MapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!";
|
||||
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuASMapBufferEx args = MemoryHelper.Read<NvGpuASMapBufferEx>(context.Memory, inputPosition);
|
||||
NvGpuASMapBufferEx Args = MemoryHelper.Read<NvGpuASMapBufferEx>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuASCtx asCtx = GetASCtx(context);
|
||||
NvGpuASCtx ASCtx = GetASCtx(Context);
|
||||
|
||||
NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle);
|
||||
NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
long pa;
|
||||
long PA;
|
||||
|
||||
if ((args.Flags & FlagRemapSubRange) != 0)
|
||||
if ((Args.Flags & FlagRemapSubRange) != 0)
|
||||
{
|
||||
lock (asCtx)
|
||||
lock (ASCtx)
|
||||
{
|
||||
if (asCtx.TryGetMapPhysicalAddress(args.Offset, out pa))
|
||||
if (ASCtx.TryGetMapPhysicalAddress(Args.Offset, out PA))
|
||||
{
|
||||
long va = args.Offset + args.BufferOffset;
|
||||
long VA = Args.Offset + Args.BufferOffset;
|
||||
|
||||
pa += args.BufferOffset;
|
||||
PA += Args.BufferOffset;
|
||||
|
||||
if (asCtx.Vmm.Map(pa, va, args.MappingSize) < 0)
|
||||
if (ASCtx.Vmm.Map(PA, VA, Args.MappingSize) < 0)
|
||||
{
|
||||
string msg = string.Format(mapErrorMsg, va, args.MappingSize);
|
||||
string Msg = string.Format(MapErrorMsg, VA, Args.MappingSize);
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, msg);
|
||||
Logger.PrintWarning(LogClass.ServiceNv, Msg);
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
@ -198,117 +198,117 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
|||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{args.Offset:x16} not mapped!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{Args.Offset:x16} not mapped!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pa = map.Address + args.BufferOffset;
|
||||
PA = Map.Address + Args.BufferOffset;
|
||||
|
||||
long size = args.MappingSize;
|
||||
long Size = Args.MappingSize;
|
||||
|
||||
if (size == 0)
|
||||
if (Size == 0)
|
||||
{
|
||||
size = (uint)map.Size;
|
||||
Size = (uint)Map.Size;
|
||||
}
|
||||
|
||||
int result = NvResult.Success;
|
||||
int Result = NvResult.Success;
|
||||
|
||||
lock (asCtx)
|
||||
lock (ASCtx)
|
||||
{
|
||||
//Note: When the fixed offset flag is not set,
|
||||
//the Offset field holds the alignment size instead.
|
||||
bool vaAllocated = (args.Flags & FlagFixedOffset) == 0;
|
||||
bool VaAllocated = (Args.Flags & FlagFixedOffset) == 0;
|
||||
|
||||
if (!vaAllocated)
|
||||
if (!VaAllocated)
|
||||
{
|
||||
if (asCtx.ValidateFixedBuffer(args.Offset, size))
|
||||
if (ASCtx.ValidateFixedBuffer(Args.Offset, Size))
|
||||
{
|
||||
args.Offset = asCtx.Vmm.Map(pa, args.Offset, size);
|
||||
Args.Offset = ASCtx.Vmm.Map(PA, Args.Offset, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = string.Format(mapErrorMsg, args.Offset, size);
|
||||
string Msg = string.Format(MapErrorMsg, Args.Offset, Size);
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, msg);
|
||||
Logger.PrintWarning(LogClass.ServiceNv, Msg);
|
||||
|
||||
result = NvResult.InvalidInput;
|
||||
Result = NvResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Offset = asCtx.Vmm.Map(pa, size);
|
||||
Args.Offset = ASCtx.Vmm.Map(PA, Size);
|
||||
}
|
||||
|
||||
if (args.Offset < 0)
|
||||
if (Args.Offset < 0)
|
||||
{
|
||||
args.Offset = 0;
|
||||
Args.Offset = 0;
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{Size:x16}!");
|
||||
|
||||
result = NvResult.InvalidInput;
|
||||
Result = NvResult.InvalidInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
asCtx.AddMap(args.Offset, size, pa, vaAllocated);
|
||||
ASCtx.AddMap(Args.Offset, Size, PA, VaAllocated);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static int GetVaRegions(ServiceCtx context)
|
||||
private static int GetVaRegions(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int InitializeEx(ServiceCtx context)
|
||||
private static int InitializeEx(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int Remap(ServiceCtx context, int cmd)
|
||||
private static int Remap(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
int count = ((cmd >> 16) & 0xff) / 0x14;
|
||||
int Count = ((Cmd >> 16) & 0xff) / 0x14;
|
||||
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
|
||||
for (int index = 0; index < count; index++, inputPosition += 0x14)
|
||||
for (int Index = 0; Index < Count; Index++, InputPosition += 0x14)
|
||||
{
|
||||
NvGpuASRemap args = MemoryHelper.Read<NvGpuASRemap>(context.Memory, inputPosition);
|
||||
NvGpuASRemap Args = MemoryHelper.Read<NvGpuASRemap>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuVmm vmm = GetASCtx(context).Vmm;
|
||||
NvGpuVmm Vmm = GetASCtx(Context).Vmm;
|
||||
|
||||
NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle);
|
||||
NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
long result = vmm.Map(map.Address, (long)(uint)args.Offset << 16,
|
||||
(long)(uint)args.Pages << 16);
|
||||
long Result = Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16,
|
||||
(long)(uint)Args.Pages << 16);
|
||||
|
||||
if (result < 0)
|
||||
if (Result < 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv,
|
||||
$"Page 0x{args.Offset:x16} size 0x{args.Pages:x16} not allocated!");
|
||||
$"Page 0x{Args.Offset:x16} size 0x{Args.Pages:x16} not allocated!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
@ -317,14 +317,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
|||
return NvResult.Success;
|
||||
}
|
||||
|
||||
public static NvGpuASCtx GetASCtx(ServiceCtx context)
|
||||
public static NvGpuASCtx GetASCtx(ServiceCtx Context)
|
||||
{
|
||||
return _asCtxs.GetOrAdd(context.Process, (key) => new NvGpuASCtx(context));
|
||||
return ASCtxs.GetOrAdd(Context.Process, (Key) => new NvGpuASCtx(Context));
|
||||
}
|
||||
|
||||
public static void UnloadProcess(KProcess process)
|
||||
public static void UnloadProcess(KProcess Process)
|
||||
{
|
||||
_asCtxs.TryRemove(process, out _);
|
||||
ASCtxs.TryRemove(Process, out _);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,181 +7,181 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuGpu
|
|||
{
|
||||
class NvGpuGpuIoctl
|
||||
{
|
||||
private static Stopwatch _pTimer;
|
||||
private static Stopwatch PTimer;
|
||||
|
||||
private static double _ticksToNs;
|
||||
private static double TicksToNs;
|
||||
|
||||
static NvGpuGpuIoctl()
|
||||
{
|
||||
_pTimer = new Stopwatch();
|
||||
PTimer = new Stopwatch();
|
||||
|
||||
_pTimer.Start();
|
||||
PTimer.Start();
|
||||
|
||||
_ticksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000;
|
||||
TicksToNs = (1.0 / Stopwatch.Frequency) * 1_000_000_000;
|
||||
}
|
||||
|
||||
public static int ProcessIoctl(ServiceCtx context, int cmd)
|
||||
public static int ProcessIoctl(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
switch (cmd & 0xffff)
|
||||
switch (Cmd & 0xffff)
|
||||
{
|
||||
case 0x4701: return ZcullGetCtxSize (context);
|
||||
case 0x4702: return ZcullGetInfo (context);
|
||||
case 0x4703: return ZbcSetTable (context);
|
||||
case 0x4705: return GetCharacteristics(context);
|
||||
case 0x4706: return GetTpcMasks (context);
|
||||
case 0x4714: return GetActiveSlotMask (context);
|
||||
case 0x471c: return GetGpuTime (context);
|
||||
case 0x4701: return ZcullGetCtxSize (Context);
|
||||
case 0x4702: return ZcullGetInfo (Context);
|
||||
case 0x4703: return ZbcSetTable (Context);
|
||||
case 0x4705: return GetCharacteristics(Context);
|
||||
case 0x4706: return GetTpcMasks (Context);
|
||||
case 0x4714: return GetActiveSlotMask (Context);
|
||||
case 0x471c: return GetGpuTime (Context);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(cmd.ToString("x8"));
|
||||
throw new NotImplementedException(Cmd.ToString("x8"));
|
||||
}
|
||||
|
||||
private static int ZcullGetCtxSize(ServiceCtx context)
|
||||
private static int ZcullGetCtxSize(ServiceCtx Context)
|
||||
{
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuGpuZcullGetCtxSize args = new NvGpuGpuZcullGetCtxSize();
|
||||
NvGpuGpuZcullGetCtxSize Args = new NvGpuGpuZcullGetCtxSize();
|
||||
|
||||
args.Size = 1;
|
||||
Args.Size = 1;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int ZcullGetInfo(ServiceCtx context)
|
||||
private static int ZcullGetInfo(ServiceCtx Context)
|
||||
{
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuGpuZcullGetInfo args = new NvGpuGpuZcullGetInfo();
|
||||
NvGpuGpuZcullGetInfo Args = new NvGpuGpuZcullGetInfo();
|
||||
|
||||
args.WidthAlignPixels = 0x20;
|
||||
args.HeightAlignPixels = 0x20;
|
||||
args.PixelSquaresByAliquots = 0x400;
|
||||
args.AliquotTotal = 0x800;
|
||||
args.RegionByteMultiplier = 0x20;
|
||||
args.RegionHeaderSize = 0x20;
|
||||
args.SubregionHeaderSize = 0xc0;
|
||||
args.SubregionWidthAlignPixels = 0x20;
|
||||
args.SubregionHeightAlignPixels = 0x40;
|
||||
args.SubregionCount = 0x10;
|
||||
Args.WidthAlignPixels = 0x20;
|
||||
Args.HeightAlignPixels = 0x20;
|
||||
Args.PixelSquaresByAliquots = 0x400;
|
||||
Args.AliquotTotal = 0x800;
|
||||
Args.RegionByteMultiplier = 0x20;
|
||||
Args.RegionHeaderSize = 0x20;
|
||||
Args.SubregionHeaderSize = 0xc0;
|
||||
Args.SubregionWidthAlignPixels = 0x20;
|
||||
Args.SubregionHeightAlignPixels = 0x40;
|
||||
Args.SubregionCount = 0x10;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int ZbcSetTable(ServiceCtx context)
|
||||
private static int ZbcSetTable(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetCharacteristics(ServiceCtx context)
|
||||
private static int GetCharacteristics(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuGpuGetCharacteristics args = MemoryHelper.Read<NvGpuGpuGetCharacteristics>(context.Memory, inputPosition);
|
||||
NvGpuGpuGetCharacteristics Args = MemoryHelper.Read<NvGpuGpuGetCharacteristics>(Context.Memory, InputPosition);
|
||||
|
||||
args.BufferSize = 0xa0;
|
||||
Args.BufferSize = 0xa0;
|
||||
|
||||
args.Arch = 0x120;
|
||||
args.Impl = 0xb;
|
||||
args.Rev = 0xa1;
|
||||
args.NumGpc = 0x1;
|
||||
args.L2CacheSize = 0x40000;
|
||||
args.OnBoardVideoMemorySize = 0x0;
|
||||
args.NumTpcPerGpc = 0x2;
|
||||
args.BusType = 0x20;
|
||||
args.BigPageSize = 0x20000;
|
||||
args.CompressionPageSize = 0x20000;
|
||||
args.PdeCoverageBitCount = 0x1b;
|
||||
args.AvailableBigPageSizes = 0x30000;
|
||||
args.GpcMask = 0x1;
|
||||
args.SmArchSmVersion = 0x503;
|
||||
args.SmArchSpaVersion = 0x503;
|
||||
args.SmArchWarpCount = 0x80;
|
||||
args.GpuVaBitCount = 0x28;
|
||||
args.Reserved = 0x0;
|
||||
args.Flags = 0x55;
|
||||
args.TwodClass = 0x902d;
|
||||
args.ThreedClass = 0xb197;
|
||||
args.ComputeClass = 0xb1c0;
|
||||
args.GpfifoClass = 0xb06f;
|
||||
args.InlineToMemoryClass = 0xa140;
|
||||
args.DmaCopyClass = 0xb0b5;
|
||||
args.MaxFbpsCount = 0x1;
|
||||
args.FbpEnMask = 0x0;
|
||||
args.MaxLtcPerFbp = 0x2;
|
||||
args.MaxLtsPerLtc = 0x1;
|
||||
args.MaxTexPerTpc = 0x0;
|
||||
args.MaxGpcCount = 0x1;
|
||||
args.RopL2EnMask0 = 0x21d70;
|
||||
args.RopL2EnMask1 = 0x0;
|
||||
args.ChipName = 0x6230326d67;
|
||||
args.GrCompbitStoreBaseHw = 0x0;
|
||||
Args.Arch = 0x120;
|
||||
Args.Impl = 0xb;
|
||||
Args.Rev = 0xa1;
|
||||
Args.NumGpc = 0x1;
|
||||
Args.L2CacheSize = 0x40000;
|
||||
Args.OnBoardVideoMemorySize = 0x0;
|
||||
Args.NumTpcPerGpc = 0x2;
|
||||
Args.BusType = 0x20;
|
||||
Args.BigPageSize = 0x20000;
|
||||
Args.CompressionPageSize = 0x20000;
|
||||
Args.PdeCoverageBitCount = 0x1b;
|
||||
Args.AvailableBigPageSizes = 0x30000;
|
||||
Args.GpcMask = 0x1;
|
||||
Args.SmArchSmVersion = 0x503;
|
||||
Args.SmArchSpaVersion = 0x503;
|
||||
Args.SmArchWarpCount = 0x80;
|
||||
Args.GpuVaBitCount = 0x28;
|
||||
Args.Reserved = 0x0;
|
||||
Args.Flags = 0x55;
|
||||
Args.TwodClass = 0x902d;
|
||||
Args.ThreedClass = 0xb197;
|
||||
Args.ComputeClass = 0xb1c0;
|
||||
Args.GpfifoClass = 0xb06f;
|
||||
Args.InlineToMemoryClass = 0xa140;
|
||||
Args.DmaCopyClass = 0xb0b5;
|
||||
Args.MaxFbpsCount = 0x1;
|
||||
Args.FbpEnMask = 0x0;
|
||||
Args.MaxLtcPerFbp = 0x2;
|
||||
Args.MaxLtsPerLtc = 0x1;
|
||||
Args.MaxTexPerTpc = 0x0;
|
||||
Args.MaxGpcCount = 0x1;
|
||||
Args.RopL2EnMask0 = 0x21d70;
|
||||
Args.RopL2EnMask1 = 0x0;
|
||||
Args.ChipName = 0x6230326d67;
|
||||
Args.GrCompbitStoreBaseHw = 0x0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetTpcMasks(ServiceCtx context)
|
||||
private static int GetTpcMasks(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuGpuGetTpcMasks args = MemoryHelper.Read<NvGpuGpuGetTpcMasks>(context.Memory, inputPosition);
|
||||
NvGpuGpuGetTpcMasks Args = MemoryHelper.Read<NvGpuGpuGetTpcMasks>(Context.Memory, InputPosition);
|
||||
|
||||
if (args.MaskBufferSize != 0)
|
||||
if (Args.MaskBufferSize != 0)
|
||||
{
|
||||
args.TpcMask = 3;
|
||||
Args.TpcMask = 3;
|
||||
}
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetActiveSlotMask(ServiceCtx context)
|
||||
private static int GetActiveSlotMask(ServiceCtx Context)
|
||||
{
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvGpuGpuGetActiveSlotMask args = new NvGpuGpuGetActiveSlotMask();
|
||||
NvGpuGpuGetActiveSlotMask Args = new NvGpuGpuGetActiveSlotMask();
|
||||
|
||||
args.Slot = 0x07;
|
||||
args.Mask = 0x01;
|
||||
Args.Slot = 0x07;
|
||||
Args.Mask = 0x01;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetGpuTime(ServiceCtx context)
|
||||
private static int GetGpuTime(ServiceCtx Context)
|
||||
{
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
context.Memory.WriteInt64(outputPosition, GetPTimerNanoSeconds());
|
||||
Context.Memory.WriteInt64(OutputPosition, GetPTimerNanoSeconds());
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static long GetPTimerNanoSeconds()
|
||||
{
|
||||
double ticks = _pTimer.ElapsedTicks;
|
||||
double Ticks = PTimer.ElapsedTicks;
|
||||
|
||||
return (long)(ticks * _ticksToNs) & 0xff_ffff_ffff_ffff;
|
||||
return (long)(Ticks * TicksToNs) & 0xff_ffff_ffff_ffff;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,57 +11,62 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel
|
|||
{
|
||||
class NvHostChannelIoctl
|
||||
{
|
||||
private static ConcurrentDictionary<KProcess, NvChannel> _channels;
|
||||
private static ConcurrentDictionary<KProcess, NvChannel> Channels;
|
||||
|
||||
static NvHostChannelIoctl()
|
||||
{
|
||||
_channels = new ConcurrentDictionary<KProcess, NvChannel>();
|
||||
Channels = new ConcurrentDictionary<KProcess, NvChannel>();
|
||||
}
|
||||
|
||||
public static int ProcessIoctl(ServiceCtx context, int cmd)
|
||||
public static int ProcessIoctl(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
switch (cmd & 0xffff)
|
||||
switch (Cmd & 0xffff)
|
||||
{
|
||||
case 0x0001: return Submit (context);
|
||||
case 0x0002: return GetSyncpoint (context);
|
||||
case 0x0003: return GetWaitBase (context);
|
||||
case 0x0009: return MapBuffer (context);
|
||||
case 0x000a: return UnmapBuffer (context);
|
||||
case 0x480b: return ZcullBind (context);
|
||||
case 0x480c: return SetErrorNotifier (context);
|
||||
case 0x4803: return SetTimeout (context);
|
||||
case 0x481a: return AllocGpfifoEx2 (context);
|
||||
case 0x481b: return KickoffPbWithAttr(context);
|
||||
case 0x0001: return Submit (Context);
|
||||
case 0x0002: return GetSyncpoint (Context);
|
||||
case 0x0003: return GetWaitBase (Context);
|
||||
case 0x0009: return MapBuffer (Context);
|
||||
case 0x000a: return UnmapBuffer (Context);
|
||||
case 0x4714: return SetUserData (Context);
|
||||
case 0x4801: return SetNvMap (Context);
|
||||
case 0x4803: return SetTimeout (Context);
|
||||
case 0x4808: return SubmitGpfifo (Context);
|
||||
case 0x4809: return AllocObjCtx (Context);
|
||||
case 0x480b: return ZcullBind (Context);
|
||||
case 0x480c: return SetErrorNotifier (Context);
|
||||
case 0x480d: return SetPriority (Context);
|
||||
case 0x481a: return AllocGpfifoEx2 (Context);
|
||||
case 0x481b: return KickoffPbWithAttr(Context);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(cmd.ToString("x8"));
|
||||
throw new NotImplementedException(Cmd.ToString("x8"));
|
||||
}
|
||||
|
||||
private static int Submit(ServiceCtx context)
|
||||
private static int Submit(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelSubmit args = MemoryHelper.Read<NvHostChannelSubmit>(context.Memory, inputPosition);
|
||||
NvHostChannelSubmit Args = MemoryHelper.Read<NvHostChannelSubmit>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;
|
||||
|
||||
for (int index = 0; index < args.CmdBufsCount; index++)
|
||||
for (int Index = 0; Index < Args.CmdBufsCount; Index++)
|
||||
{
|
||||
long cmdBufOffset = inputPosition + 0x10 + index * 0xc;
|
||||
long CmdBufOffset = InputPosition + 0x10 + Index * 0xc;
|
||||
|
||||
NvHostChannelCmdBuf cmdBuf = MemoryHelper.Read<NvHostChannelCmdBuf>(context.Memory, cmdBufOffset);
|
||||
NvHostChannelCmdBuf CmdBuf = MemoryHelper.Read<NvHostChannelCmdBuf>(Context.Memory, CmdBufOffset);
|
||||
|
||||
NvMapHandle map = NvMapIoctl.GetNvMap(context, cmdBuf.MemoryId);
|
||||
NvMapHandle Map = NvMapIoctl.GetNvMap(Context, CmdBuf.MemoryId);
|
||||
|
||||
int[] cmdBufData = new int[cmdBuf.WordsCount];
|
||||
int[] CmdBufData = new int[CmdBuf.WordsCount];
|
||||
|
||||
for (int offset = 0; offset < cmdBufData.Length; offset++)
|
||||
for (int Offset = 0; Offset < CmdBufData.Length; Offset++)
|
||||
{
|
||||
cmdBufData[offset] = context.Memory.ReadInt32(map.Address + cmdBuf.Offset + offset * 4);
|
||||
CmdBufData[Offset] = Context.Memory.ReadInt32(Map.Address + CmdBuf.Offset + Offset * 4);
|
||||
}
|
||||
|
||||
context.Device.Gpu.PushCommandBuffer(vmm, cmdBufData);
|
||||
Context.Device.Gpu.PushCommandBuffer(Vmm, CmdBufData);
|
||||
}
|
||||
|
||||
//TODO: Relocation, waitchecks, etc.
|
||||
|
@ -69,99 +74,99 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel
|
|||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetSyncpoint(ServiceCtx context)
|
||||
private static int GetSyncpoint(ServiceCtx Context)
|
||||
{
|
||||
//TODO
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelGetParamArg args = MemoryHelper.Read<NvHostChannelGetParamArg>(context.Memory, inputPosition);
|
||||
NvHostChannelGetParamArg Args = MemoryHelper.Read<NvHostChannelGetParamArg>(Context.Memory, InputPosition);
|
||||
|
||||
args.Value = 0;
|
||||
Args.Value = 0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetWaitBase(ServiceCtx context)
|
||||
private static int GetWaitBase(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelGetParamArg args = MemoryHelper.Read<NvHostChannelGetParamArg>(context.Memory, inputPosition);
|
||||
NvHostChannelGetParamArg Args = MemoryHelper.Read<NvHostChannelGetParamArg>(Context.Memory, InputPosition);
|
||||
|
||||
args.Value = 0;
|
||||
Args.Value = 0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int MapBuffer(ServiceCtx context)
|
||||
private static int MapBuffer(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelMapBuffer args = MemoryHelper.Read<NvHostChannelMapBuffer>(context.Memory, inputPosition);
|
||||
NvHostChannelMapBuffer Args = MemoryHelper.Read<NvHostChannelMapBuffer>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;
|
||||
|
||||
for (int index = 0; index < args.NumEntries; index++)
|
||||
for (int Index = 0; Index < Args.NumEntries; Index++)
|
||||
{
|
||||
int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8);
|
||||
int Handle = Context.Memory.ReadInt32(InputPosition + 0xc + Index * 8);
|
||||
|
||||
NvMapHandle map = NvMapIoctl.GetNvMap(context, handle);
|
||||
NvMapHandle Map = NvMapIoctl.GetNvMap(Context, Handle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
lock (map)
|
||||
lock (Map)
|
||||
{
|
||||
if (map.DmaMapAddress == 0)
|
||||
if (Map.DmaMapAddress == 0)
|
||||
{
|
||||
map.DmaMapAddress = vmm.MapLow(map.Address, map.Size);
|
||||
Map.DmaMapAddress = Vmm.MapLow(Map.Address, Map.Size);
|
||||
}
|
||||
|
||||
context.Memory.WriteInt32(outputPosition + 0xc + 4 + index * 8, (int)map.DmaMapAddress);
|
||||
Context.Memory.WriteInt32(OutputPosition + 0xc + 4 + Index * 8, (int)Map.DmaMapAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int UnmapBuffer(ServiceCtx context)
|
||||
private static int UnmapBuffer(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
|
||||
NvHostChannelMapBuffer args = MemoryHelper.Read<NvHostChannelMapBuffer>(context.Memory, inputPosition);
|
||||
NvHostChannelMapBuffer Args = MemoryHelper.Read<NvHostChannelMapBuffer>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;
|
||||
|
||||
for (int index = 0; index < args.NumEntries; index++)
|
||||
for (int Index = 0; Index < Args.NumEntries; Index++)
|
||||
{
|
||||
int handle = context.Memory.ReadInt32(inputPosition + 0xc + index * 8);
|
||||
int Handle = Context.Memory.ReadInt32(InputPosition + 0xc + Index * 8);
|
||||
|
||||
NvMapHandle map = NvMapIoctl.GetNvMap(context, handle);
|
||||
NvMapHandle Map = NvMapIoctl.GetNvMap(Context, Handle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
lock (map)
|
||||
lock (Map)
|
||||
{
|
||||
if (map.DmaMapAddress != 0)
|
||||
if (Map.DmaMapAddress != 0)
|
||||
{
|
||||
vmm.Free(map.DmaMapAddress, map.Size);
|
||||
Vmm.Free(Map.DmaMapAddress, Map.Size);
|
||||
|
||||
map.DmaMapAddress = 0;
|
||||
Map.DmaMapAddress = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,146 +174,146 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel
|
|||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetUserData(ServiceCtx context)
|
||||
private static int SetUserData(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetNvMap(ServiceCtx context)
|
||||
private static int SetNvMap(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetTimeout(ServiceCtx context)
|
||||
private static int SetTimeout(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
|
||||
GetChannel(context).Timeout = context.Memory.ReadInt32(inputPosition);
|
||||
GetChannel(Context).Timeout = Context.Memory.ReadInt32(InputPosition);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SubmitGpfifo(ServiceCtx context)
|
||||
private static int SubmitGpfifo(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelSubmitGpfifo args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(context.Memory, inputPosition);
|
||||
NvHostChannelSubmitGpfifo Args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;;
|
||||
|
||||
for (int index = 0; index < args.NumEntries; index++)
|
||||
for (int Index = 0; Index < Args.NumEntries; Index++)
|
||||
{
|
||||
long gpfifo = context.Memory.ReadInt64(inputPosition + 0x18 + index * 8);
|
||||
long Gpfifo = Context.Memory.ReadInt64(InputPosition + 0x18 + Index * 8);
|
||||
|
||||
PushGpfifo(context, vmm, gpfifo);
|
||||
PushGpfifo(Context, Vmm, Gpfifo);
|
||||
}
|
||||
|
||||
args.SyncptId = 0;
|
||||
args.SyncptValue = 0;
|
||||
Args.SyncptId = 0;
|
||||
Args.SyncptValue = 0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int AllocObjCtx(ServiceCtx context)
|
||||
private static int AllocObjCtx(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int ZcullBind(ServiceCtx context)
|
||||
private static int ZcullBind(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetErrorNotifier(ServiceCtx context)
|
||||
private static int SetErrorNotifier(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetPriority(ServiceCtx context)
|
||||
private static int SetPriority(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int AllocGpfifoEx2(ServiceCtx context)
|
||||
private static int AllocGpfifoEx2(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int KickoffPbWithAttr(ServiceCtx context)
|
||||
private static int KickoffPbWithAttr(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelSubmitGpfifo args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(context.Memory, inputPosition);
|
||||
NvHostChannelSubmitGpfifo Args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(Context.Memory, InputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;;
|
||||
|
||||
for (int index = 0; index < args.NumEntries; index++)
|
||||
for (int Index = 0; Index < Args.NumEntries; Index++)
|
||||
{
|
||||
long gpfifo = context.Memory.ReadInt64(args.Address + index * 8);
|
||||
long Gpfifo = Context.Memory.ReadInt64(Args.Address + Index * 8);
|
||||
|
||||
PushGpfifo(context, vmm, gpfifo);
|
||||
PushGpfifo(Context, Vmm, Gpfifo);
|
||||
}
|
||||
|
||||
args.SyncptId = 0;
|
||||
args.SyncptValue = 0;
|
||||
Args.SyncptId = 0;
|
||||
Args.SyncptValue = 0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static void PushGpfifo(ServiceCtx context, NvGpuVmm vmm, long gpfifo)
|
||||
private static void PushGpfifo(ServiceCtx Context, NvGpuVmm Vmm, long Gpfifo)
|
||||
{
|
||||
context.Device.Gpu.Pusher.Push(vmm, gpfifo);
|
||||
Context.Device.Gpu.Pusher.Push(Vmm, Gpfifo);
|
||||
}
|
||||
|
||||
public static NvChannel GetChannel(ServiceCtx context)
|
||||
public static NvChannel GetChannel(ServiceCtx Context)
|
||||
{
|
||||
return _channels.GetOrAdd(context.Process, (key) => new NvChannel());
|
||||
return Channels.GetOrAdd(Context.Process, (Key) => new NvChannel());
|
||||
}
|
||||
|
||||
public static void UnloadProcess(KProcess process)
|
||||
public static void UnloadProcess(KProcess Process)
|
||||
{
|
||||
_channels.TryRemove(process, out _);
|
||||
Channels.TryRemove(Process, out _);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,116 +10,116 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl
|
|||
{
|
||||
class NvHostCtrlIoctl
|
||||
{
|
||||
private static ConcurrentDictionary<KProcess, NvHostCtrlUserCtx> _userCtxs;
|
||||
private static ConcurrentDictionary<KProcess, NvHostCtrlUserCtx> UserCtxs;
|
||||
|
||||
private static bool _isProductionMode = true;
|
||||
private static bool IsProductionMode = true;
|
||||
|
||||
static NvHostCtrlIoctl()
|
||||
{
|
||||
_userCtxs = new ConcurrentDictionary<KProcess, NvHostCtrlUserCtx>();
|
||||
UserCtxs = new ConcurrentDictionary<KProcess, NvHostCtrlUserCtx>();
|
||||
|
||||
if (Set.NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object productionModeSetting))
|
||||
if (Set.NxSettings.Settings.TryGetValue("nv!rmos_set_production_mode", out object ProductionModeSetting))
|
||||
{
|
||||
_isProductionMode = ((string)productionModeSetting) != "0"; // Default value is ""
|
||||
IsProductionMode = ((string)ProductionModeSetting) != "0"; // Default value is ""
|
||||
}
|
||||
}
|
||||
|
||||
public static int ProcessIoctl(ServiceCtx context, int cmd)
|
||||
public static int ProcessIoctl(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
switch (cmd & 0xffff)
|
||||
switch (Cmd & 0xffff)
|
||||
{
|
||||
case 0x0014: return SyncptRead (context);
|
||||
case 0x0015: return SyncptIncr (context);
|
||||
case 0x0016: return SyncptWait (context);
|
||||
case 0x0019: return SyncptWaitEx (context);
|
||||
case 0x001a: return SyncptReadMax (context);
|
||||
case 0x001b: return GetConfig (context);
|
||||
case 0x001d: return EventWait (context);
|
||||
case 0x001e: return EventWaitAsync(context);
|
||||
case 0x001f: return EventRegister (context);
|
||||
case 0x0014: return SyncptRead (Context);
|
||||
case 0x0015: return SyncptIncr (Context);
|
||||
case 0x0016: return SyncptWait (Context);
|
||||
case 0x0019: return SyncptWaitEx (Context);
|
||||
case 0x001a: return SyncptReadMax (Context);
|
||||
case 0x001b: return GetConfig (Context);
|
||||
case 0x001d: return EventWait (Context);
|
||||
case 0x001e: return EventWaitAsync(Context);
|
||||
case 0x001f: return EventRegister (Context);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(cmd.ToString("x8"));
|
||||
throw new NotImplementedException(Cmd.ToString("x8"));
|
||||
}
|
||||
|
||||
private static int SyncptRead(ServiceCtx context)
|
||||
private static int SyncptRead(ServiceCtx Context)
|
||||
{
|
||||
return SyncptReadMinOrMax(context, max: false);
|
||||
return SyncptReadMinOrMax(Context, Max: false);
|
||||
}
|
||||
|
||||
private static int SyncptIncr(ServiceCtx context)
|
||||
private static int SyncptIncr(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
|
||||
int id = context.Memory.ReadInt32(inputPosition);
|
||||
int Id = Context.Memory.ReadInt32(InputPosition);
|
||||
|
||||
if ((uint)id >= NvHostSyncpt.SyncptsCount)
|
||||
if ((uint)Id >= NvHostSyncpt.SyncptsCount)
|
||||
{
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
GetUserCtx(context).Syncpt.Increment(id);
|
||||
GetUserCtx(Context).Syncpt.Increment(Id);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SyncptWait(ServiceCtx context)
|
||||
private static int SyncptWait(ServiceCtx Context)
|
||||
{
|
||||
return SyncptWait(context, extended: false);
|
||||
return SyncptWait(Context, Extended: false);
|
||||
}
|
||||
|
||||
private static int SyncptWaitEx(ServiceCtx context)
|
||||
private static int SyncptWaitEx(ServiceCtx Context)
|
||||
{
|
||||
return SyncptWait(context, extended: true);
|
||||
return SyncptWait(Context, Extended: true);
|
||||
}
|
||||
|
||||
private static int SyncptReadMax(ServiceCtx context)
|
||||
private static int SyncptReadMax(ServiceCtx Context)
|
||||
{
|
||||
return SyncptReadMinOrMax(context, max: true);
|
||||
return SyncptReadMinOrMax(Context, Max: true);
|
||||
}
|
||||
|
||||
private static int GetConfig(ServiceCtx context)
|
||||
private static int GetConfig(ServiceCtx Context)
|
||||
{
|
||||
if (!_isProductionMode)
|
||||
if (!IsProductionMode)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
string domain = MemoryHelper.ReadAsciiString(context.Memory, inputPosition + 0, 0x41);
|
||||
string name = MemoryHelper.ReadAsciiString(context.Memory, inputPosition + 0x41, 0x41);
|
||||
string Domain = MemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0, 0x41);
|
||||
string Name = MemoryHelper.ReadAsciiString(Context.Memory, InputPosition + 0x41, 0x41);
|
||||
|
||||
if (Set.NxSettings.Settings.TryGetValue($"{domain}!{name}", out object nvSetting))
|
||||
if (Set.NxSettings.Settings.TryGetValue($"{Domain}!{Name}", out object NvSetting))
|
||||
{
|
||||
byte[] settingBuffer = new byte[0x101];
|
||||
byte[] SettingBuffer = new byte[0x101];
|
||||
|
||||
if (nvSetting is string stringValue)
|
||||
if (NvSetting is string StringValue)
|
||||
{
|
||||
if (stringValue.Length > 0x100)
|
||||
if (StringValue.Length > 0x100)
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceNv, $"{domain}!{name} String value size is too big!");
|
||||
Logger.PrintError(LogClass.ServiceNv, $"{Domain}!{Name} String value size is too big!");
|
||||
}
|
||||
else
|
||||
{
|
||||
settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0");
|
||||
SettingBuffer = Encoding.ASCII.GetBytes(StringValue + "\0");
|
||||
}
|
||||
}
|
||||
|
||||
if (nvSetting is int intValue)
|
||||
if (NvSetting is int IntValue)
|
||||
{
|
||||
settingBuffer = BitConverter.GetBytes(intValue);
|
||||
SettingBuffer = BitConverter.GetBytes(IntValue);
|
||||
}
|
||||
else if (nvSetting is bool boolValue)
|
||||
else if (NvSetting is bool BoolValue)
|
||||
{
|
||||
settingBuffer[0] = boolValue ? (byte)1 : (byte)0;
|
||||
SettingBuffer[0] = BoolValue ? (byte)1 : (byte)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(nvSetting.GetType().Name);
|
||||
throw new NotImplementedException(NvSetting.GetType().Name);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(outputPosition + 0x82, settingBuffer);
|
||||
Context.Memory.WriteBytes(OutputPosition + 0x82, SettingBuffer);
|
||||
|
||||
Logger.PrintDebug(LogClass.ServiceNv, $"Got setting {domain}!{name}");
|
||||
Logger.PrintDebug(LogClass.ServiceNv, $"Got setting {Domain}!{Name}");
|
||||
}
|
||||
|
||||
return NvResult.Success;
|
||||
|
@ -128,156 +128,156 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl
|
|||
return NvResult.NotAvailableInProduction;
|
||||
}
|
||||
|
||||
private static int EventWait(ServiceCtx context)
|
||||
private static int EventWait(ServiceCtx Context)
|
||||
{
|
||||
return EventWait(context, async: false);
|
||||
return EventWait(Context, Async: false);
|
||||
}
|
||||
|
||||
private static int EventWaitAsync(ServiceCtx context)
|
||||
private static int EventWaitAsync(ServiceCtx Context)
|
||||
{
|
||||
return EventWait(context, async: true);
|
||||
return EventWait(Context, Async: true);
|
||||
}
|
||||
|
||||
private static int EventRegister(ServiceCtx context)
|
||||
private static int EventRegister(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
int eventId = context.Memory.ReadInt32(inputPosition);
|
||||
int EventId = Context.Memory.ReadInt32(InputPosition);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv, "Stubbed.");
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SyncptReadMinOrMax(ServiceCtx context, bool max)
|
||||
private static int SyncptReadMinOrMax(ServiceCtx Context, bool Max)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostCtrlSyncptRead args = MemoryHelper.Read<NvHostCtrlSyncptRead>(context.Memory, inputPosition);
|
||||
NvHostCtrlSyncptRead Args = MemoryHelper.Read<NvHostCtrlSyncptRead>(Context.Memory, InputPosition);
|
||||
|
||||
if ((uint)args.Id >= NvHostSyncpt.SyncptsCount)
|
||||
if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
|
||||
{
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
if (max)
|
||||
if (Max)
|
||||
{
|
||||
args.Value = GetUserCtx(context).Syncpt.GetMax(args.Id);
|
||||
Args.Value = GetUserCtx(Context).Syncpt.GetMax(Args.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Value = GetUserCtx(context).Syncpt.GetMin(args.Id);
|
||||
Args.Value = GetUserCtx(Context).Syncpt.GetMin(Args.Id);
|
||||
}
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SyncptWait(ServiceCtx context, bool extended)
|
||||
private static int SyncptWait(ServiceCtx Context, bool Extended)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostCtrlSyncptWait args = MemoryHelper.Read<NvHostCtrlSyncptWait>(context.Memory, inputPosition);
|
||||
NvHostCtrlSyncptWait Args = MemoryHelper.Read<NvHostCtrlSyncptWait>(Context.Memory, InputPosition);
|
||||
|
||||
NvHostSyncpt syncpt = GetUserCtx(context).Syncpt;
|
||||
NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt;
|
||||
|
||||
if ((uint)args.Id >= NvHostSyncpt.SyncptsCount)
|
||||
if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
|
||||
{
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
int result;
|
||||
int Result;
|
||||
|
||||
if (syncpt.MinCompare(args.Id, args.Thresh))
|
||||
if (Syncpt.MinCompare(Args.Id, Args.Thresh))
|
||||
{
|
||||
result = NvResult.Success;
|
||||
Result = NvResult.Success;
|
||||
}
|
||||
else if (args.Timeout == 0)
|
||||
else if (Args.Timeout == 0)
|
||||
{
|
||||
result = NvResult.TryAgain;
|
||||
Result = NvResult.TryAgain;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + args.Timeout + "ms...");
|
||||
Logger.PrintDebug(LogClass.ServiceNv, "Waiting syncpt with timeout of " + Args.Timeout + "ms...");
|
||||
|
||||
using (ManualResetEvent waitEvent = new ManualResetEvent(false))
|
||||
using (ManualResetEvent WaitEvent = new ManualResetEvent(false))
|
||||
{
|
||||
syncpt.AddWaiter(args.Thresh, waitEvent);
|
||||
Syncpt.AddWaiter(Args.Thresh, WaitEvent);
|
||||
|
||||
//Note: Negative (> INT_MAX) timeouts aren't valid on .NET,
|
||||
//in this case we just use the maximum timeout possible.
|
||||
int timeout = args.Timeout;
|
||||
int Timeout = Args.Timeout;
|
||||
|
||||
if (timeout < -1)
|
||||
if (Timeout < -1)
|
||||
{
|
||||
timeout = int.MaxValue;
|
||||
Timeout = int.MaxValue;
|
||||
}
|
||||
|
||||
if (timeout == -1)
|
||||
if (Timeout == -1)
|
||||
{
|
||||
waitEvent.WaitOne();
|
||||
WaitEvent.WaitOne();
|
||||
|
||||
result = NvResult.Success;
|
||||
Result = NvResult.Success;
|
||||
}
|
||||
else if (waitEvent.WaitOne(timeout))
|
||||
else if (WaitEvent.WaitOne(Timeout))
|
||||
{
|
||||
result = NvResult.Success;
|
||||
Result = NvResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NvResult.TimedOut;
|
||||
Result = NvResult.TimedOut;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.PrintDebug(LogClass.ServiceNv, "Resuming...");
|
||||
}
|
||||
|
||||
if (extended)
|
||||
if (Extended)
|
||||
{
|
||||
context.Memory.WriteInt32(outputPosition + 0xc, syncpt.GetMin(args.Id));
|
||||
Context.Memory.WriteInt32(OutputPosition + 0xc, Syncpt.GetMin(Args.Id));
|
||||
}
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static int EventWait(ServiceCtx context, bool async)
|
||||
private static int EventWait(ServiceCtx Context, bool Async)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostCtrlSyncptWaitEx args = MemoryHelper.Read<NvHostCtrlSyncptWaitEx>(context.Memory, inputPosition);
|
||||
NvHostCtrlSyncptWaitEx Args = MemoryHelper.Read<NvHostCtrlSyncptWaitEx>(Context.Memory, InputPosition);
|
||||
|
||||
if ((uint)args.Id >= NvHostSyncpt.SyncptsCount)
|
||||
if ((uint)Args.Id >= NvHostSyncpt.SyncptsCount)
|
||||
{
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
void WriteArgs()
|
||||
{
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
}
|
||||
|
||||
NvHostSyncpt syncpt = GetUserCtx(context).Syncpt;
|
||||
NvHostSyncpt Syncpt = GetUserCtx(Context).Syncpt;
|
||||
|
||||
if (syncpt.MinCompare(args.Id, args.Thresh))
|
||||
if (Syncpt.MinCompare(Args.Id, Args.Thresh))
|
||||
{
|
||||
args.Value = syncpt.GetMin(args.Id);
|
||||
Args.Value = Syncpt.GetMin(Args.Id);
|
||||
|
||||
WriteArgs();
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
if (!async)
|
||||
if (!Async)
|
||||
{
|
||||
args.Value = 0;
|
||||
Args.Value = 0;
|
||||
}
|
||||
|
||||
if (args.Timeout == 0)
|
||||
if (Args.Timeout == 0)
|
||||
{
|
||||
WriteArgs();
|
||||
|
||||
|
@ -286,114 +286,114 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl
|
|||
|
||||
NvHostEvent Event;
|
||||
|
||||
int result, eventIndex;
|
||||
int Result, EventIndex;
|
||||
|
||||
if (async)
|
||||
if (Async)
|
||||
{
|
||||
eventIndex = args.Value;
|
||||
EventIndex = Args.Value;
|
||||
|
||||
if ((uint)eventIndex >= NvHostCtrlUserCtx.EventsCount)
|
||||
if ((uint)EventIndex >= NvHostCtrlUserCtx.EventsCount)
|
||||
{
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
Event = GetUserCtx(context).Events[eventIndex];
|
||||
Event = GetUserCtx(Context).Events[EventIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
Event = GetFreeEvent(context, syncpt, args.Id, out eventIndex);
|
||||
Event = GetFreeEvent(Context, Syncpt, Args.Id, out EventIndex);
|
||||
}
|
||||
|
||||
if (Event != null &&
|
||||
(Event.State == NvHostEventState.Registered ||
|
||||
Event.State == NvHostEventState.Free))
|
||||
{
|
||||
Event.Id = args.Id;
|
||||
Event.Thresh = args.Thresh;
|
||||
Event.Id = Args.Id;
|
||||
Event.Thresh = Args.Thresh;
|
||||
|
||||
Event.State = NvHostEventState.Waiting;
|
||||
|
||||
if (!async)
|
||||
if (!Async)
|
||||
{
|
||||
args.Value = ((args.Id & 0xfff) << 16) | 0x10000000;
|
||||
Args.Value = ((Args.Id & 0xfff) << 16) | 0x10000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Value = args.Id << 4;
|
||||
Args.Value = Args.Id << 4;
|
||||
}
|
||||
|
||||
args.Value |= eventIndex;
|
||||
Args.Value |= EventIndex;
|
||||
|
||||
result = NvResult.TryAgain;
|
||||
Result = NvResult.TryAgain;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NvResult.InvalidInput;
|
||||
Result = NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
WriteArgs();
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static NvHostEvent GetFreeEvent(
|
||||
ServiceCtx context,
|
||||
NvHostSyncpt syncpt,
|
||||
int id,
|
||||
out int eventIndex)
|
||||
ServiceCtx Context,
|
||||
NvHostSyncpt Syncpt,
|
||||
int Id,
|
||||
out int EventIndex)
|
||||
{
|
||||
NvHostEvent[] events = GetUserCtx(context).Events;
|
||||
NvHostEvent[] Events = GetUserCtx(Context).Events;
|
||||
|
||||
eventIndex = NvHostCtrlUserCtx.EventsCount;
|
||||
EventIndex = NvHostCtrlUserCtx.EventsCount;
|
||||
|
||||
int nullIndex = NvHostCtrlUserCtx.EventsCount;
|
||||
int NullIndex = NvHostCtrlUserCtx.EventsCount;
|
||||
|
||||
for (int index = 0; index < NvHostCtrlUserCtx.EventsCount; index++)
|
||||
for (int Index = 0; Index < NvHostCtrlUserCtx.EventsCount; Index++)
|
||||
{
|
||||
NvHostEvent Event = events[index];
|
||||
NvHostEvent Event = Events[Index];
|
||||
|
||||
if (Event != null)
|
||||
{
|
||||
if (Event.State == NvHostEventState.Registered ||
|
||||
Event.State == NvHostEventState.Free)
|
||||
{
|
||||
eventIndex = index;
|
||||
EventIndex = Index;
|
||||
|
||||
if (Event.Id == id)
|
||||
if (Event.Id == Id)
|
||||
{
|
||||
return Event;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nullIndex == NvHostCtrlUserCtx.EventsCount)
|
||||
else if (NullIndex == NvHostCtrlUserCtx.EventsCount)
|
||||
{
|
||||
nullIndex = index;
|
||||
NullIndex = Index;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullIndex < NvHostCtrlUserCtx.EventsCount)
|
||||
if (NullIndex < NvHostCtrlUserCtx.EventsCount)
|
||||
{
|
||||
eventIndex = nullIndex;
|
||||
EventIndex = NullIndex;
|
||||
|
||||
return events[nullIndex] = new NvHostEvent();
|
||||
return Events[NullIndex] = new NvHostEvent();
|
||||
}
|
||||
|
||||
if (eventIndex < NvHostCtrlUserCtx.EventsCount)
|
||||
if (EventIndex < NvHostCtrlUserCtx.EventsCount)
|
||||
{
|
||||
return events[eventIndex];
|
||||
return Events[EventIndex];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx context)
|
||||
public static NvHostCtrlUserCtx GetUserCtx(ServiceCtx Context)
|
||||
{
|
||||
return _userCtxs.GetOrAdd(context.Process, (key) => new NvHostCtrlUserCtx());
|
||||
return UserCtxs.GetOrAdd(Context.Process, (Key) => new NvHostCtrlUserCtx());
|
||||
}
|
||||
|
||||
public static void UnloadProcess(KProcess process)
|
||||
public static void UnloadProcess(KProcess Process)
|
||||
{
|
||||
_userCtxs.TryRemove(process, out _);
|
||||
UserCtxs.TryRemove(Process, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl
|
|||
public const int LocksCount = 16;
|
||||
public const int EventsCount = 64;
|
||||
|
||||
public NvHostSyncpt Syncpt { get; }
|
||||
public NvHostSyncpt Syncpt { get; private set; }
|
||||
|
||||
public NvHostEvent[] Events { get; }
|
||||
public NvHostEvent[] Events { get; private set; }
|
||||
|
||||
public NvHostCtrlUserCtx()
|
||||
{
|
||||
|
|
|
@ -9,98 +9,98 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostCtrl
|
|||
{
|
||||
public const int SyncptsCount = 192;
|
||||
|
||||
private int[] _counterMin;
|
||||
private int[] _counterMax;
|
||||
private int[] CounterMin;
|
||||
private int[] CounterMax;
|
||||
|
||||
private long _eventMask;
|
||||
private long EventMask;
|
||||
|
||||
private ConcurrentDictionary<EventWaitHandle, int> _waiters;
|
||||
private ConcurrentDictionary<EventWaitHandle, int> Waiters;
|
||||
|
||||
public NvHostSyncpt()
|
||||
{
|
||||
_counterMin = new int[SyncptsCount];
|
||||
_counterMax = new int[SyncptsCount];
|
||||
CounterMin = new int[SyncptsCount];
|
||||
CounterMax = new int[SyncptsCount];
|
||||
|
||||
_waiters = new ConcurrentDictionary<EventWaitHandle, int>();
|
||||
Waiters = new ConcurrentDictionary<EventWaitHandle, int>();
|
||||
}
|
||||
|
||||
public int GetMin(int id)
|
||||
public int GetMin(int Id)
|
||||
{
|
||||
return _counterMin[id];
|
||||
return CounterMin[Id];
|
||||
}
|
||||
|
||||
public int GetMax(int id)
|
||||
public int GetMax(int Id)
|
||||
{
|
||||
return _counterMax[id];
|
||||
return CounterMax[Id];
|
||||
}
|
||||
|
||||
public int Increment(int id)
|
||||
public int Increment(int Id)
|
||||
{
|
||||
if (((_eventMask >> id) & 1) != 0)
|
||||
if (((EventMask >> Id) & 1) != 0)
|
||||
{
|
||||
Interlocked.Increment(ref _counterMax[id]);
|
||||
Interlocked.Increment(ref CounterMax[Id]);
|
||||
}
|
||||
|
||||
return IncrementMin(id);
|
||||
return IncrementMin(Id);
|
||||
}
|
||||
|
||||
public int IncrementMin(int id)
|
||||
public int IncrementMin(int Id)
|
||||
{
|
||||
int value = Interlocked.Increment(ref _counterMin[id]);
|
||||
int Value = Interlocked.Increment(ref CounterMin[Id]);
|
||||
|
||||
WakeUpWaiters(id, value);
|
||||
WakeUpWaiters(Id, Value);
|
||||
|
||||
return value;
|
||||
return Value;
|
||||
}
|
||||
|
||||
public int IncrementMax(int id)
|
||||
public int IncrementMax(int Id)
|
||||
{
|
||||
return Interlocked.Increment(ref _counterMax[id]);
|
||||
return Interlocked.Increment(ref CounterMax[Id]);
|
||||
}
|
||||
|
||||
public void AddWaiter(int threshold, EventWaitHandle waitEvent)
|
||||
public void AddWaiter(int Threshold, EventWaitHandle WaitEvent)
|
||||
{
|
||||
if (!_waiters.TryAdd(waitEvent, threshold))
|
||||
if (!Waiters.TryAdd(WaitEvent, Threshold))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool RemoveWaiter(EventWaitHandle waitEvent)
|
||||
public bool RemoveWaiter(EventWaitHandle WaitEvent)
|
||||
{
|
||||
return _waiters.TryRemove(waitEvent, out _);
|
||||
return Waiters.TryRemove(WaitEvent, out _);
|
||||
}
|
||||
|
||||
private void WakeUpWaiters(int id, int newValue)
|
||||
private void WakeUpWaiters(int Id, int NewValue)
|
||||
{
|
||||
foreach (KeyValuePair<EventWaitHandle, int> kv in _waiters)
|
||||
foreach (KeyValuePair<EventWaitHandle, int> KV in Waiters)
|
||||
{
|
||||
if (MinCompare(id, newValue, _counterMax[id], kv.Value))
|
||||
if (MinCompare(Id, NewValue, CounterMax[Id], KV.Value))
|
||||
{
|
||||
kv.Key.Set();
|
||||
KV.Key.Set();
|
||||
|
||||
_waiters.TryRemove(kv.Key, out _);
|
||||
Waiters.TryRemove(KV.Key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool MinCompare(int id, int threshold)
|
||||
public bool MinCompare(int Id, int Threshold)
|
||||
{
|
||||
return MinCompare(id, _counterMin[id], _counterMax[id], threshold);
|
||||
return MinCompare(Id, CounterMin[Id], CounterMax[Id], Threshold);
|
||||
}
|
||||
|
||||
private bool MinCompare(int id, int min, int max, int threshold)
|
||||
private bool MinCompare(int Id, int Min, int Max, int Threshold)
|
||||
{
|
||||
int minDiff = min - threshold;
|
||||
int maxDiff = max - threshold;
|
||||
int MinDiff = Min - Threshold;
|
||||
int MaxDiff = Max - Threshold;
|
||||
|
||||
if (((_eventMask >> id) & 1) != 0)
|
||||
if (((EventMask >> Id) & 1) != 0)
|
||||
{
|
||||
return minDiff >= 0;
|
||||
return MinDiff >= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint)maxDiff >= (uint)minDiff;
|
||||
return (uint)MaxDiff >= (uint)MinDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,26 +13,26 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvMap
|
|||
public bool Allocated;
|
||||
public long DmaMapAddress;
|
||||
|
||||
private long _dupes;
|
||||
private long Dupes;
|
||||
|
||||
public NvMapHandle()
|
||||
{
|
||||
_dupes = 1;
|
||||
Dupes = 1;
|
||||
}
|
||||
|
||||
public NvMapHandle(int size) : this()
|
||||
public NvMapHandle(int Size) : this()
|
||||
{
|
||||
Size = size;
|
||||
this.Size = Size;
|
||||
}
|
||||
|
||||
public void IncrementRefCount()
|
||||
{
|
||||
Interlocked.Increment(ref _dupes);
|
||||
Interlocked.Increment(ref Dupes);
|
||||
}
|
||||
|
||||
public long DecrementRefCount()
|
||||
{
|
||||
return Interlocked.Decrement(ref _dupes);
|
||||
return Interlocked.Decrement(ref Dupes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,290 +11,290 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvMap
|
|||
{
|
||||
private const int FlagNotFreedYet = 1;
|
||||
|
||||
private static ConcurrentDictionary<KProcess, IdDictionary> _maps;
|
||||
private static ConcurrentDictionary<KProcess, IdDictionary> Maps;
|
||||
|
||||
static NvMapIoctl()
|
||||
{
|
||||
_maps = new ConcurrentDictionary<KProcess, IdDictionary>();
|
||||
Maps = new ConcurrentDictionary<KProcess, IdDictionary>();
|
||||
}
|
||||
|
||||
public static int ProcessIoctl(ServiceCtx context, int cmd)
|
||||
public static int ProcessIoctl(ServiceCtx Context, int Cmd)
|
||||
{
|
||||
switch (cmd & 0xffff)
|
||||
switch (Cmd & 0xffff)
|
||||
{
|
||||
case 0x0101: return Create(context);
|
||||
case 0x0103: return FromId(context);
|
||||
case 0x0104: return Alloc (context);
|
||||
case 0x0105: return Free (context);
|
||||
case 0x0109: return Param (context);
|
||||
case 0x010e: return GetId (context);
|
||||
case 0x0101: return Create(Context);
|
||||
case 0x0103: return FromId(Context);
|
||||
case 0x0104: return Alloc (Context);
|
||||
case 0x0105: return Free (Context);
|
||||
case 0x0109: return Param (Context);
|
||||
case 0x010e: return GetId (Context);
|
||||
}
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{cmd:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Unsupported Ioctl command 0x{Cmd:x8}!");
|
||||
|
||||
return NvResult.NotSupported;
|
||||
}
|
||||
|
||||
private static int Create(ServiceCtx context)
|
||||
private static int Create(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvMapCreate args = MemoryHelper.Read<NvMapCreate>(context.Memory, inputPosition);
|
||||
NvMapCreate Args = MemoryHelper.Read<NvMapCreate>(Context.Memory, InputPosition);
|
||||
|
||||
if (args.Size == 0)
|
||||
if (Args.Size == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{args.Size:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid size 0x{Args.Size:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
int size = IntUtils.AlignUp(args.Size, NvGpuVmm.PageSize);
|
||||
int Size = IntUtils.AlignUp(Args.Size, NvGpuVmm.PageSize);
|
||||
|
||||
args.Handle = AddNvMap(context, new NvMapHandle(size));
|
||||
Args.Handle = AddNvMap(Context, new NvMapHandle(Size));
|
||||
|
||||
Logger.PrintInfo(LogClass.ServiceNv, $"Created map {args.Handle} with size 0x{size:x8}!");
|
||||
Logger.PrintInfo(LogClass.ServiceNv, $"Created map {Args.Handle} with size 0x{Size:x8}!");
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int FromId(ServiceCtx context)
|
||||
private static int FromId(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvMapFromId args = MemoryHelper.Read<NvMapFromId>(context.Memory, inputPosition);
|
||||
NvMapFromId Args = MemoryHelper.Read<NvMapFromId>(Context.Memory, InputPosition);
|
||||
|
||||
NvMapHandle map = GetNvMap(context, args.Id);
|
||||
NvMapHandle Map = GetNvMap(Context, Args.Id);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
map.IncrementRefCount();
|
||||
Map.IncrementRefCount();
|
||||
|
||||
args.Handle = args.Id;
|
||||
Args.Handle = Args.Id;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int Alloc(ServiceCtx context)
|
||||
private static int Alloc(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvMapAlloc args = MemoryHelper.Read<NvMapAlloc>(context.Memory, inputPosition);
|
||||
NvMapAlloc Args = MemoryHelper.Read<NvMapAlloc>(Context.Memory, InputPosition);
|
||||
|
||||
NvMapHandle map = GetNvMap(context, args.Handle);
|
||||
NvMapHandle Map = GetNvMap(Context, Args.Handle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
if ((args.Align & (args.Align - 1)) != 0)
|
||||
if ((Args.Align & (Args.Align - 1)) != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{args.Align:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid alignment 0x{Args.Align:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
if ((uint)args.Align < NvGpuVmm.PageSize)
|
||||
if ((uint)Args.Align < NvGpuVmm.PageSize)
|
||||
{
|
||||
args.Align = NvGpuVmm.PageSize;
|
||||
Args.Align = NvGpuVmm.PageSize;
|
||||
}
|
||||
|
||||
int result = NvResult.Success;
|
||||
int Result = NvResult.Success;
|
||||
|
||||
if (!map.Allocated)
|
||||
if (!Map.Allocated)
|
||||
{
|
||||
map.Allocated = true;
|
||||
Map.Allocated = true;
|
||||
|
||||
map.Align = args.Align;
|
||||
map.Kind = (byte)args.Kind;
|
||||
Map.Align = Args.Align;
|
||||
Map.Kind = (byte)Args.Kind;
|
||||
|
||||
int size = IntUtils.AlignUp(map.Size, NvGpuVmm.PageSize);
|
||||
int Size = IntUtils.AlignUp(Map.Size, NvGpuVmm.PageSize);
|
||||
|
||||
long address = args.Address;
|
||||
long Address = Args.Address;
|
||||
|
||||
if (address == 0)
|
||||
if (Address == 0)
|
||||
{
|
||||
//When the address is zero, we need to allocate
|
||||
//our own backing memory for the NvMap.
|
||||
//TODO: Is this allocation inside the transfer memory?
|
||||
result = NvResult.OutOfMemory;
|
||||
Result = NvResult.OutOfMemory;
|
||||
}
|
||||
|
||||
if (result == NvResult.Success)
|
||||
if (Result == NvResult.Success)
|
||||
{
|
||||
map.Size = size;
|
||||
map.Address = address;
|
||||
Map.Size = Size;
|
||||
Map.Address = Address;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static int Free(ServiceCtx context)
|
||||
private static int Free(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvMapFree args = MemoryHelper.Read<NvMapFree>(context.Memory, inputPosition);
|
||||
NvMapFree Args = MemoryHelper.Read<NvMapFree>(Context.Memory, InputPosition);
|
||||
|
||||
NvMapHandle map = GetNvMap(context, args.Handle);
|
||||
NvMapHandle Map = GetNvMap(Context, Args.Handle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
if (map.DecrementRefCount() <= 0)
|
||||
if (Map.DecrementRefCount() <= 0)
|
||||
{
|
||||
DeleteNvMap(context, args.Handle);
|
||||
DeleteNvMap(Context, Args.Handle);
|
||||
|
||||
Logger.PrintInfo(LogClass.ServiceNv, $"Deleted map {args.Handle}!");
|
||||
Logger.PrintInfo(LogClass.ServiceNv, $"Deleted map {Args.Handle}!");
|
||||
|
||||
args.Address = map.Address;
|
||||
args.Flags = 0;
|
||||
Args.Address = Map.Address;
|
||||
Args.Flags = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Address = 0;
|
||||
args.Flags = FlagNotFreedYet;
|
||||
Args.Address = 0;
|
||||
Args.Flags = FlagNotFreedYet;
|
||||
}
|
||||
|
||||
args.Size = map.Size;
|
||||
Args.Size = Map.Size;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int Param(ServiceCtx context)
|
||||
private static int Param(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvMapParam args = MemoryHelper.Read<NvMapParam>(context.Memory, inputPosition);
|
||||
NvMapParam Args = MemoryHelper.Read<NvMapParam>(Context.Memory, InputPosition);
|
||||
|
||||
NvMapHandle map = GetNvMap(context, args.Handle);
|
||||
NvMapHandle Map = GetNvMap(Context, Args.Handle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
switch ((NvMapHandleParam)args.Param)
|
||||
switch ((NvMapHandleParam)Args.Param)
|
||||
{
|
||||
case NvMapHandleParam.Size: args.Result = map.Size; break;
|
||||
case NvMapHandleParam.Align: args.Result = map.Align; break;
|
||||
case NvMapHandleParam.Heap: args.Result = 0x40000000; break;
|
||||
case NvMapHandleParam.Kind: args.Result = map.Kind; break;
|
||||
case NvMapHandleParam.Compr: args.Result = 0; break;
|
||||
case NvMapHandleParam.Size: Args.Result = Map.Size; break;
|
||||
case NvMapHandleParam.Align: Args.Result = Map.Align; break;
|
||||
case NvMapHandleParam.Heap: Args.Result = 0x40000000; break;
|
||||
case NvMapHandleParam.Kind: Args.Result = Map.Kind; break;
|
||||
case NvMapHandleParam.Compr: Args.Result = 0; break;
|
||||
|
||||
//Note: Base is not supported and returns an error.
|
||||
//Any other value also returns an error.
|
||||
default: return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int GetId(ServiceCtx context)
|
||||
private static int GetId(ServiceCtx Context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
long InputPosition = Context.Request.GetBufferType0x21().Position;
|
||||
long OutputPosition = Context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvMapGetId args = MemoryHelper.Read<NvMapGetId>(context.Memory, inputPosition);
|
||||
NvMapGetId Args = MemoryHelper.Read<NvMapGetId>(Context.Memory, InputPosition);
|
||||
|
||||
NvMapHandle map = GetNvMap(context, args.Handle);
|
||||
NvMapHandle Map = GetNvMap(Context, Args.Handle);
|
||||
|
||||
if (map == null)
|
||||
if (Map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{args.Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Args.Handle:x8}!");
|
||||
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
args.Id = args.Handle;
|
||||
Args.Id = Args.Handle;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
MemoryHelper.Write(Context.Memory, OutputPosition, Args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int AddNvMap(ServiceCtx context, NvMapHandle map)
|
||||
private static int AddNvMap(ServiceCtx Context, NvMapHandle Map)
|
||||
{
|
||||
IdDictionary dict = _maps.GetOrAdd(context.Process, (key) =>
|
||||
IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>
|
||||
{
|
||||
IdDictionary newDict = new IdDictionary();
|
||||
IdDictionary NewDict = new IdDictionary();
|
||||
|
||||
newDict.Add(0, new NvMapHandle());
|
||||
NewDict.Add(0, new NvMapHandle());
|
||||
|
||||
return newDict;
|
||||
return NewDict;
|
||||
});
|
||||
|
||||
return dict.Add(map);
|
||||
return Dict.Add(Map);
|
||||
}
|
||||
|
||||
private static bool DeleteNvMap(ServiceCtx context, int handle)
|
||||
private static bool DeleteNvMap(ServiceCtx Context, int Handle)
|
||||
{
|
||||
if (_maps.TryGetValue(context.Process, out IdDictionary dict))
|
||||
if (Maps.TryGetValue(Context.Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.Delete(handle) != null;
|
||||
return Dict.Delete(Handle) != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void InitializeNvMap(ServiceCtx context)
|
||||
public static void InitializeNvMap(ServiceCtx Context)
|
||||
{
|
||||
IdDictionary dict = _maps.GetOrAdd(context.Process, (key) =>new IdDictionary());
|
||||
IdDictionary Dict = Maps.GetOrAdd(Context.Process, (Key) =>new IdDictionary());
|
||||
|
||||
dict.Add(0, new NvMapHandle());
|
||||
Dict.Add(0, new NvMapHandle());
|
||||
}
|
||||
|
||||
public static NvMapHandle GetNvMapWithFb(ServiceCtx context, int handle)
|
||||
public static NvMapHandle GetNvMapWithFb(ServiceCtx Context, int Handle)
|
||||
{
|
||||
if (_maps.TryGetValue(context.Process, out IdDictionary dict))
|
||||
if (Maps.TryGetValue(Context.Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.GetData<NvMapHandle>(handle);
|
||||
return Dict.GetData<NvMapHandle>(Handle);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static NvMapHandle GetNvMap(ServiceCtx context, int handle)
|
||||
public static NvMapHandle GetNvMap(ServiceCtx Context, int Handle)
|
||||
{
|
||||
if (handle != 0 && _maps.TryGetValue(context.Process, out IdDictionary dict))
|
||||
if (Handle != 0 && Maps.TryGetValue(Context.Process, out IdDictionary Dict))
|
||||
{
|
||||
return dict.GetData<NvMapHandle>(handle);
|
||||
return Dict.GetData<NvMapHandle>(Handle);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void UnloadProcess(KProcess process)
|
||||
public static void UnloadProcess(KProcess Process)
|
||||
{
|
||||
_maps.TryRemove(process, out _);
|
||||
Maps.TryRemove(Process, out _);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,29 +6,29 @@ namespace Ryujinx.HLE.HOS.Services.Pctl
|
|||
{
|
||||
class IParentalControlService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private bool _initialized = false;
|
||||
private bool Initialized = false;
|
||||
|
||||
private bool _needInitialize;
|
||||
private bool NeedInitialize;
|
||||
|
||||
public IParentalControlService(bool needInitialize = true)
|
||||
public IParentalControlService(bool NeedInitialize = true)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, Initialize }
|
||||
};
|
||||
|
||||
_needInitialize = needInitialize;
|
||||
this.NeedInitialize = NeedInitialize;
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx context)
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
if (_needInitialize && !_initialized)
|
||||
if (NeedInitialize && !Initialized)
|
||||
{
|
||||
_initialized = true;
|
||||
Initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -5,29 +5,29 @@ namespace Ryujinx.HLE.HOS.Services.Pctl
|
|||
{
|
||||
class IParentalControlServiceFactory : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IParentalControlServiceFactory()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CreateService },
|
||||
{ 1, CreateServiceWithoutInitialize }
|
||||
};
|
||||
}
|
||||
|
||||
public long CreateService(ServiceCtx context)
|
||||
public long CreateService(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IParentalControlService());
|
||||
MakeObject(Context, new IParentalControlService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateServiceWithoutInitialize(ServiceCtx context)
|
||||
public long CreateServiceWithoutInitialize(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IParentalControlService(false));
|
||||
MakeObject(Context, new IParentalControlService(false));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Pl
|
|||
{
|
||||
class ISharedFontManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISharedFontManager()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, RequestLoad },
|
||||
{ 1, GetLoadState },
|
||||
|
@ -25,104 +25,104 @@ namespace Ryujinx.HLE.HOS.Services.Pl
|
|||
};
|
||||
}
|
||||
|
||||
public long RequestLoad(ServiceCtx context)
|
||||
public long RequestLoad(ServiceCtx Context)
|
||||
{
|
||||
SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
|
||||
SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
|
||||
|
||||
//We don't need to do anything here because we do lazy initialization
|
||||
//on SharedFontManager (the font is loaded when necessary).
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetLoadState(ServiceCtx context)
|
||||
public long GetLoadState(ServiceCtx Context)
|
||||
{
|
||||
SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
|
||||
SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
|
||||
|
||||
//1 (true) indicates that the font is already loaded.
|
||||
//All fonts are already loaded.
|
||||
context.ResponseData.Write(1);
|
||||
Context.ResponseData.Write(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetFontSize(ServiceCtx context)
|
||||
public long GetFontSize(ServiceCtx Context)
|
||||
{
|
||||
SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
|
||||
SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
|
||||
|
||||
context.ResponseData.Write(context.Device.System.Font.GetFontSize(fontType));
|
||||
Context.ResponseData.Write(Context.Device.System.Font.GetFontSize(FontType));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSharedMemoryAddressOffset(ServiceCtx context)
|
||||
public long GetSharedMemoryAddressOffset(ServiceCtx Context)
|
||||
{
|
||||
SharedFontType fontType = (SharedFontType)context.RequestData.ReadInt32();
|
||||
SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
|
||||
|
||||
context.ResponseData.Write(context.Device.System.Font.GetSharedMemoryAddressOffset(fontType));
|
||||
Context.ResponseData.Write(Context.Device.System.Font.GetSharedMemoryAddressOffset(FontType));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSharedMemoryNativeHandle(ServiceCtx context)
|
||||
public long GetSharedMemoryNativeHandle(ServiceCtx Context)
|
||||
{
|
||||
context.Device.System.Font.EnsureInitialized(context.Device.System.ContentManager);
|
||||
Context.Device.System.Font.EnsureInitialized(Context.Device.System.ContentManager);
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(context.Device.System.FontSharedMem, out int handle) != KernelResult.Success)
|
||||
if (Context.Process.HandleTable.GenerateHandle(Context.Device.System.FontSharedMem, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetSharedFontInOrderOfPriority(ServiceCtx context)
|
||||
public long GetSharedFontInOrderOfPriority(ServiceCtx Context)
|
||||
{
|
||||
long languageCode = context.RequestData.ReadInt64();
|
||||
int loadedCount = 0;
|
||||
long LanguageCode = Context.RequestData.ReadInt64();
|
||||
int LoadedCount = 0;
|
||||
|
||||
for (SharedFontType type = 0; type < SharedFontType.Count; type++)
|
||||
for (SharedFontType Type = 0; Type < SharedFontType.Count; Type++)
|
||||
{
|
||||
int offset = (int)type * 4;
|
||||
int Offset = (int)Type * 4;
|
||||
|
||||
if (!AddFontToOrderOfPriorityList(context, type, offset))
|
||||
if (!AddFontToOrderOfPriorityList(Context, (SharedFontType)Type, Offset))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
loadedCount++;
|
||||
LoadedCount++;
|
||||
}
|
||||
|
||||
context.ResponseData.Write(loadedCount);
|
||||
context.ResponseData.Write((int)SharedFontType.Count);
|
||||
Context.ResponseData.Write(LoadedCount);
|
||||
Context.ResponseData.Write((int)SharedFontType.Count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private bool AddFontToOrderOfPriorityList(ServiceCtx context, SharedFontType fontType, int offset)
|
||||
private bool AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, int Offset)
|
||||
{
|
||||
long typesPosition = context.Request.ReceiveBuff[0].Position;
|
||||
long typesSize = context.Request.ReceiveBuff[0].Size;
|
||||
long TypesPosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long TypesSize = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
long offsetsPosition = context.Request.ReceiveBuff[1].Position;
|
||||
long offsetsSize = context.Request.ReceiveBuff[1].Size;
|
||||
long OffsetsPosition = Context.Request.ReceiveBuff[1].Position;
|
||||
long OffsetsSize = Context.Request.ReceiveBuff[1].Size;
|
||||
|
||||
long fontSizeBufferPosition = context.Request.ReceiveBuff[2].Position;
|
||||
long fontSizeBufferSize = context.Request.ReceiveBuff[2].Size;
|
||||
long FontSizeBufferPosition = Context.Request.ReceiveBuff[2].Position;
|
||||
long FontSizeBufferSize = Context.Request.ReceiveBuff[2].Size;
|
||||
|
||||
if ((uint)offset + 4 > (uint)typesSize ||
|
||||
(uint)offset + 4 > (uint)offsetsSize ||
|
||||
(uint)offset + 4 > (uint)fontSizeBufferSize)
|
||||
if ((uint)Offset + 4 > (uint)TypesSize ||
|
||||
(uint)Offset + 4 > (uint)OffsetsSize ||
|
||||
(uint)Offset + 4 > (uint)FontSizeBufferSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
context.Memory.WriteInt32(typesPosition + offset, (int)fontType);
|
||||
Context.Memory.WriteInt32(TypesPosition + Offset, (int)FontType);
|
||||
|
||||
context.Memory.WriteInt32(offsetsPosition + offset, context.Device.System.Font.GetSharedMemoryAddressOffset(fontType));
|
||||
Context.Memory.WriteInt32(OffsetsPosition + Offset, Context.Device.System.Font.GetSharedMemoryAddressOffset(FontType));
|
||||
|
||||
context.Memory.WriteInt32(fontSizeBufferPosition + offset, context.Device.System.Font.GetFontSize(fontType));
|
||||
Context.Memory.WriteInt32(FontSizeBufferPosition + Offset, Context.Device.System.Font.GetFontSize(FontType));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6,19 +6,19 @@ namespace Ryujinx.HLE.HOS.Services.Prepo
|
|||
{
|
||||
class IPrepoService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IPrepoService()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 10101, SaveReportWithUser }
|
||||
};
|
||||
}
|
||||
|
||||
public static long SaveReportWithUser(ServiceCtx context)
|
||||
public static long SaveReportWithUser(ServiceCtx Context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServicePrepo, "Stubbed.");
|
||||
|
||||
|
|
|
@ -6,20 +6,20 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
{
|
||||
class IPsmServer : IpcService
|
||||
{
|
||||
enum ChargerType
|
||||
enum ChargerType : int
|
||||
{
|
||||
None,
|
||||
ChargerOrDock,
|
||||
UsbC
|
||||
}
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IPsmServer()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetBatteryChargePercentage },
|
||||
{ 1, GetChargerType },
|
||||
|
@ -28,21 +28,21 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
}
|
||||
|
||||
// GetBatteryChargePercentage() -> u32
|
||||
public static long GetBatteryChargePercentage(ServiceCtx context)
|
||||
public static long GetBatteryChargePercentage(ServiceCtx Context)
|
||||
{
|
||||
int chargePercentage = 100;
|
||||
int ChargePercentage = 100;
|
||||
|
||||
context.ResponseData.Write(chargePercentage);
|
||||
Context.ResponseData.Write(ChargePercentage);
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. ChargePercentage: {chargePercentage}");
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. ChargePercentage: {ChargePercentage}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetChargerType() -> u32
|
||||
public static long GetChargerType(ServiceCtx context)
|
||||
public static long GetChargerType(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)ChargerType.ChargerOrDock);
|
||||
Context.ResponseData.Write((int)ChargerType.ChargerOrDock);
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. ChargerType: {ChargerType.ChargerOrDock}");
|
||||
|
||||
|
@ -50,9 +50,9 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
}
|
||||
|
||||
// OpenSession() -> IPsmSession
|
||||
public long OpenSession(ServiceCtx context)
|
||||
public long OpenSession(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(context, new IPsmSession(context.Device.System));
|
||||
MakeObject(Context, new IPsmSession(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
{
|
||||
class IPsmSession : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private KEvent _stateChangeEvent;
|
||||
private int _stateChangeEventHandle;
|
||||
private KEvent StateChangeEvent;
|
||||
private int StateChangeEventHandle;
|
||||
|
||||
public IPsmSession(Horizon system)
|
||||
public IPsmSession(Horizon System)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, BindStateChangeEvent },
|
||||
{ 1, UnbindStateChangeEvent },
|
||||
|
@ -25,24 +25,24 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
{ 4, SetBatteryVoltageStateChangeEventEnabled }
|
||||
};
|
||||
|
||||
_stateChangeEvent = new KEvent(system);
|
||||
_stateChangeEventHandle = -1;
|
||||
StateChangeEvent = new KEvent(System);
|
||||
StateChangeEventHandle = -1;
|
||||
}
|
||||
|
||||
// BindStateChangeEvent() -> KObject
|
||||
public long BindStateChangeEvent(ServiceCtx context)
|
||||
public long BindStateChangeEvent(ServiceCtx Context)
|
||||
{
|
||||
if (_stateChangeEventHandle == -1)
|
||||
if (StateChangeEventHandle == -1)
|
||||
{
|
||||
KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent, out int stateChangeEventHandle);
|
||||
KernelResult ResultCode = Context.Process.HandleTable.GenerateHandle(StateChangeEvent, out int StateChangeEventHandle);
|
||||
|
||||
if (resultCode != KernelResult.Success)
|
||||
if (ResultCode != KernelResult.Success)
|
||||
{
|
||||
return (long)resultCode;
|
||||
return (long)ResultCode;
|
||||
}
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangeEventHandle);
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(StateChangeEventHandle);
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, "Stubbed.");
|
||||
|
||||
|
@ -50,12 +50,12 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
}
|
||||
|
||||
// UnbindStateChangeEvent()
|
||||
public long UnbindStateChangeEvent(ServiceCtx context)
|
||||
public long UnbindStateChangeEvent(ServiceCtx Context)
|
||||
{
|
||||
if (_stateChangeEventHandle != -1)
|
||||
if (StateChangeEventHandle != -1)
|
||||
{
|
||||
context.Process.HandleTable.CloseHandle(_stateChangeEventHandle);
|
||||
_stateChangeEventHandle = -1;
|
||||
Context.Process.HandleTable.CloseHandle(StateChangeEventHandle);
|
||||
StateChangeEventHandle = -1;
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, "Stubbed.");
|
||||
|
@ -64,31 +64,31 @@ namespace Ryujinx.HLE.HOS.Services.Psm
|
|||
}
|
||||
|
||||
// SetChargerTypeChangeEventEnabled(u8)
|
||||
public long SetChargerTypeChangeEventEnabled(ServiceCtx context)
|
||||
public long SetChargerTypeChangeEventEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool chargerTypeChangeEventEnabled = context.RequestData.ReadBoolean();
|
||||
bool ChargerTypeChangeEventEnabled = Context.RequestData.ReadBoolean();
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. ChargerTypeChangeEventEnabled: {chargerTypeChangeEventEnabled}");
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. ChargerTypeChangeEventEnabled: {ChargerTypeChangeEventEnabled}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SetPowerSupplyChangeEventEnabled(u8)
|
||||
public long SetPowerSupplyChangeEventEnabled(ServiceCtx context)
|
||||
public long SetPowerSupplyChangeEventEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool powerSupplyChangeEventEnabled = context.RequestData.ReadBoolean();
|
||||
bool PowerSupplyChangeEventEnabled = Context.RequestData.ReadBoolean();
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. PowerSupplyChangeEventEnabled: {powerSupplyChangeEventEnabled}");
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. PowerSupplyChangeEventEnabled: {PowerSupplyChangeEventEnabled}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SetBatteryVoltageStateChangeEventEnabled(u8)
|
||||
public long SetBatteryVoltageStateChangeEventEnabled(ServiceCtx context)
|
||||
public long SetBatteryVoltageStateChangeEventEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool batteryVoltageStateChangeEventEnabled = context.RequestData.ReadBoolean();
|
||||
bool BatteryVoltageStateChangeEventEnabled = Context.RequestData.ReadBoolean();
|
||||
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. BatteryVoltageStateChangeEventEnabled: {batteryVoltageStateChangeEventEnabled}");
|
||||
Logger.PrintStub(LogClass.ServicePsm, $"Stubbed. BatteryVoltageStateChangeEventEnabled: {BatteryVoltageStateChangeEventEnabled}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
{
|
||||
static class ServiceFactory
|
||||
{
|
||||
public static IpcService MakeService(Horizon system, string name)
|
||||
public static IpcService MakeService(Horizon System, string Name)
|
||||
{
|
||||
switch (name)
|
||||
switch (Name)
|
||||
{
|
||||
case "acc:u0":
|
||||
return new IAccountService();
|
||||
|
@ -90,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
return new IRandomInterface();
|
||||
|
||||
case "es":
|
||||
return new IeTicketService();
|
||||
return new IETicketService();
|
||||
|
||||
case "friend:a":
|
||||
return new Friend.IServiceCreator();
|
||||
|
@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
return new IFileSystemProxy();
|
||||
|
||||
case "hid":
|
||||
return new IHidServer(system);
|
||||
return new IHidServer(System);
|
||||
|
||||
case "irs":
|
||||
return new IIrSensorServer();
|
||||
|
@ -141,10 +141,10 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
return new IVulnerabilityManagerInterface();
|
||||
|
||||
case "nvdrv":
|
||||
return new INvDrvServices(system);
|
||||
return new INvDrvServices(System);
|
||||
|
||||
case "nvdrv:a":
|
||||
return new INvDrvServices(system);
|
||||
return new INvDrvServices(System);
|
||||
|
||||
case "pctl:s":
|
||||
return new IParentalControlServiceFactory();
|
||||
|
@ -204,7 +204,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
return new IApplicationRootService();
|
||||
}
|
||||
|
||||
throw new NotImplementedException(name);
|
||||
throw new NotImplementedException(Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ namespace Ryujinx.HLE.HOS.Services.Set
|
|||
{
|
||||
class ISettingsServer : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISettingsServer()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetLanguageCode },
|
||||
{ 1, GetAvailableLanguageCodes },
|
||||
|
@ -21,57 +21,57 @@ namespace Ryujinx.HLE.HOS.Services.Set
|
|||
};
|
||||
}
|
||||
|
||||
public static long GetLanguageCode(ServiceCtx context)
|
||||
public static long GetLanguageCode(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(context.Device.System.State.DesiredLanguageCode);
|
||||
Context.ResponseData.Write(Context.Device.System.State.DesiredLanguageCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAvailableLanguageCodes(ServiceCtx context)
|
||||
public static long GetAvailableLanguageCodes(ServiceCtx Context)
|
||||
{
|
||||
GetAvailableLanguagesCodesImpl(
|
||||
context,
|
||||
context.Request.RecvListBuff[0].Position,
|
||||
context.Request.RecvListBuff[0].Size);
|
||||
Context,
|
||||
Context.Request.RecvListBuff[0].Position,
|
||||
Context.Request.RecvListBuff[0].Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAvailableLanguageCodeCount(ServiceCtx context)
|
||||
public static long GetAvailableLanguageCodeCount(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length);
|
||||
Context.ResponseData.Write(SystemStateMgr.LanguageCodes.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAvailableLanguageCodes2(ServiceCtx context)
|
||||
public static long GetAvailableLanguageCodes2(ServiceCtx Context)
|
||||
{
|
||||
GetAvailableLanguagesCodesImpl(
|
||||
context,
|
||||
context.Request.ReceiveBuff[0].Position,
|
||||
context.Request.ReceiveBuff[0].Size);
|
||||
Context,
|
||||
Context.Request.ReceiveBuff[0].Position,
|
||||
Context.Request.ReceiveBuff[0].Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAvailableLanguagesCodesImpl(ServiceCtx context, long position, long size)
|
||||
public static long GetAvailableLanguagesCodesImpl(ServiceCtx Context, long Position, long Size)
|
||||
{
|
||||
int count = (int)(size / 8);
|
||||
int Count = (int)(Size / 8);
|
||||
|
||||
if (count > SystemStateMgr.LanguageCodes.Length)
|
||||
if (Count > SystemStateMgr.LanguageCodes.Length)
|
||||
{
|
||||
count = SystemStateMgr.LanguageCodes.Length;
|
||||
Count = SystemStateMgr.LanguageCodes.Length;
|
||||
}
|
||||
|
||||
for (int index = 0; index < count; index++)
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
context.Memory.WriteInt64(position, SystemStateMgr.GetLanguageCode(index));
|
||||
Context.Memory.WriteInt64(Position, SystemStateMgr.GetLanguageCode(Index));
|
||||
|
||||
position += 8;
|
||||
Position += 8;
|
||||
}
|
||||
|
||||
context.ResponseData.Write(count);
|
||||
Context.ResponseData.Write(Count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ namespace Ryujinx.HLE.HOS.Services.Set
|
|||
{
|
||||
class ISystemSettingsServer : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISystemSettingsServer()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 3, GetFirmwareVersion },
|
||||
{ 4, GetFirmwareVersion2 },
|
||||
|
@ -29,185 +29,185 @@ namespace Ryujinx.HLE.HOS.Services.Set
|
|||
}
|
||||
|
||||
// GetFirmwareVersion() -> buffer<nn::settings::system::FirmwareVersion, 0x1a, 0x100>
|
||||
public static long GetFirmwareVersion(ServiceCtx context)
|
||||
public static long GetFirmwareVersion(ServiceCtx Context)
|
||||
{
|
||||
return GetFirmwareVersion2(context);
|
||||
return GetFirmwareVersion2(Context);
|
||||
}
|
||||
|
||||
// GetFirmwareVersion2() -> buffer<nn::settings::system::FirmwareVersion, 0x1a, 0x100>
|
||||
public static long GetFirmwareVersion2(ServiceCtx context)
|
||||
public static long GetFirmwareVersion2(ServiceCtx Context)
|
||||
{
|
||||
long replyPos = context.Request.RecvListBuff[0].Position;
|
||||
long replySize = context.Request.RecvListBuff[0].Size;
|
||||
long ReplyPos = Context.Request.RecvListBuff[0].Position;
|
||||
long ReplySize = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
byte[] firmwareData = GetFirmwareData(context.Device);
|
||||
byte[] FirmwareData = GetFirmwareData(Context.Device);
|
||||
|
||||
if (firmwareData != null)
|
||||
if (FirmwareData != null)
|
||||
{
|
||||
context.Memory.WriteBytes(replyPos, firmwareData);
|
||||
Context.Memory.WriteBytes(ReplyPos, FirmwareData);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const byte majorFwVersion = 0x03;
|
||||
const byte minorFwVersion = 0x00;
|
||||
const byte microFwVersion = 0x00;
|
||||
const byte unknown = 0x00; //Build?
|
||||
const byte MajorFWVersion = 0x03;
|
||||
const byte MinorFWVersion = 0x00;
|
||||
const byte MicroFWVersion = 0x00;
|
||||
const byte Unknown = 0x00; //Build?
|
||||
|
||||
const int revisionNumber = 0x0A;
|
||||
const int RevisionNumber = 0x0A;
|
||||
|
||||
const string platform = "NX";
|
||||
const string unknownHex = "7fbde2b0bba4d14107bf836e4643043d9f6c8e47";
|
||||
const string version = "3.0.0";
|
||||
const string build = "NintendoSDK Firmware for NX 3.0.0-10.0";
|
||||
const string Platform = "NX";
|
||||
const string UnknownHex = "7fbde2b0bba4d14107bf836e4643043d9f6c8e47";
|
||||
const string Version = "3.0.0";
|
||||
const string Build = "NintendoSDK Firmware for NX 3.0.0-10.0";
|
||||
|
||||
//http://switchbrew.org/index.php?title=System_Version_Title
|
||||
using (MemoryStream ms = new MemoryStream(0x100))
|
||||
using (MemoryStream MS = new MemoryStream(0x100))
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
writer.Write(majorFwVersion);
|
||||
writer.Write(minorFwVersion);
|
||||
writer.Write(microFwVersion);
|
||||
writer.Write(unknown);
|
||||
Writer.Write(MajorFWVersion);
|
||||
Writer.Write(MinorFWVersion);
|
||||
Writer.Write(MicroFWVersion);
|
||||
Writer.Write(Unknown);
|
||||
|
||||
writer.Write(revisionNumber);
|
||||
Writer.Write(RevisionNumber);
|
||||
|
||||
writer.Write(Encoding.ASCII.GetBytes(platform));
|
||||
Writer.Write(Encoding.ASCII.GetBytes(Platform));
|
||||
|
||||
ms.Seek(0x28, SeekOrigin.Begin);
|
||||
MS.Seek(0x28, SeekOrigin.Begin);
|
||||
|
||||
writer.Write(Encoding.ASCII.GetBytes(unknownHex));
|
||||
Writer.Write(Encoding.ASCII.GetBytes(UnknownHex));
|
||||
|
||||
ms.Seek(0x68, SeekOrigin.Begin);
|
||||
MS.Seek(0x68, SeekOrigin.Begin);
|
||||
|
||||
writer.Write(Encoding.ASCII.GetBytes(version));
|
||||
Writer.Write(Encoding.ASCII.GetBytes(Version));
|
||||
|
||||
ms.Seek(0x80, SeekOrigin.Begin);
|
||||
MS.Seek(0x80, SeekOrigin.Begin);
|
||||
|
||||
writer.Write(Encoding.ASCII.GetBytes(build));
|
||||
Writer.Write(Encoding.ASCII.GetBytes(Build));
|
||||
|
||||
context.Memory.WriteBytes(replyPos, ms.ToArray());
|
||||
Context.Memory.WriteBytes(ReplyPos, MS.ToArray());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetColorSetId() -> i32
|
||||
public static long GetColorSetId(ServiceCtx context)
|
||||
public static long GetColorSetId(ServiceCtx Context)
|
||||
{
|
||||
context.ResponseData.Write((int)context.Device.System.State.ThemeColor);
|
||||
Context.ResponseData.Write((int)Context.Device.System.State.ThemeColor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetColorSetId() -> i32
|
||||
public static long SetColorSetId(ServiceCtx context)
|
||||
public static long SetColorSetId(ServiceCtx Context)
|
||||
{
|
||||
int colorSetId = context.RequestData.ReadInt32();
|
||||
int ColorSetId = Context.RequestData.ReadInt32();
|
||||
|
||||
context.Device.System.State.ThemeColor = (ColorSet)colorSetId;
|
||||
Context.Device.System.State.ThemeColor = (ColorSet)ColorSetId;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetSettingsItemValue(buffer<nn::settings::SettingsName, 0x19, 0x48>, buffer<nn::settings::SettingsItemKey, 0x19, 0x48>) -> (u64, buffer<unknown, 6, 0>)
|
||||
public static long GetSettingsItemValue(ServiceCtx context)
|
||||
public static long GetSettingsItemValue(ServiceCtx Context)
|
||||
{
|
||||
long classPos = context.Request.PtrBuff[0].Position;
|
||||
long classSize = context.Request.PtrBuff[0].Size;
|
||||
long ClassPos = Context.Request.PtrBuff[0].Position;
|
||||
long ClassSize = Context.Request.PtrBuff[0].Size;
|
||||
|
||||
long namePos = context.Request.PtrBuff[1].Position;
|
||||
long nameSize = context.Request.PtrBuff[1].Size;
|
||||
long NamePos = Context.Request.PtrBuff[1].Position;
|
||||
long NameSize = Context.Request.PtrBuff[1].Size;
|
||||
|
||||
long replyPos = context.Request.ReceiveBuff[0].Position;
|
||||
long replySize = context.Request.ReceiveBuff[0].Size;
|
||||
long ReplyPos = Context.Request.ReceiveBuff[0].Position;
|
||||
long ReplySize = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
byte[] Class = context.Memory.ReadBytes(classPos, classSize);
|
||||
byte[] name = context.Memory.ReadBytes(namePos, nameSize);
|
||||
byte[] Class = Context.Memory.ReadBytes(ClassPos, ClassSize);
|
||||
byte[] Name = Context.Memory.ReadBytes(NamePos, NameSize);
|
||||
|
||||
string askedSetting = Encoding.ASCII.GetString(Class).Trim('\0') + "!" + Encoding.ASCII.GetString(name).Trim('\0');
|
||||
string AskedSetting = Encoding.ASCII.GetString(Class).Trim('\0') + "!" + Encoding.ASCII.GetString(Name).Trim('\0');
|
||||
|
||||
NxSettings.Settings.TryGetValue(askedSetting, out object nxSetting);
|
||||
NxSettings.Settings.TryGetValue(AskedSetting, out object NxSetting);
|
||||
|
||||
if (nxSetting != null)
|
||||
if (NxSetting != null)
|
||||
{
|
||||
byte[] settingBuffer = new byte[replySize];
|
||||
byte[] SettingBuffer = new byte[ReplySize];
|
||||
|
||||
if (nxSetting is string stringValue)
|
||||
if (NxSetting is string StringValue)
|
||||
{
|
||||
if (stringValue.Length + 1 > replySize)
|
||||
if (StringValue.Length + 1 > ReplySize)
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceSet, $"{askedSetting} String value size is too big!");
|
||||
Logger.PrintError(LogClass.ServiceSet, $"{AskedSetting} String value size is too big!");
|
||||
}
|
||||
else
|
||||
{
|
||||
settingBuffer = Encoding.ASCII.GetBytes(stringValue + "\0");
|
||||
SettingBuffer = Encoding.ASCII.GetBytes(StringValue + "\0");
|
||||
}
|
||||
}
|
||||
|
||||
if (nxSetting is int intValue)
|
||||
if (NxSetting is int IntValue)
|
||||
{
|
||||
settingBuffer = BitConverter.GetBytes(intValue);
|
||||
SettingBuffer = BitConverter.GetBytes(IntValue);
|
||||
}
|
||||
else if (nxSetting is bool boolValue)
|
||||
else if (NxSetting is bool BoolValue)
|
||||
{
|
||||
settingBuffer[0] = boolValue ? (byte)1 : (byte)0;
|
||||
SettingBuffer[0] = BoolValue ? (byte)1 : (byte)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(nxSetting.GetType().Name);
|
||||
throw new NotImplementedException(NxSetting.GetType().Name);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(replyPos, settingBuffer);
|
||||
Context.Memory.WriteBytes(ReplyPos, SettingBuffer);
|
||||
|
||||
Logger.PrintDebug(LogClass.ServiceSet, $"{askedSetting} set value: {nxSetting} as {nxSetting.GetType()}");
|
||||
Logger.PrintDebug(LogClass.ServiceSet, $"{AskedSetting} set value: {NxSetting} as {NxSetting.GetType()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintError(LogClass.ServiceSet, $"{askedSetting} not found!");
|
||||
Logger.PrintError(LogClass.ServiceSet, $"{AskedSetting} not found!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static byte[] GetFirmwareData(Switch device)
|
||||
public static byte[] GetFirmwareData(Switch Device)
|
||||
{
|
||||
byte[] data = null;
|
||||
long titleId = 0x0100000000000809;
|
||||
string contentPath = device.System.ContentManager.GetInstalledContentPath(titleId, StorageId.NandSystem, ContentType.Data);
|
||||
byte[] Data = null;
|
||||
long TitleId = 0x0100000000000809;
|
||||
string ContentPath = Device.System.ContentManager.GetInstalledContentPath(TitleId, StorageId.NandSystem, ContentType.Data);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(contentPath))
|
||||
if(string.IsNullOrWhiteSpace(ContentPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string firmwareTitlePath = device.FileSystem.SwitchPathToSystemPath(contentPath);
|
||||
FileStream firmwareStream = File.Open(firmwareTitlePath, FileMode.Open, FileAccess.Read);
|
||||
Nca firmwareContent = new Nca(device.System.KeySet, firmwareStream, false);
|
||||
Stream romFsStream = firmwareContent.OpenSection(0, false, device.System.FsIntegrityCheckLevel);
|
||||
string FirmwareTitlePath = Device.FileSystem.SwitchPathToSystemPath(ContentPath);
|
||||
FileStream FirmwareStream = File.Open(FirmwareTitlePath, FileMode.Open, FileAccess.Read);
|
||||
Nca FirmwareContent = new Nca(Device.System.KeySet, FirmwareStream, false);
|
||||
Stream RomFsStream = FirmwareContent.OpenSection(0, false, Device.System.FsIntegrityCheckLevel);
|
||||
|
||||
if(romFsStream == null)
|
||||
if(RomFsStream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Romfs firmwareRomFs = new Romfs(romFsStream);
|
||||
Romfs FirmwareRomFs = new Romfs(RomFsStream);
|
||||
|
||||
using(MemoryStream memoryStream = new MemoryStream())
|
||||
using(MemoryStream MemoryStream = new MemoryStream())
|
||||
{
|
||||
using (Stream firmwareFile = firmwareRomFs.OpenFile("/file"))
|
||||
using (Stream FirmwareFile = FirmwareRomFs.OpenFile("/file"))
|
||||
{
|
||||
firmwareFile.CopyTo(memoryStream);
|
||||
FirmwareFile.CopyTo(MemoryStream);
|
||||
}
|
||||
|
||||
data = memoryStream.ToArray();
|
||||
Data = MemoryStream.ToArray();
|
||||
}
|
||||
|
||||
firmwareContent.Dispose();
|
||||
firmwareStream.Dispose();
|
||||
FirmwareContent.Dispose();
|
||||
FirmwareStream.Dispose();
|
||||
|
||||
return data;
|
||||
return Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
|
|||
static class NxSettings
|
||||
{
|
||||
//Generated automatically from a Switch 3.0 config file (Tid: 0100000000000818).
|
||||
public static Dictionary<string, object> Settings = new Dictionary<string, object>
|
||||
public static Dictionary<string, object> Settings = new Dictionary<string, object>()
|
||||
{
|
||||
{ "account!na_required_for_network_service", true },
|
||||
{ "account.daemon!background_awaking_periodicity", 10800 },
|
||||
|
@ -1705,7 +1705,7 @@ namespace Ryujinx.HLE.HOS.Services.Set
|
|||
{ "time!standard_steady_clock_rtc_update_interval_minutes", 5 },
|
||||
{ "time!standard_network_clock_sufficient_accuracy_minutes", 43200 },
|
||||
{ "usb!usb30_force_enabled", false },
|
||||
{ "wlan_debug!skip_wlan_boot", false }
|
||||
{ "wlan_debug!skip_wlan_boot", false },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@
|
|||
BadHints,
|
||||
Protocol,
|
||||
Overflow,
|
||||
Max
|
||||
Max,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
|
|||
{
|
||||
class IResolver : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IResolver()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, SetDnsAddressesPrivate },
|
||||
{ 1, GetDnsAddressesPrivate },
|
||||
|
@ -28,65 +28,65 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
|
|||
{ 5, GetGaiStringError },
|
||||
{ 8, RequestCancelHandle },
|
||||
{ 9, CancelSocketCall },
|
||||
{ 11, ClearDnsAddresses }
|
||||
{ 11, ClearDnsAddresses },
|
||||
};
|
||||
}
|
||||
|
||||
private long SerializeHostEnt(ServiceCtx context, IPHostEntry hostEntry, List<IPAddress> addresses = null)
|
||||
private long SerializeHostEnt(ServiceCtx Context, IPHostEntry HostEntry, List<IPAddress> Addresses = null)
|
||||
{
|
||||
long originalBufferPosition = context.Request.ReceiveBuff[0].Position;
|
||||
long bufferPosition = originalBufferPosition;
|
||||
long bufferSize = context.Request.ReceiveBuff[0].Size;
|
||||
long OriginalBufferPosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long BufferPosition = OriginalBufferPosition;
|
||||
long BufferSize = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
string hostName = hostEntry.HostName + '\0';
|
||||
string HostName = HostEntry.HostName + '\0';
|
||||
|
||||
// h_name
|
||||
context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(hostName));
|
||||
bufferPosition += hostName.Length;
|
||||
Context.Memory.WriteBytes(BufferPosition, Encoding.ASCII.GetBytes(HostName));
|
||||
BufferPosition += HostName.Length;
|
||||
|
||||
// h_aliases list size
|
||||
context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(hostEntry.Aliases.Length));
|
||||
bufferPosition += 4;
|
||||
Context.Memory.WriteInt32(BufferPosition, IPAddress.HostToNetworkOrder(HostEntry.Aliases.Length));
|
||||
BufferPosition += 4;
|
||||
|
||||
// Actual aliases
|
||||
foreach (string alias in hostEntry.Aliases)
|
||||
foreach (string Alias in HostEntry.Aliases)
|
||||
{
|
||||
context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(alias + '\0'));
|
||||
bufferPosition += alias.Length + 1;
|
||||
Context.Memory.WriteBytes(BufferPosition, Encoding.ASCII.GetBytes(Alias + '\0'));
|
||||
BufferPosition += Alias.Length + 1;
|
||||
}
|
||||
|
||||
// h_addrtype but it's a short (also only support IPv4)
|
||||
context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)2));
|
||||
bufferPosition += 2;
|
||||
Context.Memory.WriteInt16(BufferPosition, IPAddress.HostToNetworkOrder((short)2));
|
||||
BufferPosition += 2;
|
||||
|
||||
// h_length but it's a short
|
||||
context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)4));
|
||||
bufferPosition += 2;
|
||||
Context.Memory.WriteInt16(BufferPosition, IPAddress.HostToNetworkOrder((short)4));
|
||||
BufferPosition += 2;
|
||||
|
||||
// Ip address count, we can only support ipv4 (blame Nintendo)
|
||||
context.Memory.WriteInt32(bufferPosition, addresses != null ? IPAddress.HostToNetworkOrder(addresses.Count) : 0);
|
||||
bufferPosition += 4;
|
||||
Context.Memory.WriteInt32(BufferPosition, Addresses != null ? IPAddress.HostToNetworkOrder(Addresses.Count) : 0);
|
||||
BufferPosition += 4;
|
||||
|
||||
if (addresses != null)
|
||||
if (Addresses != null)
|
||||
{
|
||||
foreach (IPAddress ip in addresses)
|
||||
foreach (IPAddress Ip in Addresses)
|
||||
{
|
||||
context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(BitConverter.ToInt32(ip.GetAddressBytes(), 0)));
|
||||
bufferPosition += 4;
|
||||
Context.Memory.WriteInt32(BufferPosition, IPAddress.HostToNetworkOrder(BitConverter.ToInt32(Ip.GetAddressBytes(), 0)));
|
||||
BufferPosition += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return bufferPosition - originalBufferPosition;
|
||||
return BufferPosition - OriginalBufferPosition;
|
||||
}
|
||||
|
||||
private string GetGaiStringErrorFromErrorCode(GaiError errorCode)
|
||||
private string GetGaiStringErrorFromErrorCode(GaiError ErrorCode)
|
||||
{
|
||||
if (errorCode > GaiError.Max)
|
||||
if (ErrorCode > GaiError.Max)
|
||||
{
|
||||
errorCode = GaiError.Max;
|
||||
ErrorCode = GaiError.Max;
|
||||
}
|
||||
|
||||
switch (errorCode)
|
||||
switch (ErrorCode)
|
||||
{
|
||||
case GaiError.AddressFamily:
|
||||
return "Address family for hostname not supported";
|
||||
|
@ -123,275 +123,275 @@ namespace Ryujinx.HLE.HOS.Services.Sfdnsres
|
|||
}
|
||||
}
|
||||
|
||||
private string GetHostStringErrorFromErrorCode(NetDbError errorCode)
|
||||
private string GetHostStringErrorFromErrorCode(NetDBError ErrorCode)
|
||||
{
|
||||
if (errorCode <= NetDbError.Internal)
|
||||
if (ErrorCode <= NetDBError.Internal)
|
||||
{
|
||||
return "Resolver internal error";
|
||||
}
|
||||
|
||||
switch (errorCode)
|
||||
switch (ErrorCode)
|
||||
{
|
||||
case NetDbError.Success:
|
||||
case NetDBError.Success:
|
||||
return "Resolver Error 0 (no error)";
|
||||
case NetDbError.HostNotFound:
|
||||
case NetDBError.HostNotFound:
|
||||
return "Unknown host";
|
||||
case NetDbError.TryAgain:
|
||||
case NetDBError.TryAgain:
|
||||
return "Host name lookup failure";
|
||||
case NetDbError.NoRecovery:
|
||||
case NetDBError.NoRecovery:
|
||||
return "Unknown server error";
|
||||
case NetDbError.NoData:
|
||||
case NetDBError.NoData:
|
||||
return "No address associated with name";
|
||||
default:
|
||||
return "Unknown resolver error";
|
||||
}
|
||||
}
|
||||
|
||||
private List<IPAddress> GetIpv4Addresses(IPHostEntry hostEntry)
|
||||
private List<IPAddress> GetIPV4Addresses(IPHostEntry HostEntry)
|
||||
{
|
||||
List<IPAddress> result = new List<IPAddress>();
|
||||
foreach (IPAddress ip in hostEntry.AddressList)
|
||||
List<IPAddress> Result = new List<IPAddress>();
|
||||
foreach (IPAddress Ip in HostEntry.AddressList)
|
||||
{
|
||||
if (ip.AddressFamily == AddressFamily.InterNetwork)
|
||||
result.Add(ip);
|
||||
if (Ip.AddressFamily == AddressFamily.InterNetwork)
|
||||
Result.Add(Ip);
|
||||
}
|
||||
return result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// SetDnsAddressesPrivate(u32, buffer<unknown, 5, 0>)
|
||||
public long SetDnsAddressesPrivate(ServiceCtx context)
|
||||
public long SetDnsAddressesPrivate(ServiceCtx Context)
|
||||
{
|
||||
uint unknown0 = context.RequestData.ReadUInt32();
|
||||
long bufferPosition = context.Request.SendBuff[0].Position;
|
||||
long bufferSize = context.Request.SendBuff[0].Size;
|
||||
uint Unknown0 = Context.RequestData.ReadUInt32();
|
||||
long BufferPosition = Context.Request.SendBuff[0].Position;
|
||||
long BufferSize = Context.Request.SendBuff[0].Size;
|
||||
|
||||
// TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness.
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {unknown0}");
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {Unknown0}");
|
||||
|
||||
return MakeError(ErrorModule.Os, 1023);
|
||||
}
|
||||
|
||||
// GetDnsAddressPrivate(u32) -> buffer<unknown, 6, 0>
|
||||
public long GetDnsAddressesPrivate(ServiceCtx context)
|
||||
public long GetDnsAddressesPrivate(ServiceCtx Context)
|
||||
{
|
||||
uint unknown0 = context.RequestData.ReadUInt32();
|
||||
uint Unknown0 = Context.RequestData.ReadUInt32();
|
||||
|
||||
// TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness.
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {unknown0}");
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {Unknown0}");
|
||||
|
||||
return MakeError(ErrorModule.Os, 1023);
|
||||
}
|
||||
|
||||
// GetHostByName(u8, u32, u64, pid, buffer<unknown, 5, 0>) -> (u32, u32, u32, buffer<unknown, 6, 0>)
|
||||
public long GetHostByName(ServiceCtx context)
|
||||
public long GetHostByName(ServiceCtx Context)
|
||||
{
|
||||
byte[] rawName = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size);
|
||||
string name = Encoding.ASCII.GetString(rawName).TrimEnd('\0');
|
||||
byte[] RawName = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, Context.Request.SendBuff[0].Size);
|
||||
string Name = Encoding.ASCII.GetString(RawName).TrimEnd('\0');
|
||||
|
||||
// TODO: use params
|
||||
bool enableNsdResolve = context.RequestData.ReadInt32() == 1;
|
||||
int timeOut = context.RequestData.ReadInt32();
|
||||
ulong pidPlaceholder = context.RequestData.ReadUInt64();
|
||||
bool EnableNsdResolve = Context.RequestData.ReadInt32() == 1;
|
||||
int TimeOut = Context.RequestData.ReadInt32();
|
||||
ulong PidPlaceholder = Context.RequestData.ReadUInt64();
|
||||
|
||||
IPHostEntry hostEntry = null;
|
||||
IPHostEntry HostEntry = null;
|
||||
|
||||
NetDbError netDbErrorCode = NetDbError.Success;
|
||||
GaiError errno = GaiError.Overflow;
|
||||
long serializedSize = 0;
|
||||
NetDBError NetDBErrorCode = NetDBError.Success;
|
||||
GaiError Errno = GaiError.Overflow;
|
||||
long SerializedSize = 0;
|
||||
|
||||
if (name.Length <= 255)
|
||||
if (Name.Length <= 255)
|
||||
{
|
||||
try
|
||||
{
|
||||
hostEntry = Dns.GetHostEntry(name);
|
||||
HostEntry = Dns.GetHostEntry(Name);
|
||||
}
|
||||
catch (SocketException exception)
|
||||
catch (SocketException Exception)
|
||||
{
|
||||
netDbErrorCode = NetDbError.Internal;
|
||||
NetDBErrorCode = NetDBError.Internal;
|
||||
|
||||
if (exception.ErrorCode == 11001)
|
||||
if (Exception.ErrorCode == 11001)
|
||||
{
|
||||
netDbErrorCode = NetDbError.HostNotFound;
|
||||
errno = GaiError.NoData;
|
||||
NetDBErrorCode = NetDBError.HostNotFound;
|
||||
Errno = GaiError.NoData;
|
||||
}
|
||||
else if (exception.ErrorCode == 11002)
|
||||
else if (Exception.ErrorCode == 11002)
|
||||
{
|
||||
netDbErrorCode = NetDbError.TryAgain;
|
||||
NetDBErrorCode = NetDBError.TryAgain;
|
||||
}
|
||||
else if (exception.ErrorCode == 11003)
|
||||
else if (Exception.ErrorCode == 11003)
|
||||
{
|
||||
netDbErrorCode = NetDbError.NoRecovery;
|
||||
NetDBErrorCode = NetDBError.NoRecovery;
|
||||
}
|
||||
else if (exception.ErrorCode == 11004)
|
||||
else if (Exception.ErrorCode == 11004)
|
||||
{
|
||||
netDbErrorCode = NetDbError.NoData;
|
||||
NetDBErrorCode = NetDBError.NoData;
|
||||
}
|
||||
else if (exception.ErrorCode == 10060)
|
||||
else if (Exception.ErrorCode == 10060)
|
||||
{
|
||||
errno = GaiError.Again;
|
||||
Errno = GaiError.Again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
netDbErrorCode = NetDbError.HostNotFound;
|
||||
NetDBErrorCode = NetDBError.HostNotFound;
|
||||
}
|
||||
|
||||
if (hostEntry != null)
|
||||
if (HostEntry != null)
|
||||
{
|
||||
errno = GaiError.Success;
|
||||
Errno = GaiError.Success;
|
||||
|
||||
List<IPAddress> addresses = GetIpv4Addresses(hostEntry);
|
||||
List<IPAddress> Addresses = GetIPV4Addresses(HostEntry);
|
||||
|
||||
if (addresses.Count == 0)
|
||||
if (Addresses.Count == 0)
|
||||
{
|
||||
errno = GaiError.NoData;
|
||||
netDbErrorCode = NetDbError.NoAddress;
|
||||
Errno = GaiError.NoData;
|
||||
NetDBErrorCode = NetDBError.NoAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
serializedSize = SerializeHostEnt(context, hostEntry, addresses);
|
||||
SerializedSize = SerializeHostEnt(Context, HostEntry, Addresses);
|
||||
}
|
||||
}
|
||||
|
||||
context.ResponseData.Write((int)netDbErrorCode);
|
||||
context.ResponseData.Write((int)errno);
|
||||
context.ResponseData.Write(serializedSize);
|
||||
Context.ResponseData.Write((int)NetDBErrorCode);
|
||||
Context.ResponseData.Write((int)Errno);
|
||||
Context.ResponseData.Write(SerializedSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetHostByAddr(u32, u32, u32, u64, pid, buffer<unknown, 5, 0>) -> (u32, u32, u32, buffer<unknown, 6, 0>)
|
||||
public long GetHostByAddress(ServiceCtx context)
|
||||
public long GetHostByAddress(ServiceCtx Context)
|
||||
{
|
||||
byte[] rawIp = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size);
|
||||
byte[] RawIp = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position, Context.Request.SendBuff[0].Size);
|
||||
|
||||
// TODO: use params
|
||||
uint socketLength = context.RequestData.ReadUInt32();
|
||||
uint type = context.RequestData.ReadUInt32();
|
||||
int timeOut = context.RequestData.ReadInt32();
|
||||
ulong pidPlaceholder = context.RequestData.ReadUInt64();
|
||||
uint SocketLength = Context.RequestData.ReadUInt32();
|
||||
uint Type = Context.RequestData.ReadUInt32();
|
||||
int TimeOut = Context.RequestData.ReadInt32();
|
||||
ulong PidPlaceholder = Context.RequestData.ReadUInt64();
|
||||
|
||||
IPHostEntry hostEntry = null;
|
||||
IPHostEntry HostEntry = null;
|
||||
|
||||
NetDbError netDbErrorCode = NetDbError.Success;
|
||||
GaiError errno = GaiError.AddressFamily;
|
||||
long serializedSize = 0;
|
||||
NetDBError NetDBErrorCode = NetDBError.Success;
|
||||
GaiError Errno = GaiError.AddressFamily;
|
||||
long SerializedSize = 0;
|
||||
|
||||
if (rawIp.Length == 4)
|
||||
if (RawIp.Length == 4)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPAddress address = new IPAddress(rawIp);
|
||||
IPAddress Address = new IPAddress(RawIp);
|
||||
|
||||
hostEntry = Dns.GetHostEntry(address);
|
||||
HostEntry = Dns.GetHostEntry(Address);
|
||||
}
|
||||
catch (SocketException exception)
|
||||
catch (SocketException Exception)
|
||||
{
|
||||
netDbErrorCode = NetDbError.Internal;
|
||||
if (exception.ErrorCode == 11001)
|
||||
NetDBErrorCode = NetDBError.Internal;
|
||||
if (Exception.ErrorCode == 11001)
|
||||
{
|
||||
netDbErrorCode = NetDbError.HostNotFound;
|
||||
errno = GaiError.NoData;
|
||||
NetDBErrorCode = NetDBError.HostNotFound;
|
||||
Errno = GaiError.NoData;
|
||||
}
|
||||
else if (exception.ErrorCode == 11002)
|
||||
else if (Exception.ErrorCode == 11002)
|
||||
{
|
||||
netDbErrorCode = NetDbError.TryAgain;
|
||||
NetDBErrorCode = NetDBError.TryAgain;
|
||||
}
|
||||
else if (exception.ErrorCode == 11003)
|
||||
else if (Exception.ErrorCode == 11003)
|
||||
{
|
||||
netDbErrorCode = NetDbError.NoRecovery;
|
||||
NetDBErrorCode = NetDBError.NoRecovery;
|
||||
}
|
||||
else if (exception.ErrorCode == 11004)
|
||||
else if (Exception.ErrorCode == 11004)
|
||||
{
|
||||
netDbErrorCode = NetDbError.NoData;
|
||||
NetDBErrorCode = NetDBError.NoData;
|
||||
}
|
||||
else if (exception.ErrorCode == 10060)
|
||||
else if (Exception.ErrorCode == 10060)
|
||||
{
|
||||
errno = GaiError.Again;
|
||||
Errno = GaiError.Again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
netDbErrorCode = NetDbError.NoAddress;
|
||||
NetDBErrorCode = NetDBError.NoAddress;
|
||||
}
|
||||
|
||||
if (hostEntry != null)
|
||||
if (HostEntry != null)
|
||||
{
|
||||
errno = GaiError.Success;
|
||||
serializedSize = SerializeHostEnt(context, hostEntry, GetIpv4Addresses(hostEntry));
|
||||
Errno = GaiError.Success;
|
||||
SerializedSize = SerializeHostEnt(Context, HostEntry, GetIPV4Addresses(HostEntry));
|
||||
}
|
||||
|
||||
context.ResponseData.Write((int)netDbErrorCode);
|
||||
context.ResponseData.Write((int)errno);
|
||||
context.ResponseData.Write(serializedSize);
|
||||
Context.ResponseData.Write((int)NetDBErrorCode);
|
||||
Context.ResponseData.Write((int)Errno);
|
||||
Context.ResponseData.Write(SerializedSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetHostStringError(u32) -> buffer<unknown, 6, 0>
|
||||
public long GetHostStringError(ServiceCtx context)
|
||||
public long GetHostStringError(ServiceCtx Context)
|
||||
{
|
||||
long resultCode = MakeError(ErrorModule.Os, 1023);
|
||||
NetDbError errorCode = (NetDbError)context.RequestData.ReadInt32();
|
||||
string errorString = GetHostStringErrorFromErrorCode(errorCode);
|
||||
long ResultCode = MakeError(ErrorModule.Os, 1023);
|
||||
NetDBError ErrorCode = (NetDBError)Context.RequestData.ReadInt32();
|
||||
string ErrorString = GetHostStringErrorFromErrorCode(ErrorCode);
|
||||
|
||||
if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size)
|
||||
if (ErrorString.Length + 1 <= Context.Request.ReceiveBuff[0].Size)
|
||||
{
|
||||
resultCode = 0;
|
||||
context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0'));
|
||||
ResultCode = 0;
|
||||
Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(ErrorString + '\0'));
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
return ResultCode;
|
||||
}
|
||||
|
||||
// GetGaiStringError(u32) -> buffer<unknown, 6, 0>
|
||||
public long GetGaiStringError(ServiceCtx context)
|
||||
public long GetGaiStringError(ServiceCtx Context)
|
||||
{
|
||||
long resultCode = MakeError(ErrorModule.Os, 1023);
|
||||
GaiError errorCode = (GaiError)context.RequestData.ReadInt32();
|
||||
string errorString = GetGaiStringErrorFromErrorCode(errorCode);
|
||||
long ResultCode = MakeError(ErrorModule.Os, 1023);
|
||||
GaiError ErrorCode = (GaiError)Context.RequestData.ReadInt32();
|
||||
string ErrorString = GetGaiStringErrorFromErrorCode(ErrorCode);
|
||||
|
||||
if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size)
|
||||
if (ErrorString.Length + 1 <= Context.Request.ReceiveBuff[0].Size)
|
||||
{
|
||||
resultCode = 0;
|
||||
context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0'));
|
||||
ResultCode = 0;
|
||||
Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(ErrorString + '\0'));
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
return ResultCode;
|
||||
}
|
||||
|
||||
// RequestCancelHandle(u64, pid) -> u32
|
||||
public long RequestCancelHandle(ServiceCtx context)
|
||||
public long RequestCancelHandle(ServiceCtx Context)
|
||||
{
|
||||
ulong unknown0 = context.RequestData.ReadUInt64();
|
||||
ulong Unknown0 = Context.RequestData.ReadUInt64();
|
||||
|
||||
context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {unknown0}");
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {Unknown0}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CancelSocketCall(u32, u64, pid)
|
||||
public long CancelSocketCall(ServiceCtx context)
|
||||
public long CancelSocketCall(ServiceCtx Context)
|
||||
{
|
||||
uint unknown0 = context.RequestData.ReadUInt32();
|
||||
ulong unknown1 = context.RequestData.ReadUInt64();
|
||||
uint Unknown0 = Context.RequestData.ReadUInt32();
|
||||
ulong Unknown1 = Context.RequestData.ReadUInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {unknown0} - " +
|
||||
$"Unknown1: {unknown1}");
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {Unknown0} - " +
|
||||
$"Unknown1: {Unknown1}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ClearDnsAddresses(u32)
|
||||
public long ClearDnsAddresses(ServiceCtx context)
|
||||
public long ClearDnsAddresses(ServiceCtx Context)
|
||||
{
|
||||
uint unknown0 = context.RequestData.ReadUInt32();
|
||||
uint Unknown0 = Context.RequestData.ReadUInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {unknown0}");
|
||||
Logger.PrintStub(LogClass.ServiceSfdnsres, $"Stubbed. Unknown0: {Unknown0}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue