Cmep: Difference between revisions
CelesteBlue (talk | contribs) m (CelesteBlue moved page F00D Processor to Cmep) |
CelesteBlue (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
Cmep is a processor in the PS Vita that performs most of the cryptography tasks including storing and handing of the most secure keys. Cmep was named "F00D" by Team Molecule after the <code>e_machine</code> field of the ELF headers, but its official name is CMeP (?Control? MeP). Cmep is a [http://en.wikipedia.org/wiki/Media-embedded_processor Toshiba MeP-c5] core. | |||
More information can be found in Toshiba documentations. For example: https://toshiba.semicon-storage.com/info/docget.jsp?did=14997&prodName=TMPV7504XBG. | More information can be found in Toshiba documentations. For example: https://toshiba.semicon-storage.com/info/docget.jsp?did=14997&prodName=TMPV7504XBG. | ||
== Devices == | |||
See [[Physical_Memory#Cmep registers]] and [[Cmep registers]] for physical memory mapping. | |||
== Reset == | |||
Although the MeP architecture documentations specify that with EVM=0 the reset/NMI vector base is at 0x00000000, it is observed that the vector base is actually at 0x00040000. However, EVA/IVA still works as expected when EVM=1. Both [[Secure Kernel]] and [[Second Loader]] set EVM=0 at the start. This is likely a modified hardware behavior and the vector base remapping might be done when the [[First Loader]] is unmapped. | |||
== Communication == | == Communication == | ||
Communication seems to go through some sort of FIFO register. | Communication seems to go through some sort of FIFO register. | ||
=== Write === | === Write === | ||
To write, put the double word into <code>0xE0000010</code>. Next read <code>0xE0000010</code> until it returns 0, which indicates the data was read by | |||
To write, put the double word into physical address <code>0xE0000010</code>. Next read <code>0xE0000010</code> until it returns 0, which indicates the data was read by Cmep. | |||
=== Read === | === Read === | ||
To read, get a double word from <code>0xE0000000</code>. If it returns 0, no data is available. Otherwise, acknowledge that the data has been read by putting the same data into <code>0xE0000000</code>. | |||
To read, get a double word from physical address <code>0xE0000000</code>. If it returns 0, no data is available. Otherwise, acknowledge that the data has been read by ARM [[TrustZonr]] by putting the same data into <code>0xE0000000</code>. | |||
=== Extra ports === | === Extra ports === | ||
In addition to the <code>0xE0000000</code> and <code>0xE0000010</code>, the communication | |||
In addition to the <code>0xE0000000</code> and <code>0xE0000010</code>, the communication between Cmep and ARM uses some other ports. | |||
{| class='wikitable' | {| class='wikitable' | ||
Line 39: | Line 51: | ||
| YES | | YES | ||
| YES | | YES | ||
| Used to send commands to | | Used to send commands to [[Secure Modules|Secure Module]], see [[#Executing Secure Module functions|Executing Secure Module functions]] | ||
|- | |- | ||
| 0xE0000018 | | 0xE0000018 | ||
| YES | | YES | ||
| YES | | YES | ||
| Used to send commands to | | Used to send commands to [[Secure Modules|Secure Module]], see [[#Executing sm commands|Executing Secure Module functions]] | ||
|- | |- | ||
| 0xE000001C | | 0xE000001C | ||
| YES | | YES | ||
| YES | | YES | ||
| Used to send commands to | | Used to send commands to [[Secure Modules|Secure Module]], see [[#Executing sm commands|Executing Secure Module functions]] | ||
|- | |- | ||
| 0xE0000054 | | 0xE0000054 | ||
Line 69: | Line 81: | ||
| YES | | YES | ||
| YES | | YES | ||
| Used by | | Used by Cmep Command 0 to prepare Cmep to receive an address that contains the secure_kernel.enp. | ||
|- | |- | ||
| 0xE0010004 | | 0xE0010004 | ||
| YES | | YES | ||
| ? | | ? | ||
| Used by | | Used by Cmep Command 0 to check if the value written in <code>0xE0010000</code> is okay (it should return a value <= 0). | ||
|} | |} | ||
== Protocol == | == Protocol == | ||
A 32-bit command buffer is defined below. The command is sent to | |||
A 32-bit command buffer is defined below. The command is sent to Cmep with the method listed above. | |||
{| class='wikitable' | {| class='wikitable' | ||
Line 100: | Line 113: | ||
| 8 | | 8 | ||
| ID | | ID | ||
| [[ | | [[#Command ID|Command ID]] | ||
|- | |- | ||
| 7 | | 7 | ||
Line 116: | Line 129: | ||
=== Command ID === | === Command ID === | ||
There are a total of | There are a total of 17 commands. Commands pass data through the 0x100 shared buffer that is setup in command 0. | ||
==== | ==== Command 0 ==== | ||
This command is used to setup a shared buffer with | This command is used to setup a shared buffer with Cmep. Firstly, Cmep will write in <code>0xE0000000</code> either 0x200 or 0x600 (and if an error happened, 0x400?). If the value 0x600 is written, it will setup a buffer that contains the secure_kernel.enp. It will write 1 to <code>0xE0010000</code> and after that 0x0 to <code>0xE0010000</code>, next, it will wait <code>0xE0010000</code> return 0 and <code>0xE0010004</code> return a value <= 0x0. If everything goes alright, it will clear the low 2 bits of the secure_kernel.enp address (normally at 0x1F850000) and OR it with 0x1 and then write it to <code>0xE0000010</code>. After it, the process is the same that the 0x200. If the value 0x200 is written, it will set the 0x100-sized shared buffer. The physical address of the buffer is written to <code>0xE0000010</code> and then command 0x0 is written. | ||
==== | ==== Command 1 ==== | ||
This command is called by a subroutine of [[SceSblSmsched#sceSblSmSchedStopForTZS]] or [[SceSblSmsched]] module_start (if an error happened while [[SceSblSmsched]] was initializing). This command seems to be used to ask | This command is called by a subroutine of [[SceSblSmsched#sceSblSmSchedStopForTZS]] or [[SceSblSmsched]] module_start (if an error happened while [[SceSblSmsched]] was initializing). This command seems to be used to ask Cmep to remove all allocated resources (like shared memory address, loaded Secure Module, etc), and probably power off or reset it. | ||
==== | ==== Command 2 ==== | ||
Load a | Load a [[Secure Modules|Secure Module]]. | ||
{| class='wikitable' | {| class='wikitable' | ||
Line 142: | Line 155: | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
| paddr_list for | | paddr_list for [[Secure Modules|Secure Module]] ELF | ||
|- | |- | ||
| 0x8 | | 0x8 | ||
Line 166: | Line 179: | ||
| 0x20 | | 0x20 | ||
| 0x4 | | 0x4 | ||
| partition ID | | partition ID, ?Media Type? | ||
|} | |} | ||
==== | ==== Command 3 ==== | ||
Load previously suspended | Load the previously suspended [[Secure Modules|Secure Module]]. | ||
{| class='wikitable' | {| class='wikitable' | ||
Line 196: | Line 209: | ||
|} | |} | ||
==== | ==== Command 4 ==== | ||
Suspend current | Suspend the current [[Secure Modules|Secure Module]]. | ||
{| class='wikitable' | {| class='wikitable' | ||
Line 223: | Line 236: | ||
|} | |} | ||
==== | ==== Command 5 ==== | ||
Kill current | Kill the current [[Secure Modules|Secure Module]]. | ||
==== | ==== Command 6 ==== | ||
Force stop? Called from [[SceSblSmsched|sceSblSmSchedDeleteAll]]. | Force stop? Called from [[SceSblSmsched|sceSblSmSchedDeleteAll]]. | ||
==== | ==== Command 7 ==== | ||
Unused. | Unused. | ||
==== | ==== Command 8 ==== | ||
Unused. | Unused. | ||
==== | ==== Command 9 ==== | ||
Set a 0x80 sized shared buffer. | Set a 0x80 sized shared buffer. | ||
Line 260: | Line 273: | ||
|} | |} | ||
==== | ==== Command 10 ==== | ||
Set the encrypted signed revoke list. | Set the encrypted signed revoke list. | ||
Line 279: | Line 292: | ||
|} | |} | ||
==== | ==== Command 11 ==== | ||
==== | ==== Command 12 ==== | ||
==== | ==== Command 13 ==== | ||
==== | ==== Command 14 ==== | ||
==== | ==== Command 15 ==== | ||
==== | ==== Command 16 ==== | ||
=== Interrupts === | === Interrupts === | ||
There are 4 interrupts that | There are 4 interrupts that Cmep sends. There are only two interrupt handles, however. | ||
* <code>cry2arm0</code>: handles interrupt 200. This is notifications about current sm status changes (loaded, unloaded, suspended, etc) | * <code>cry2arm0</code>: handles interrupt 200. This is notifications about current sm status changes (loaded, unloaded, suspended, etc) | ||
* <code>cry2arm123</code>: handles interrupts 201, 202, 203. This interrupt is sent once an sm command has finished processing (see below). | * <code>cry2arm123</code>: handles interrupts 201, 202, 203. This interrupt is sent once an sm command has finished processing (see below). | ||
=== Executing | === Executing Secure Module functions === | ||
You can find an open source ARM | You can find an open source ARM TrustZone<->Cmep protocol implementation at https://github.com/xyzz/f00d. It allows calling [[Secure Modules|Secure Modules]] commands with a maximum of control over the sent data, received data and timing. | ||
When a [[SM]] is loaded, you can execute a [[ | When a [[SM]] is loaded, you can execute a [[Secure Module Functions|functions it provides]] by writing into registers 0xE0000014, 0xE0000018, 0xE000001C paddr to the [[Secure Modules Functions#Request_Buffer|request buffer]] OR'd with 1. | ||
Once result is available, ARM will get an interrupt 201-203. Read status code from 0xE0000004 (or 0xE0000008, 0xE000000C) and confirm you received it by writing it back to the same register. | Once result is available, ARM will get an interrupt 201-203. Read status code from 0xE0000004 (or 0xE0000008, 0xE000000C) and confirm you received it by writing it back to the same register. | ||
Line 309: | Line 322: | ||
* 1: command executed successfully | * 1: command executed successfully | ||
* 3: invalid | * 3: invalid function ID | ||
* 5: invalid | * 5: invalid function buffer physical address (e.g. trying to pass secure memory) | ||
* 9: SCE_SBL_ERROR_COMMON_EIO | * 9: SCE_SBL_ERROR_COMMON_EIO | ||
== Memory == | == Memory == | ||
Cmep has its own private 128kB memory from <code>0x00800000</code> to <code>0x00820000</code>. Secure Modules are typically loaded to <code>0x0080B000</code>. secure_kernel is loaded to <code>0x00800000</code>. | |||
== | == Secure Modules Task states == | ||
ARM [[TrustZone]] implements a scheduler for [[ | ARM [[TrustZone]] implements a scheduler for [[Secure Modules|Secure Modules]] tasks. Normally, only one task can run on Cmep at a time. The external [[Secure Modules|Secure Module]] scheduler running on ARM allows to have multiple tasks at once. The following provides an explanation of various states the task can be in. | ||
{| class='wikitable' | {| class='wikitable' | ||
Line 362: | Line 375: | ||
| ? | | ? | ||
|} | |} | ||
== Related pages == | |||
* [[Cmep basics]] | |||
* [[Cmep registers]] | |||
* [[F00D Key Ring Base]] | |||
* [[Secure Block]] | |||
* [[First Loader]] | |||
* [[Second Loader]] | |||
* [[Secure Kernel]] | |||
* [[Secure Modules]] | |||
* [[Secure Modules Functions]] | |||
* [[Ernie Secure]] |
Revision as of 01:57, 13 February 2023
Cmep is a processor in the PS Vita that performs most of the cryptography tasks including storing and handing of the most secure keys. Cmep was named "F00D" by Team Molecule after the e_machine
field of the ELF headers, but its official name is CMeP (?Control? MeP). Cmep is a Toshiba MeP-c5 core.
More information can be found in Toshiba documentations. For example: https://toshiba.semicon-storage.com/info/docget.jsp?did=14997&prodName=TMPV7504XBG.
Devices
See Physical_Memory#Cmep registers and Cmep registers for physical memory mapping.
Reset
Although the MeP architecture documentations specify that with EVM=0 the reset/NMI vector base is at 0x00000000, it is observed that the vector base is actually at 0x00040000. However, EVA/IVA still works as expected when EVM=1. Both Secure Kernel and Second Loader set EVM=0 at the start. This is likely a modified hardware behavior and the vector base remapping might be done when the First Loader is unmapped.
Communication
Communication seems to go through some sort of FIFO register.
Write
To write, put the double word into physical address 0xE0000010
. Next read 0xE0000010
until it returns 0, which indicates the data was read by Cmep.
Read
To read, get a double word from physical address 0xE0000000
. If it returns 0, no data is available. Otherwise, acknowledge that the data has been read by ARM TrustZonr by putting the same data into 0xE0000000
.
Extra ports
In addition to the 0xE0000000
and 0xE0000010
, the communication between Cmep and ARM uses some other ports.
Port | Read | Write | Used by |
---|---|---|---|
0xE0000004 | YES | ? | SMC 0x12d, 0x136, 0x137, 0x13B Interrupt 0xC8 |
0xE0000008 | YES | ? | SMC 0x12d, 0x136, 0x137, 0x13B Interrupt 0xC8 |
0xE000000C | YES | ? | SMC 0x12d, 0x136, 0x137, 0x13B Interrupt 0xC8 |
0xE0000014 | YES | YES | Used to send commands to Secure Module, see Executing Secure Module functions |
0xE0000018 | YES | YES | Used to send commands to Secure Module, see Executing Secure Module functions |
0xE000001C | YES | YES | Used to send commands to Secure Module, see Executing Secure Module functions |
0xE0000054 | ? | YES | SMC 0x12d, 0x135, 0x13B, Interrupt 0xC8 |
0xE0000058 | ? | YES | SMC 0x12d, 0x135, 0x13B, Interrupt 0xC8 |
0xE000005C | ? | YES | SMC 0x12d, 0x135, 0x13B, Interrupt 0xC8 |
0xE0010000 | YES | YES | Used by Cmep Command 0 to prepare Cmep to receive an address that contains the secure_kernel.enp. |
0xE0010004 | YES | ? | Used by Cmep Command 0 to check if the value written in 0xE0010000 is okay (it should return a value <= 0).
|
Protocol
A 32-bit command buffer is defined below. The command is sent to Cmep with the method listed above.
Bit End | Bit Start | Name | Description |
---|---|---|---|
31 | 16 | Size | Size of the command buffer |
18 | 13 | - | Always 0 |
12 | 8 | ID | Command ID |
7 | 1 | - | Always 0 |
0 | 0 | Valid | Set to 1 |
Command ID
There are a total of 17 commands. Commands pass data through the 0x100 shared buffer that is setup in command 0.
Command 0
This command is used to setup a shared buffer with Cmep. Firstly, Cmep will write in 0xE0000000
either 0x200 or 0x600 (and if an error happened, 0x400?). If the value 0x600 is written, it will setup a buffer that contains the secure_kernel.enp. It will write 1 to 0xE0010000
and after that 0x0 to 0xE0010000
, next, it will wait 0xE0010000
return 0 and 0xE0010004
return a value <= 0x0. If everything goes alright, it will clear the low 2 bits of the secure_kernel.enp address (normally at 0x1F850000) and OR it with 0x1 and then write it to 0xE0000010
. After it, the process is the same that the 0x200. If the value 0x200 is written, it will set the 0x100-sized shared buffer. The physical address of the buffer is written to 0xE0000010
and then command 0x0 is written.
Command 1
This command is called by a subroutine of SceSblSmsched#sceSblSmSchedStopForTZS or SceSblSmsched module_start (if an error happened while SceSblSmsched was initializing). This command seems to be used to ask Cmep to remove all allocated resources (like shared memory address, loaded Secure Module, etc), and probably power off or reset it.
Command 2
Load a Secure Module.
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | num_paddrs |
0x4 | 0x4 | paddr_list for Secure Module ELF |
0x8 | 0x4 | buf_0x40: some 0x40 buffer |
0xC | 0x4 | ctx_0x4 |
0x10 | 0x4 | ctx_0x8 |
0x14 | 0x4 | ctx_0xC |
0x1C | 0x4 | field_60: system version (2) |
0x20 | 0x4 | partition ID, ?Media Type? |
Command 3
Load the previously suspended Secure Module.
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | num_paddrs |
0x4 | 0x4 | paddr_list for suspend buffer |
0x8 | 0x4 | buf_0x40: some 0x40 buffer |
0xC | 0x4 | delayed_cmd |
Command 4
Suspend the current Secure Module.
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | num_paddrs |
0x4 | 0x4 | paddr_list for suspend buffer |
0x8 | 0x4 | buf_0x40: some 0x40 buffer |
0xC | 0x4 | delayed_cmd |
Command 5
Kill the current Secure Module.
Command 6
Force stop? Called from sceSblSmSchedDeleteAll.
Command 7
Unused.
Command 8
Unused.
Command 9
Set a 0x80 sized shared buffer.
This seems like a SceKernelPARange.
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | PA |
0x4 | 0x4 | length |
Command 10
Set the encrypted signed revoke list.
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | num_paddrs |
0x4 | 0x4 | paddr_list for signed revoke list |
Command 11
Command 12
Command 13
Command 14
Command 15
Command 16
Interrupts
There are 4 interrupts that Cmep sends. There are only two interrupt handles, however.
cry2arm0
: handles interrupt 200. This is notifications about current sm status changes (loaded, unloaded, suspended, etc)cry2arm123
: handles interrupts 201, 202, 203. This interrupt is sent once an sm command has finished processing (see below).
Executing Secure Module functions
You can find an open source ARM TrustZone<->Cmep protocol implementation at https://github.com/xyzz/f00d. It allows calling Secure Modules commands with a maximum of control over the sent data, received data and timing.
When a SM is loaded, you can execute a functions it provides by writing into registers 0xE0000014, 0xE0000018, 0xE000001C paddr to the request buffer OR'd with 1.
Once result is available, ARM will get an interrupt 201-203. Read status code from 0xE0000004 (or 0xE0000008, 0xE000000C) and confirm you received it by writing it back to the same register.
Possible results:
- 1: command executed successfully
- 3: invalid function ID
- 5: invalid function buffer physical address (e.g. trying to pass secure memory)
- 9: SCE_SBL_ERROR_COMMON_EIO
Memory
Cmep has its own private 128kB memory from 0x00800000
to 0x00820000
. Secure Modules are typically loaded to 0x0080B000
. secure_kernel is loaded to 0x00800000
.
Secure Modules Task states
ARM TrustZone implements a scheduler for Secure Modules tasks. Normally, only one task can run on Cmep at a time. The external Secure Module scheduler running on ARM allows to have multiple tasks at once. The following provides an explanation of various states the task can be in.
ID | Description |
---|---|
1 | Created / Suspended (Unloaded) |
2 | Running |
3 | Errored (Unloaded) |
4 | ? (Unloaded) |
5 | ? (Unloaded) |
6 | Start/resume requested |
7 | Suspending |
8 | ? |
9 | ? |
10 | ? |
11 | Suspend requested |
12 | ? |