aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs
blob: 951ed5301ba686042fba2ae147121a94c898f8c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using Ryujinx.HLE.FileSystem;
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")]
    class IGeneralInterface : IpcService
    {
        public IGeneralInterface(ServiceCtx context) { }

        [CommandCmif(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;

#pragma warning disable IDE0059 // Remove unnecessary value assignment
            SystemVersion version = context.Device.System.ContentManager.GetCurrentFirmwareVersion();
#pragma warning restore IDE0059
            MemorySize memorySize = context.Device.Configuration.MemoryConfiguration.ToKernelMemorySize();

            switch (configItem)
            {
                case ConfigItem.DisableProgramVerification:
                    configValue = 0;
                    break;
                case ConfigItem.DramId:
                    if (memorySize == MemorySize.MemorySize8GiB)
                    {
                        configValue = (ulong)DramId.IowaSamsung8GiB;
                    }
                    else if (memorySize == MemorySize.MemorySize6GiB)
                    {
                        configValue = (ulong)DramId.IcosaSamsung6GiB;
                    }
                    else
                    {
                        configValue = (ulong)DramId.IcosaSamsung4GiB;
                    }
                    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;
        }
    }
}