Secure Monitor

Revision as of 17:28, 14 April 2019 by Hexkyz (talk | contribs) (→‎DramId)

Secure Monitor Calls

The secure monitor provides two top level handlers of which each provides a range of sub handlers.

Secure Monitor Calls follow the ARM SMC calling convention up to a small change:

Bit number Bit mask Description
31 0x80000000 Set to 0 means Yielding Call; Set to 1 means Fast Call.
30 0x40000000 Set to 0 means SMC32 convention; Set to 1 means SMC64.
29-24 0x3F000000 Service Call ranges.
23-16 0x00FF0000 Must be zero.
15-8 0x0000FF00 Argument type. This is different from the ARM SMC calling convention.
7-0 0x000000FF Function number within the range call type.

If bit n is set in the argument type then parameter Xn is treated as a pointer and the kernel will setup address translation for it in svcCallSecureMonitor.

SMC arguments are passed using registers X0-X7 with X0 always sending the call sub-id and returning the result of the call.

ID 0

Functions exposed to user-mode processes using svcCallSecureMonitor. SMCs should be called from CPUID 3 (where SPL runs).

Sub-ID Name In Out
0xC3000401 SetConfig
0xC3000002 GetConfig (Same as ID 1, Sub-ID 4)
0xC3000003 CheckStatus
0xC3000404 GetResult
0xC3000E05 ExpMod
0xC3000006 GetRandomBytes (Same as ID 1, Sub-ID 5)
0xC3000007 #GenerateAesKek
0xC3000008 #LoadAesKey
0xC3000009 #CryptAes
0xC300000A #GenerateSpecificAesKey
0xC300040B #ComputeCmac
[1.0.0-4.1.0] 0xC300100C #LoadRsaOaepKey
[5.0.0+] 0xC300D60C #EncryptRsaKeyForImport
[1.0.0-4.1.0] 0xC300100D #DecryptRsaPrivateKey
[5.0.0] 0xC300100D #DecryptOrImportRsaKey
[1.0.0-4.1.0] 0xC300100E #LoadSecureExpModKey
0xC300060F #SecureExpMod
0xC3000610 #UnwrapRsaOaepWrappedTitleKey
0xC3000011 #LoadTitleKey
0xC3000012 [2.0.0+] UnwrapAesWrappedTitleKey

The overall concept here is the following:

  • All key material (AES and RSA) is stored in userspace, but it's encrypted with random AES kek's ("key encryption keys").
  • Each kek is generated as a function of an access key (picked at random).
  • The kek is generated differently depending on the #CryptoUsecase the key is used for.
    • This means: Each key is "locked" to the #CryptoUsecase it was designated for.
    • You can use a key for a different usecase, but you will only get garbage output.
  • After the kek has been generated, it is wrapped with a session-specific key and given back to userspace.
    • This means: Plaintext kek keys never leave TrustZone.
    • Further, this means: Actual AES/RSA keys never leave TrustZone.

Note: The CryptoUsecase_TitleKey represents a RSA wrapped AES key.

GenerateAesKek

Takes an "access key" as input, an #enum_CryptoUsecase.

Returns a session-unique kek for said usecase.

LoadAesKey

Takes a session kek created with #GenerateAesKek, and a wrapped AES key.

The session kek must have been created with CryptoUsecase_Aes.

CryptAes

Encrypts/decrypts using Aes (CTR and CBC).

Key must be set prior using one of the #LoadAesKey, #GenerateSpecificAesKey or #LoadRsaWrappedAesKey commands.

GenerateSpecificAesKey

Todo: This one seems unrelated to #enum_CryptoUsecase.

LoadRsaOaepKey

Takes a session kek created with #GenerateAesKek, a wrapped AES key, and a wrapped RSA private key.

The session kek must have been created with CryptoUsecase_RsaOaep.

This function was removed in 5.0.0, and replaced with #EncryptRsaKeyForImport.

EncryptRsaKeyForImport

Takes in two session keks created with #GenerateAesKek, two wrapped AES keys, an enum member, and a wrapped RSA private key.

Decrypts and validates the wrapped RSA private key with the first kek/wrapped key, and re-encrypts it with the second if valid.

The re-encrypted key is then passed to the user, for use with #DecryptOrImportRsaKey.

DecryptRsaPrivateKey

Takes a session kek created with #GenerateAesKek, a wrapped AES key, an enum member, and a wrapped RSA private key.

The session kek must have been created with CryptoUsecase_RsaPrivate.

[4.0.0+] The SMC handler when certain conditions pass and SMC_ID==0xC300100D now returns error 0x6 instead of calling the handler funcptr.

DecryptOrImportRsaKey

This function replaced #DecryptRsaPrivateKey in 5.0.0, adding an additional enum member argument.

This SMC extends DecryptRsaPrivateKey's original functionality to enable importing private keys into the security engine instead of decrypting them, when certain enum members are passed.

LoadSecureExpModKey

Takes a session kek created with #GenerateAesKek, and a wrapped RSA key.

The session kek must have been created with CryptoUsecase_RsaSecureExpMod.

This function was removed in 5.0.0, and replaced with #EncryptRsaKeyForImport.

SecureExpMod

Performs an Exp Mod operation using an exponent previously loaded with the #LoadSecureExpModKey command.

UnwrapRsaOaepWrappedTitleKey

Takes an Rsa-Oaep-wrapped TitleKey, an RSA Public Key, and a label hash.

Performs an Exp Mod operation using an exponent previously loaded with the #LoadRsaOaepKey command, and then validates/extracts a Titlekey from the resulting message.

Returns a session-unique AES key especially for use in #LoadTitleKey.

LoadTitleKey

Takes a session-unique AES key from #UnwrapAesWrappedTitleKey or #UnwrapRsaOaepWrappedTitleKey.

enum CryptoUsecase

Value Name
0 CryptoUsecase_Aes
1 CryptoUsecase_RsaPrivate
2 CryptoUsecase_RsaSecureExpMod
3 CryptoUsecase_RsaOaep

ID 1

Functions exposed to the kernel internally.

Sub-ID Name In Out
0xC4000001 #CpuSuspend X1=power_state, X2=entrypoint_addr, X3=context_id None
0x84000002 #CpuOff None None
0xC4000003 #CpuOn X1=target_cpu, X2=entrypoint_addr, X3=context_id, X4,X5,X6,X7=0 X0=result
0xC3000004 #GetConfig (Same as ID 0, Sub-ID 2) W1=config_item, X2,X3,X4,X5,X6,X7=0 X0=result, X1,X2,X3,X4=config_val
0xC3000005 #GetRandomBytes (Same as ID 0, Sub-ID 6) X1=size, X2,X3,X4,X5,X6,X7=0 X0=result, X1,X2,X3,X4,X5,X6,X7=rand_bytes
0xC3000006 #Panic W1=panic_color, X2,X3,X4,X5,X6,X7=0 X0=result
0xC3000007 [2.0.0+] #ConfigureCarveout X1=carveout_index, X2=region_phys_addr, X3=region_size, X4,X5,X6,X7=0 X0=result
0xC3000008 [2.0.0+] #ReadWriteRegister X1=reg_addr, W2=rw_mask, W3=in_val, X4,X5,X6,X7=0 X0=result, W1=out_val

CpuSuspend

Standard ARM PCSI SMC. Suspends the CPU (CPU0).

The kernel calls this SMC on shutdown with power_state set to 0x0201001B (power level: 0x02==system; power type: 0x01==powerdown; ID: 0x1B).

CpuOff

Standard ARM PCSI SMC. Turns off the CPU (CPU1, CPU2 or CPU3).

CpuOn

Standard ARM PCSI SMC. Turns on the CPU (CPU1, CPU2 or CPU3).

GetConfig

Takes a config_item and returns an associated config_val.

ConfigItem Name
1 #DisableProgramVerification
2 #DramId
3 #SecurityEngineIrqNumber
4 #Version
5 #HardwareType
6 #IsRetail
7 #IsRecoveryBoot
8 #DeviceId
9 [1.0.0-4.0.0] #BootReason
10 #MemoryArrange
11 #IsDebugMode
12 #KernelConfiguration
13 #IsChargerHiZModeEnabled
14 [4.0.0+] #IsKiosk
15 [5.0.0+] #NewHardwareType
16 [5.0.0+] #NewKeyGeneration
17 [5.0.0+] #Package2Hash

DisableProgramVerification

PM checks this item and if non-zero, calls fsp-pr SetEnabledProgramVerification(false).

DramId

This is extracted directly from FUSE_RESERVED_ODM4.

Value Description
0 DramId_EristaIcosaSamsung4gb
1 DramId_EristaIcosaHynix4gb
2 DramId_EristaIcosaMicron4gb
3 Reserved
4 DramId_EristaIcosaSamsung6gb
5 [4.0.0+] Reserved (DramId_EristaIcosaHynix6gb)
6 [4.0.0+] Reserved (DramId_EristaIcosaMicron6gb)
7 [5.0.0+] DramId_MarikoIowax1x2Samsung4gb ([4.0.0-4.1.0] Reserved)
8 [5.0.0+] DramId_MarikoIowaSamsung4gb
9 [5.0.0+] DramId_MarikoIowaSamsung8gb
10 [6.0.0+] DramId_MarikoIowaHynix4gb ([5.0.0-5.1.0] Reserved)
11 [7.0.0+] DramId_MarikoIowaMicron4gb ([5.0.0-6.2.0] Reserved)
12 [5.0.0+] DramId_MarikoHoagSamsung4gb
13 [5.0.0+] DramId_MarikoHoagSamsung8gb
14 [7.0.0+] DramId_MarikoHoagHynix4gb ([5.0.0-6.2.0] Reserved)
15 [7.0.0+] DramId_MarikoHoagMicron4gb ([5.0.0-6.2.0] Reserved)

PCV selects memory training tables based on DramId.

Platform DramId Revision DVFS version
jetson-tx1 N/A 0x07
11_40800_01_V9.8.3_V1.6
11_68000_01_V9.8.3_V1.6
11_102000_01_V9.8.3_V1.6
11_204000_05_V9.8.3_V1.6
11_408000_02_V9.8.3_V1.6
11_665600_03_V9.8.3_V1.6
11_800000_01_V9.8.3_V1.6
11_1065600_01_V9.8.3_V1.6
11_1331200_01_V9.8.3_V1.6
11_1600000_02_V9.8.3_V1.6
nx-abcb EristaIcosaSamsung4gb 0x07
10_40800_NoCfgVersion_V9.8.7_V1.6
10_68000_NoCfgVersion_V9.8.7_V1.6
10_102000_NoCfgVersion_V9.8.7_V1.6
10_204000_NoCfgVersion_V9.8.7_V1.6
10_408000_NoCfgVersion_V9.8.7_V1.6
10_665600_NoCfgVersion_V9.8.7_V1.6
10_800000_NoCfgVersion_V9.8.7_V1.6
10_1065600_NoCfgVersion_V9.8.7_V1.6
10_1331200_NoCfgVersion_V9.8.7_V1.6
10_1600000_NoCfgVersion_V9.8.7_V1.6
nx-abcb EristaIcosaMicron4gb 0x07
10_40800_NoCfgVersion_V9.8.4_V1.6
10_68000_NoCfgVersion_V9.8.4_V1.6
10_102000_NoCfgVersion_V9.8.4_V1.6
10_204000_NoCfgVersion_V9.8.4_V1.6
10_408000_NoCfgVersion_V9.8.4_V1.6
10_665600_NoCfgVersion_V9.8.4_V1.6
10_800000_NoCfgVersion_V9.8.4_V1.6
10_1065600_NoCfgVersion_V9.8.4_V1.6
10_1331200_NoCfgVersion_V9.8.4_V1.6
10_1600000_NoCfgVersion_V9.8.4_V1.6
nx-abcb EristaIcosaHynix4gb 0x07
10_40800_NoCfgVersion_V9.8.4_V1.6
10_68000_NoCfgVersion_V9.8.4_V1.6
10_102000_NoCfgVersion_V9.8.4_V1.6
10_204000_NoCfgVersion_V9.8.4_V1.6
10_408000_NoCfgVersion_V9.8.4_V1.6
10_665600_NoCfgVersion_V9.8.4_V1.6
10_800000_NoCfgVersion_V9.8.4_V1.6
10_1065600_NoCfgVersion_V9.8.4_V1.6
10_1331200_NoCfgVersion_V9.8.4_V1.6
10_1600000_NoCfgVersion_V9.8.4_V1.6
nx-abca2 EristaIcosaSamsung4gb or EristaIcosaMicron4gb 0x07
10_40800_NoCfgVersion_V9.8.7_V1.6
10_68000_NoCfgVersion_V9.8.7_V1.6
10_102000_NoCfgVersion_V9.8.7_V1.6
10_204000_NoCfgVersion_V9.8.7_V1.6
10_408000_NoCfgVersion_V9.8.7_V1.6
10_665600_NoCfgVersion_V9.8.7_V1.6
10_800000_NoCfgVersion_V9.8.7_V1.6
10_1065600_NoCfgVersion_V9.8.7_V1.6
10_1331200_NoCfgVersion_V9.8.7_V1.6
10_1600000_NoCfgVersion_V9.8.7_V1.6
nx-abca2 EristaIcosaHynix4gb 0x07
10_40800_NoCfgVersion_V9.8.7_V1.6
10_68000_NoCfgVersion_V9.8.7_V1.6
10_102000_NoCfgVersion_V9.8.7_V1.6
10_204000_NoCfgVersion_V9.8.7_V1.6
10_408000_NoCfgVersion_V9.8.7_V1.6
10_665600_NoCfgVersion_V9.8.7_V1.6
10_800000_NoCfgVersion_V9.8.7_V1.6
10_1065600_NoCfgVersion_V9.8.7_V1.6
10_1331200_NoCfgVersion_V9.8.7_V1.6
10_1600000_NoCfgVersion_V9.8.7_V1.6
nx-abca2 EristaIcosaSamsung6gb 0x07
10_40800_NoCfgVersion_V9.8.7_V1.6
10_68000_NoCfgVersion_V9.8.7_V1.6
10_102000_NoCfgVersion_V9.8.7_V1.6
10_204000_NoCfgVersion_V9.8.7_V1.6
10_408000_NoCfgVersion_V9.8.7_V1.6
10_665600_NoCfgVersion_V9.8.7_V1.6
10_800000_NoCfgVersion_V9.8.7_V1.6
10_1065600_NoCfgVersion_V9.8.7_V1.6
10_1331200_NoCfgVersion_V9.8.7_V1.6
10_1600000_NoCfgVersion_V9.8.7_V1.6
nx-abca2 MarikoIowax1x2Samsung4gb 0x03
01_204000_NoCfgVersion_V0.3.1_V2.0
01_1331200.0_NoCfgVersion_V0.3.1_V2.0
01_1600000_NoCfgVersion_V0.3.1_V2.0
nx-abca2 MarikoIowaSamsung4gb or MarikoHoagSamsung4gb 0x03
01_204000_NoCfgVersion_V0.3.1_V2.0
01_1331200.0_NoCfgVersion_V0.3.1_V2.0
01_1600000_NoCfgVersion_V0.3.1_V2.0
nx-abca2 MarikoIowaSamsung8gb or MarikoHoagSamsung8gb 0x03
01_204000_NoCfgVersion_V0.4.2_V2.0
01_1331200.0_NoCfgVersion_V0.4.2_V2.0
01_1600000_NoCfgVersion_V0.4.2_V2.0
nx-abca2 MarikoIowaHynix4gb or MarikoHoagHynix4gb 0x03
01_204000_NoCfgVersion_V0.3.1_V2.0
01_1331200.0_NoCfgVersion_V0.3.1_V2.0
01_1600000_NoCfgVersion_V0.3.1_V2.0
nx-abca2 MarikoIowaMicron4gb or MarikoHoagMicron4gb 0x03
01_204000_NoCfgVersion_V0.4.2_V2.0
01_1331200.0_NoCfgVersion_V0.4.2_V2.0
01_1600000_NoCfgVersion_V0.4.2_V2.0

nx-abcb (Copper) is the SDEV unit. Among other differences, this has extra hardware to support HDMI output.

nx-abca2 (Icosa or Hoag in Erista, Iowa or Hoag in Mariko) hardware types are variations of the retail or EDEV form factors.

Erista memory is LPDDR4, while Mariko memory is LPDDR4X.

SecurityEngineIrqNumber

SPL uses this for setting up the security engine IRQ.

Version

The current Package1 Maxver Constant - 1.

HardwareType

[1.0.0+] This item is obtained by checking bits 8 and 2 from FUSE_RESERVED_ODM4. It can be 0 (Icosa), 1 (Copper), 2 (Hoag) or 3 (Invalid).

[4.0.0+] This item is obtained by checking bits 8, 2 and 16-19 from FUSE_RESERVED_ODM4. It can be 0 (Icosa), 1 (Copper), 2 (Hoag), 3 (Mariko) or 4 (Invalid).

[7.0.0+] This item no longer depends on fuses and can only be 0 (Icosa) or 0xF (Invalid) in retail units.

IsRetail

This item is obtained by checking bits 9 and 0-1 from FUSE_RESERVED_ODM4. It can be 0 (Debug), 1 (Retail) or 2 (Invalid).

IsRecoveryBoot

Used to determine if the system is booting from SafeMode firmware.

Under normal circumstances, this just returns bit 0 of the active bootloader info's attribute field.

DeviceId

NIM checks if this item matches the set:cal DeviceId with byte7 cleared. If they don't match, a panic is thrown.

BootReason

Used to determine how the system booted.

MemoryArrange

PM uses this item for selecting the appropriate size for each LimitableResource_Memory.

IsDebugMode

Kernel uses this to determine behavior of svcBreak positive arguments. It will break instead of just force-exiting the process which is what happens on retail.

[2.0.0+] This is also used with certain debug SVCs.

[3.0.0+] RO checks this and if set then skipping NRR rsa signatures is allowed.

The value of this field is loaded from BootConfig unsigned-config+0x10 u8 bit1.

KernelConfiguration

Kernel reads this when setting up memory-related code.

Bit 0 is a boolean determining whether kernel should it will memset various allocated memory-regions with 0x58, 0x59, 0x5A ('X', 'Y', 'Z') instead of zero. This allows Nintendo devs to find uninitialized memory bugs.

Bit 1 is a boolean determining whether kernel should forcefully enable usermode exception handlers (when false, only certain aborts (((1LL << (esr >> 26)) & 0x1115804400224001) == 0, typically data/prefetch aborts) that occur when the faulting address is in a readable region with MemoryType_CodeStatic will trigger usermode exception handlers).

Bit 2 is a boolean determining whether kernel should enable usermode access to the Performance Monitors (whether PMUSERENR_EL0 should be 1 or 0).

Bits 8-15 are a boolean determining whether kernel should call smcPanic on error instead of infinite-looping.

Bits 16-17 determine how much memory is available. 00/03 = 4 GB, 01 = 6 GB, 02 = 8 GB.

IsChargerHiZModeEnabled

This tells if the TI Charger (bq24192) is active.

NewKeyGeneration

This item is obtained from FUSE_RESERVED_ODM2 if bit 11 from FUSE_RESERVED_ODM4 is set, FUSE_RESERVED_ODM0 matches 0x8E61ECAE and FUSE_RESERVED_ODM1 matches 0xF2BA3BB2.

[5.0.0+] FS can now use this value for the KeyGeneration parameter when calling GenerateAesKek during "GetBisEncryptionKey".

IsKiosk

This item is bit 10 from FUSE_RESERVED_ODM4.

[4.0.0+] Settings uses this value to overwrite the quest flag from GetQuestFlag. This is used to detect if a Switch is a kiosk unit for display at retail stores.

NewHardwareType

This item is currently hardcoded to 0.

[5.0.0+] PCV uses this value in combination with HardwareType to configure power blocks and memory tables for different hardware.

Value SoC GPU Power Blocks
0 T210 GM20B (0x12B) max77620_sd0, max77621_cpu and max77621_gpu
1 T214 GM2?? (0x12E) max77620_sd0, max77812_cpu and max77812_gpu
2 T214 GM2?? (0x12E) max77620_sd0, max77812_cpu and max77812_gpu

Package2Hash

This is a SHA-256 hash calculated over the package2 image. Since the hash calculation is an optional step in pkg2ldr, this item is only valid in recovery mode. Otherwise, an error is returned instead.

GetRandomBytes

Takes a size and returns rand_bytes.

The kernel limits size to 0x38 (for fitting in return registers).

Panic

Issues a system panic.

The kernel always calls this with panic_color set to 0xF00.

ConfigureCarveout

Configures memory controller carveout regions.

If carveout_index is 0, region_phys_addr and region_size are used to configure MC_SECURITY_CARVEOUT4. If carveout_index is 1, region_phys_addr and region_size are used to configure MC_SECURITY_CARVEOUT5. Any other carveout_index values are invalid.

The kernel calls this with carveout_index set to 0, region_phys_addr set to 0x80060000 and region_size set to a dynamically calculated size which covers all the kernel and built-in sysmodules' DRAM regions.

ReadWriteRegister

Relays svcReadWriteRegister to the Secure Monitor.

Errors

Value Description
2 Invalid input
3 Busy