diff --git a/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs b/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs index b4aebc7ea..15625fc2e 100644 --- a/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs @@ -1,13 +1,127 @@ -namespace Ryujinx.HLE.HOS.Services.Sm +using Ryujinx.Common.Logging; +using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Services.Spl.Types; + +namespace Ryujinx.HLE.HOS.Services.Spl { [Service("spl:")] [Service("spl:es")] [Service("spl:fs")] [Service("spl:manu")] [Service("spl:mig")] - [Service("spl:ssl")] + [Service("spl:ssl")] class IGeneralInterface : IpcService { public IGeneralInterface(ServiceCtx context) { } + + [CommandHipc(0)] + // GetConfig(u32 config_item) -> u64 config_value + public ResultCode GetConfig(ServiceCtx context) + { + ConfigItem configItem = (ConfigItem)context.RequestData.ReadUInt32(); + + // NOTE: Nintendo explicitly blacklists package2 hash here, amusingly. + // This is not blacklisted in safemode, but we're never in safe mode... + if (configItem == ConfigItem.Package2Hash) + { + return ResultCode.InvalidArguments; + } + + // TODO: This should call svcCallSecureMonitor using arg 0xC3000002. + // Since it's currently not implemented we can use a private method for now. + SmcResult result = SmcGetConfig(context, out ulong configValue, configItem); + + // Nintendo has some special handling here for hardware type/is_retail. + if (result == SmcResult.InvalidArgument) + { + switch (configItem) + { + case ConfigItem.HardwareType: + configValue = (ulong)HardwareType.Icosa; + result = SmcResult.Success; + break; + case ConfigItem.HardwareState: + configValue = (ulong)HardwareState.Development; + result = SmcResult.Success; + break; + default: + break; + } + } + + context.ResponseData.Write(configValue); + + return (ResultCode)((int)result << 9) | ResultCode.ModuleId; + } + + private SmcResult SmcGetConfig(ServiceCtx context, out ulong configValue, ConfigItem configItem) + { + configValue = default; + + SystemVersion version = context.Device.System.ContentManager.GetCurrentFirmwareVersion(); + MemorySize memorySize = context.Device.Configuration.MemoryConfiguration.ToKernelMemorySize(); + + switch (configItem) + { + case ConfigItem.DisableProgramVerification: + configValue = 0; + break; + case ConfigItem.DramId: + if (memorySize == MemorySize.MemorySize8GB) + { + configValue = (ulong)DramId.IowaSamsung8GB; + } + else if (memorySize == MemorySize.MemorySize6GB) + { + configValue = (ulong)DramId.IcosaSamsung6GB; + } + else + { + configValue = (ulong)DramId.IcosaSamsung4GB; + } + break; + case ConfigItem.SecurityEngineInterruptNumber: + return SmcResult.NotImplemented; + case ConfigItem.FuseVersion: + return SmcResult.NotImplemented; + case ConfigItem.HardwareType: + configValue = (ulong)HardwareType.Icosa; + break; + case ConfigItem.HardwareState: + configValue = (ulong)HardwareState.Production; + break; + case ConfigItem.IsRecoveryBoot: + configValue = 0; + break; + case ConfigItem.DeviceId: + return SmcResult.NotImplemented; + case ConfigItem.BootReason: + // This was removed in firmware 4.0.0. + return SmcResult.InvalidArgument; + case ConfigItem.MemoryMode: + configValue = (ulong)context.Device.Configuration.MemoryConfiguration; + break; + case ConfigItem.IsDevelopmentFunctionEnabled: + configValue = 0; + break; + case ConfigItem.KernelConfiguration: + return SmcResult.NotImplemented; + case ConfigItem.IsChargerHiZModeEnabled: + return SmcResult.NotImplemented; + case ConfigItem.QuestState: + return SmcResult.NotImplemented; + case ConfigItem.RegulatorType: + return SmcResult.NotImplemented; + case ConfigItem.DeviceUniqueKeyGeneration: + return SmcResult.NotImplemented; + case ConfigItem.Package2Hash: + return SmcResult.NotImplemented; + default: + return SmcResult.InvalidArgument; + } + + return SmcResult.Success; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Spl/ResultCode.cs new file mode 100644 index 000000000..4f61998a6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/ResultCode.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Spl +{ + enum ResultCode + { + ModuleId = 26, + ErrorCodeShift = 9, + + Success = 0, + + InvalidArguments = (101 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/Types/ConfigItem.cs b/Ryujinx.HLE/HOS/Services/Spl/Types/ConfigItem.cs new file mode 100644 index 000000000..f08bbeaa3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/Types/ConfigItem.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.HLE.HOS.Services.Spl.Types +{ + enum ConfigItem + { + // Standard config items. + DisableProgramVerification = 1, + DramId = 2, + SecurityEngineInterruptNumber = 3, + FuseVersion = 4, + HardwareType = 5, + HardwareState = 6, + IsRecoveryBoot = 7, + DeviceId = 8, + BootReason = 9, + MemoryMode = 10, + IsDevelopmentFunctionEnabled = 11, + KernelConfiguration = 12, + IsChargerHiZModeEnabled = 13, + QuestState = 14, + RegulatorType = 15, + DeviceUniqueKeyGeneration = 16, + Package2Hash = 17 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/Types/DramId.cs b/Ryujinx.HLE/HOS/Services/Spl/Types/DramId.cs new file mode 100644 index 000000000..4e1d1f0e1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/Types/DramId.cs @@ -0,0 +1,35 @@ +namespace Ryujinx.HLE.HOS.Services.Spl.Types +{ + enum DramId + { + IcosaSamsung4GB, + IcosaHynix4GB, + IcosaMicron4GB, + IowaHynix1y4GB, + IcosaSamsung6GB, + HoagHynix1y4GB, + AulaHynix1y4GB, + IowaX1X2Samsung4GB, + IowaSansung4GB, + IowaSamsung8GB, + IowaHynix4GB, + IowaMicron4GB, + HoagSamsung4GB, + HoagSamsung8GB, + HoagHynix4GB, + HoagMicron4GB, + IowaSamsung4GBY, + IowaSamsung1y4GBX, + IowaSamsung1y8GBX, + HoagSamsung1y4GBX, + IowaSamsung1y4GBY, + IowaSamsung1y8GBY, + AulaSamsung1y4GB, + HoagSamsung1y8GBX, + AulaSamsung1y4GBX, + IowaMicron1y4GB, + HoagMicron1y4GB, + AulaMicron1y4GB, + AulaSamsung1y8GBX + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/Types/HardwareState.cs b/Ryujinx.HLE/HOS/Services/Spl/Types/HardwareState.cs new file mode 100644 index 000000000..414d0f118 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/Types/HardwareState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Spl.Types +{ + enum HardwareState + { + Development, + Production + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/Types/HardwareType.cs b/Ryujinx.HLE/HOS/Services/Spl/Types/HardwareType.cs new file mode 100644 index 000000000..491eb943a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/Types/HardwareType.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Spl.Types +{ + enum HardwareType + { + Icosa, + Copper, + Hoag, + Iowa, + Calcio, + Aula + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Spl/Types/SmcResult.cs b/Ryujinx.HLE/HOS/Services/Spl/Types/SmcResult.cs new file mode 100644 index 000000000..d5f424a63 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Spl/Types/SmcResult.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.HLE.HOS.Services.Spl.Types +{ + enum SmcResult + { + Success = 0, + NotImplemented = 1, + InvalidArgument = 2, + Busy = 3, + NoAsyncOperation = 4, + InvalidAsyncOperation = 5, + NotPermitted = 6, + NotInitialized = 7, + + PsciSuccess = 0, + PsciNotSupported = -1, + PsciInvalidParameters = -2, + PsciDenied = -3, + PsciAlreadyOn = -4 + } +} \ No newline at end of file