Difference between revisions of "SMC"

From Nintendo Switch Brew
Jump to navigation Jump to search
Line 22: Line 22:
 
If bit ''n'' is set in the argument type then parameter X''n'' is treated as a pointer and the kernel will setup address translation for it in [[SVC#svcCallSecureMonitor|svcCallSecureMonitor]].
 
If bit ''n'' is set in the argument type then parameter X''n'' is treated as a pointer and the kernel will setup address translation for it in [[SVC#svcCallSecureMonitor|svcCallSecureMonitor]].
  
== Id 0 ==
+
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 [[SVC|svcCallSecureMonitor]].
 
Functions exposed to user-mode processes using [[SVC|svcCallSecureMonitor]].
  
 
{| class=wikitable
 
{| class=wikitable
! Sub-Id || Name || In || Out
+
! Sub-ID || Name || In || Out
 
|-
 
|-
 
| 0xC3000401 || SetConfig || ||
 
| 0xC3000401 || SetConfig || ||
 
|-
 
|-
| 0xC3000002 || GetConfig (Same as Id 1 Sub-Id 4.) || ||
+
| 0xC3000002 || GetConfig (Same as ID 1, Sub-ID 4) || ||
 
|-
 
|-
 
| 0xC3000003 || CheckStatus || ||
 
| 0xC3000003 || CheckStatus || ||
Line 38: Line 40:
 
| 0xC3000E05 || ExpMod || ||
 
| 0xC3000E05 || ExpMod || ||
 
|-
 
|-
| 0xC3000006 || GetRandomBytes (Same as Id 1 Sub-Id 5.) || ||
+
| 0xC3000006 || GetRandomBytes (Same as ID 1, Sub-ID 5) || ||
 
|-
 
|-
 
| 0xC3000007 || [[#GenerateAesKek]] || ||
 
| 0xC3000007 || [[#GenerateAesKek]] || ||
Line 58: Line 60:
 
| 0xC300060F || [[#PublicRsa]] || ||
 
| 0xC300060F || [[#PublicRsa]] || ||
 
|-
 
|-
| 0xC3000610 || [[#UnwrapRsaEncryptedAesKey]] || ||
+
| 0xC3000610 || [[#UnwrapPreparedAesKey]] || ||
 
|-
 
|-
| 0xC3000011 || [[#LoadRsaWrappedAesKey]] || ||
+
| 0xC3000011 || [[#LoadPreparedAesKey]] || ||
 
|-
 
|-
| 0xC3000012 || [2.0.0+] GenerateRsaWrappedAesKek || ||
+
| 0xC3000012 || [2.0.0+] GeneratePreparedAesKek || ||
 
|}
 
|}
  
Line 74: Line 76:
 
** This means: Plaintext kek keys never leave TrustZone.
 
** This means: Plaintext kek keys never leave TrustZone.
 
** Further, this means: Actual AES/RSA keys never leave TrustZone.
 
** Further, this means: Actual AES/RSA keys never leave TrustZone.
 +
 +
Note:
 +
The [[#CryptoUsecase|CryptoUsecase_PreparedAesKey]] represents a RSA wrapped AES key.
  
 
=== GenerateAesKek ===
 
=== GenerateAesKek ===
Line 113: Line 118:
 
Key must be set prior using the [[#LoadRsaPublicKey]] command.
 
Key must be set prior using the [[#LoadRsaPublicKey]] command.
  
=== UnwrapRsaEncryptedAesKey ===
+
=== UnwrapPreparedAesKey ===
 
Takes a session kek created with [[#GenerateAesKek]], and a wrapped RSA public key.
 
Takes a session kek created with [[#GenerateAesKek]], and a wrapped RSA public key.
  
Returns a session-unique AES key especially for use in [[#LoadRsaWrappedAesKey]].
+
Returns a session-unique AES key especially for use in [[#LoadPreparedAesKey]].
  
The session kek must have been created with CryptoUsecase_RsaWrappedAesKey.
+
The session kek must have been created with CryptoUsecase_PreparedAesKey.
  
=== LoadRsaWrappedAesKey ===
+
=== LoadPreparedAesKey ===
Takes a session-unique AES key from [[#UnwrapRsaEncryptedAesKey]].
+
Takes a session-unique AES key from [[#UnwrapPreparedAesKey]].
  
 
=== enum CryptoUsecase ===
 
=== enum CryptoUsecase ===
Line 133: Line 138:
 
| 2 || CryptoUsecase_PublicRsa
 
| 2 || CryptoUsecase_PublicRsa
 
|-
 
|-
| 3 || CryptoUsecase_RsaWrappedAesKey
+
| 3 || CryptoUsecase_PreparedAesKey
 
|}
 
|}
  
== Id 1 ==
+
== ID 1 ==
 
Functions exposed to the kernel internally.
 
Functions exposed to the kernel internally.
  
 
{| class=wikitable
 
{| class=wikitable
! Sub-Id || Name || In || Out
+
! Sub-ID || Name || In || Out
 
|-
 
|-
| 0xC4000001 || CpuSuspend || X1=power_state, X2=entrypoint_addr, X3=context_addr || None
+
| 0xC4000001 || [[#CpuSuspend]] || X1=power_state, X2=entrypoint_addr, X3=context_id || None
 
|-
 
|-
| 0x84000002 || CpuOff || None || None
+
| 0x84000002 || [[#CpuOff]] || None || None
 
|-
 
|-
| 0xC4000003 || CpuOn || ||
+
| 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
+
| 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=dst_addr, X2,X3,X4,X5,X6,X7=0 ||
+
| 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=unk, X2,X3,X4,X5,X6,X7=0 || X0=result
+
| 0xC3000006 || [[#Panic]] || W1=unk, X2,X3,X4,X5,X6,X7=0 || X0=result
 
|-
 
|-
 
| 0xC3000007 || [2.0.0+] ProtectKernelRegion || ||
 
| 0xC3000007 || [2.0.0+] ProtectKernelRegion || ||
Line 158: Line 163:
 
| 0xC3000008 || [2.0.0+] ReadWriteRegister || ||
 
| 0xC3000008 || [2.0.0+] ReadWriteRegister || ||
 
|}
 
|}
 +
 +
=== 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'''.
 +
 +
=== 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 '''unk''' set to 0xF00.
  
 
= Errors =
 
= Errors =
2: Invalid input
+
{| class=wikitable
3: Busy
+
! Value || Description
 +
|-
 +
| 2 || Invalid input
 +
|-
 +
| 3 || Busy
 +
|}

Revision as of 20:10, 7 December 2017

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.

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
0xC300100C #LoadRsaPrivateKey
0xC300100D #PrivateRsa
0xC300100E #LoadRsaPublicKey
0xC300060F #PublicRsa
0xC3000610 #UnwrapPreparedAesKey
0xC3000011 #LoadPreparedAesKey
0xC3000012 [2.0.0+] GeneratePreparedAesKek

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_PreparedAesKey represents a RSA wrapped AES key.

GenerateAesKek

Takes an "access key" as input, an #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 #CryptoUsecase.

LoadRsaPrivateKey

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

The session kek must have been created with CryptoUsecase_PrivateRsa.

PrivateRsa

Encrypts using Rsa private key.

Key must be set prior using the #LoadRsaPrivateKey command.

LoadRsaPublicKey

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

The session kek must have been created with CryptoUsecase_PublicRsa.

PublicRsa

Encrypts using Rsa public key.

Key must be set prior using the #LoadRsaPublicKey command.

UnwrapPreparedAesKey

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

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

The session kek must have been created with CryptoUsecase_PreparedAesKey.

LoadPreparedAesKey

Takes a session-unique AES key from #UnwrapPreparedAesKey.

enum CryptoUsecase

Value Name
0 CryptoUsecase_Aes
1 CryptoUsecase_PrivateRsa
2 CryptoUsecase_PublicRsa
3 CryptoUsecase_PreparedAesKey

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=unk, X2,X3,X4,X5,X6,X7=0 X0=result
0xC3000007 [2.0.0+] ProtectKernelRegion
0xC3000008 [2.0.0+] ReadWriteRegister

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.

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 unk set to 0xF00.

Errors

Value Description
2 Invalid input
3 Busy