mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-08-03 12:16:24 -04:00
Document state machine
Golden path not updated
This commit is contained in:
parent
ab12c201c4
commit
76b25bc121
1 changed files with 96 additions and 61 deletions
|
@ -119,67 +119,90 @@ values of the Block RAMs used to construct the `FW_ROM`. The `FW_ROM`
|
||||||
start address is located at `0x0000_0000` in the CPU memory map, which
|
start address is located at `0x0000_0000` in the CPU memory map, which
|
||||||
is also the CPU reset vector.
|
is also the CPU reset vector.
|
||||||
|
|
||||||
|
### Reset intentions
|
||||||
|
|
||||||
|
We have a number of reset options we call `startfrom`:
|
||||||
|
|
||||||
|
1. Start from flash slot 1 (default): `FLASH1`
|
||||||
|
2. Start from flash slot 2: `FLASH2`.
|
||||||
|
3. Load and start an app from flash slot 1 with a specific app hash:
|
||||||
|
`FLASH1_VER`
|
||||||
|
4. Load and start an app from flash slot 2 with a specific app hash:
|
||||||
|
`FLASH2_VER`.
|
||||||
|
5. Load and start a new app from client: `CLIENT`.
|
||||||
|
6. load and start an app from client with a specific app hash:
|
||||||
|
`CLIENT_VER`.
|
||||||
|
|
||||||
### Firmware state machine
|
### Firmware state machine
|
||||||
|
|
||||||
This is the state diagram of the firmware. There are only six states.
|
This is the state diagram of the firmware. Change of state occur when
|
||||||
|
we receive specific I/O or a fatal error occurs.
|
||||||
Change of state occur when we receive specific I/O or a fatal error
|
|
||||||
occurs.
|
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
S0: resetinfo
|
S0: initial
|
||||||
S4: loadflash
|
|
||||||
S1: waitcommand
|
S1: waitcommand
|
||||||
S2: loading
|
S2: loading
|
||||||
S3: running
|
S3: flash_loading
|
||||||
|
S4: auth_app
|
||||||
|
S5: starting
|
||||||
|
S6: compute_cdi
|
||||||
SE: failed
|
SE: failed
|
||||||
|
|
||||||
[*] --> S0
|
[*] --> S0
|
||||||
|
|
||||||
S0 --> S4: load 1 (def) or load 2
|
|
||||||
S0 --> S1
|
S0 --> S1
|
||||||
|
S0 --> S4: Default
|
||||||
|
|
||||||
S1 --> S1: Commands
|
S1 --> S1: Commands
|
||||||
S1 --> S2: LOAD_APP
|
S1 --> S2: LOAD_APP
|
||||||
S1 --> SE: Error
|
S1 --> SE: Error
|
||||||
|
|
||||||
S2 --> S2: LOAD_APP_DATA
|
S2 --> S2: LOAD_APP_DATA
|
||||||
S2 --> S3: Last block received
|
S2 --> S6: Last block received
|
||||||
S2 --> SE: Error
|
S2 --> SE: Error
|
||||||
|
|
||||||
S4 --> S3
|
S6 --> S3
|
||||||
|
|
||||||
|
S3 --> S5
|
||||||
|
|
||||||
|
S4 --> S5
|
||||||
S4 --> SE: Error
|
S4 --> SE: Error
|
||||||
|
|
||||||
SE --> [*]
|
SE --> [*]
|
||||||
S3 --> [*]
|
S5 --> [*]
|
||||||
```
|
```
|
||||||
|
|
||||||
States:
|
States:
|
||||||
|
|
||||||
- `resetinfo` - We start by checking resetinfo data in `FW_RAM`
|
- `initial`: We start by checking resetinfo data in `FW_RAM` for
|
||||||
- `waitcommand` - Waiting for initial commands from client. Allows the
|
`startfrom`.
|
||||||
|
- `waitcommand`: Waiting for initial commands from client. Allows the
|
||||||
commands `NAME_VERSION`, `GET_UDI`, `LOAD_APP`.
|
commands `NAME_VERSION`, `GET_UDI`, `LOAD_APP`.
|
||||||
- `loadflash` - Loading an app from flash.
|
- `loading`: Expecting application data from client. Allows only the
|
||||||
- `loading` - Expect application data. Allows only the command
|
command `LOAD_APP_DATA`.
|
||||||
`LOAD_APP_DATA`.
|
- `flash_loading`: Loading and authentication app from flash. Computes CDI,
|
||||||
- `running` - Computes CDI and starts the application. Allows no commands.
|
creates or checks the authentication of the flash app. Allows no commands.
|
||||||
|
- `starting`: Starts the application. Does not return to firmware.
|
||||||
|
Allows no commands.
|
||||||
- `failed` - Halts CPU. Allows no commands.
|
- `failed` - Halts CPU. Allows no commands.
|
||||||
|
|
||||||
Allowed data in state `resetinfo`:
|
Allowed data in state `resetinfo`:
|
||||||
|
|
||||||
| *startfrom* | *next state* |
|
| *startfrom* | *next state* |
|
||||||
|----------------------|---------------|
|
|--------------|-----------------|
|
||||||
| `default` | `loadflash` |
|
| `FLASH1` | `flash_loading` |
|
||||||
| `Start flash slot 1` | `loadflash` |
|
| `FLASH2` | `flash_loading` |
|
||||||
| `Start flash slot 2` | `loadflash` |
|
| `FLASH1_VER` | `flash_loading` |
|
||||||
| `Start from client` | `waitcommand` |
|
| `FLASH2_VER` | `flash_loading` |
|
||||||
|
| `CLIENT` | `waitcommand` |
|
||||||
|
| `CLIENT_VER` | `waitcommand` |
|
||||||
|
|
||||||
I/O in state `loadflash`:
|
I/O in state `flash_loading`:
|
||||||
|
|
||||||
| *I/O* | *next state* |
|
| *I/O* | *next state* |
|
||||||
|--------------------|--------------|
|
|--------------------|--------------|
|
||||||
| Last app data read | `run` |
|
| Last app data read | `starting` |
|
||||||
|
|
||||||
Commands in state `waitcommand`:
|
Commands in state `waitcommand`:
|
||||||
|
|
||||||
|
@ -192,40 +215,52 @@ Commands in state `waitcommand`:
|
||||||
Commands in state `loading`:
|
Commands in state `loading`:
|
||||||
|
|
||||||
| *command* | *next state* |
|
| *command* | *next state* |
|
||||||
|------------------------|----------------------------------|
|
|------------------------|---------------------------------------|
|
||||||
| `FW_CMD_LOAD_APP_DATA` | unchanged or `run` on last chunk |
|
| `FW_CMD_LOAD_APP_DATA` | unchanged or `starting` on last chunk |
|
||||||
|
|
||||||
|
No other states allows commands.
|
||||||
|
|
||||||
See [Firmware protocol in the Dev
|
See [Firmware protocol in the Dev
|
||||||
Handbook](http://dev.tillitis.se/protocol/#firmware-protocol) for the
|
Handbook](http://dev.tillitis.se/protocol/#firmware-protocol) for the
|
||||||
definition of the specific commands and their responses.
|
definition of the specific commands and their responses.
|
||||||
|
|
||||||
Exection starts in state `resetinfo` where the firmware checks in
|
Plain text explanation of the states:
|
||||||
`FW_RAM` for what to do next.
|
|
||||||
|
|
||||||
State changes to `loadflash` if the `FW_RAM` data indicates
|
- `initial`: Execution starts here. The firmware checks in the
|
||||||
that it should start one of the two flash apps.
|
`FW_RAM` for `startfrom` for what to do next.
|
||||||
|
|
||||||
State changes to `waitcommand` if the `FW_RAM` data indicates that it
|
For all `startfrom` values `FLASH_*` the next state is `startflash`.
|
||||||
instead should wait for commands from a client.
|
Otherwise it goes to `waitcommand`, indicating that it should wait
|
||||||
|
for further commands from the client.
|
||||||
|
|
||||||
In `loadflash` state changes to `running` if the app has been
|
- `flash_loading` loads and measure an app from flash, the Compound
|
||||||
successfully loaded into RAM or to `failed` otherwise.
|
Device Identifier (CDI) is computed, then the app is authenticated
|
||||||
|
against a stored digest to see that no one has changed the app by
|
||||||
|
manipulating the flash. The compuation is done by:
|
||||||
|
|
||||||
State changes from `waitcommand` to `loading` when receiving
|
digest = blake2s(cdi, nonce from flash)
|
||||||
`LOAD_APP`, which also sets the size of the number of data blocks to
|
|
||||||
expect. After that we expect several `LOAD_APP_DATA` commands until
|
|
||||||
the last block is received, when state is changed to `running`.
|
|
||||||
|
|
||||||
In `running`, the loaded device app is measured, the Compound Device
|
and then compared against the stored digest in the app's flash slot.
|
||||||
Identifier (CDI) is computed, we do some cleanup of firmware data
|
|
||||||
structures, enable the system calls, and finally start the app, which
|
|
||||||
ends the firmware state machine. Hardware guarantees that we leave
|
|
||||||
firmware mode automatically when the program counter leaves ROM.
|
|
||||||
|
|
||||||
The device app is now running in application mode. We can, however,
|
- `waitcommand` waits for command from the client. State changes to
|
||||||
return to firmware mode (excepting access to the UDS) by doing system
|
`loading` when receiving `LOAD_APP`, which also sets the size of the
|
||||||
calls. Note that ROM is still readable, but is now hardware protected
|
number of data blocks to expect. After that we expect several
|
||||||
from execution, except through the system call mechanism.
|
`LOAD_APP_DATA` commands until the last block is received, when
|
||||||
|
state is changed to `running`.
|
||||||
|
|
||||||
|
- `compute_cdi`: The the Compound Device Identifier (CDI) is computed
|
||||||
|
and we go to `starting`.
|
||||||
|
|
||||||
|
- `starting`: Clean up firmware data structures, enable the system
|
||||||
|
calls, and start the app, which ends the firmware state machine.
|
||||||
|
Hardware guarantees that we leave firmware mode automatically when
|
||||||
|
the program counter leaves ROM.
|
||||||
|
|
||||||
|
After `starting` the device app is now running in application mode. We
|
||||||
|
can, however, return to firmware mode (excepting access to the UDS) by
|
||||||
|
doing system calls. Note that ROM is still readable, but is now
|
||||||
|
hardware protected from execution, except through the system call
|
||||||
|
mechanism.
|
||||||
|
|
||||||
### Golden path
|
### Golden path
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue