From fea9df790df8bb8edda85caae146f152a442796b Mon Sep 17 00:00:00 2001 From: Michael Cardell Widerkrantz Date: Wed, 30 Apr 2025 18:46:36 +0200 Subject: [PATCH] fw/docs: Correct documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mikael Ă…gren --- hw/application_fpga/fw/README.md | 96 ++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/hw/application_fpga/fw/README.md b/hw/application_fpga/fw/README.md index dc1476e..1e58dc9 100644 --- a/hw/application_fpga/fw/README.md +++ b/hw/application_fpga/fw/README.md @@ -163,6 +163,7 @@ stateDiagram-v2 S0 --> S1 S0 --> S4: Default S0 --> S3 + S0 --> SE: Unknown reset type S1 --> S1: Other commands S1 --> S2: LOAD_APP @@ -191,8 +192,8 @@ States: - *LOADING*: Expecting application data from client. Allows only the command `LOAD_APP_DATA` to continue loading the device app. - *LOAD_FLASH*: Loading an app from flash. Allows no commands. -- *LOAD_FLASH_MGMT*: Loading and verifyiing a device app from flash. - Allows no commands. +- *LOAD_FLASH_MGMT*: Loading an app from flash and registering it as a + prospective managment app. Allows no commands. - *START*: Computes CDI. Possibly verifies app. Starts the application. Does not return to firmware. Allows no commands. - *FAIL* - Halts CPU. Allows no commands. @@ -207,6 +208,7 @@ Allowed data in state *INITIAL*: | `FLASH1_VER` | *LOAD_FLASH* | | `CLIENT` | *WAITCOMMAND* | | `CLIENT_VER` | *WAITCOMMAND* | +| unknown | *FAIL* | I/O in state *LOAD_FLASH*: @@ -220,15 +222,16 @@ I/O in state *LOAD_FLASH_MGMT*: |--------------------|--------------| | Last app data read | *START* | -Commands in state `waitcommand`: +Commands in state *WAITCOMMAND*: -| *command* | *next state* | -|-----------------------|--------------| -| `FW_CMD_NAME_VERSION` | unchanged | -| `FW_CMD_GET_UDI` | unchanged | -| `FW_CMD_LOAD_APP` | *LOADING* | +| *command* | *next state* | +|-----------------------|--------------------------------------------| +| `FW_CMD_NAME_VERSION` | unchanged | +| `FW_CMD_GET_UDI` | unchanged | +| `FW_CMD_LOAD_APP` | *LOADING* or unchanged on invalid app size | +| | | -Commands in state `loading`: +Commands in state *LOADING*: | *command* | *next state* | |------------------------|------------------------------------| @@ -245,17 +248,23 @@ Plain text explanation of the states: - *INITIAL*: Start here. Check the `FW_RAM` for the `resetinfo` type for what to do next. - For all types which begins with `FLASH_*`, set next state to - *LOAD_FLASH*, otherwise set next state to *WAITCOMMAND*. + For type `FLASH0` transition to *LOAD_FLASH_MGMT* because the app in + slot 0 is considered a special management app. For all other types + beginning with `FLASH*` transition to *LOAD_FLASH* to load an + ordinary app from flash. + + For type `CLIENT*` transitionto *WAITCOMMAND* to expect a device app + from the client. + + If type is unknown, error out. - *LOAD_FLASH*: Load device app from flash into RAM, app slot taken from context. Compute a BLAKE2s digest over the entire app. Transition to *START*. - *LOAD_FLASH_MGMT*: Load device app from flash into RAM, app slot - alway 0. Compute a BLAKE2s digest over the entire app. Register the - app as a prospective management app if it later goes through - verification. Transition to *START*. + always 0. Compute a BLAKE2s digest over the entire app. Register the + app as a prospective management app. Transition to *START*. - *WAITCOMMAND*: Wait for commands from the client. Transition to *LOADING* on `LOAD_APP` command, which also sets the size of the @@ -266,7 +275,8 @@ Plain text explanation of the states: - *START*: Compute the Compound Device Identifier (CDI). If we have a registered verification digest, verify that the app we are about to - start is indeed the correct app. + start is indeed the correct app. This also means that a prospective + management app is now verified. Clean up firmware data structures, enable the system calls, and start the app, which ends the firmware state machine. Hardware @@ -289,32 +299,37 @@ state. ### Golden path from start to default app -Firmware loads the device application at the start of RAM +Firmware will load the device application at the start of RAM (`0x4000_0000`) from either flash or from the client through the UART. -Firmware uses a part of the FW\_RAM for its own stack. +Firmware is using a part of the FW\_RAM for its own stack. When reset is released, the CPU starts executing the firmware. It begins in `start.S` by clearing all CPU registers, clears all FW\_RAM, -sets up a stack for itself there, and then jumps to `main()`. Also -included in the assembly part of firmware is an interrupt handler for -the system calls, but the handler is not yet enabled. +except the part reserved for the resetinfo area, sets up a stack for +itself there, and then jumps to `main()`. Also included in the +assembly part of firmware is an interrupt handler for the system +calls, but the handler is not yet enabled. Beginning at `main()` it fills the entire RAM with pseudo random data and setting up the RAM address and data hardware scrambling with values from the True Random Number Generator (TRNG). -1. Check the special resetinfo area in FW\_RAM for reset type. Type +Firmware then proceeds to: + +1. Read the partition table from flash and store in FW\_RAM. + +2. Check the special resetinfo area in FW\_RAM for reset type. Type zero means default behaviour, load from flash app slot 0, expecting the app there to have a specific hardcoded BLAKE2s digest. -2. Load app data from flash slot 0 into RAM. +3. Load app data from flash slot 0 into RAM. -3. Compute a BLAKE2s digest of the loaded app. +4. Compute a BLAKE2s digest of the loaded app. -4. Compare the computed digest against the allowed app digest +5. Compare the computed digest against the allowed app digest hardcoded in the firmware. If it's not equal, halt CPU. -7. [Start the device app](#start-the-device-app). +6. [Start the device app](#start-the-device-app). ### Start the device app @@ -372,9 +387,9 @@ Such a verified boot loader app: - Can be specifically trusted by firmware to be able to do filesystem management to be able to update an app slot on flash. Add the app's - digest to `allowed_app_digest` in `mgmt_app.c` to allow it to allow - it to use `PRELOAD_DELETE`, `PRELOAD_STORE`, and - `PRELOAD_STORE_FIN`. + digest to `allowed_app_digest` in `mgmt_app.c` to allow it to use + `PRELOAD_DELETE`, `PRELOAD_STORE`, `PRELOAD_STORE_FIN`, and + `PRELOAD_GET_DIGSIG`. It works like this: @@ -414,7 +429,7 @@ The loader shares the secret with the next app by putting it in the part of `resetinfo` that is reserved for inter-app communication. The next app can now use the secret as a seed for it's own key -material. Depending on the app's behaviour and the numer of keys it +material. Depending on the app's behaviour and the number of keys it needs it can derive more keys, for instance by having nonces stored on its flash area and doing: @@ -545,7 +560,7 @@ You can pass data to the firmware about the reset type `type` and a digest that the next app must have. You can also leave some data to the next app in the chain in `next_app_data`. -The types of the reset are defined in `reset.h`: +The types of reset are defined in `reset.h`: | *Name* | *Comment* | |--------------------|------------------------------------------------| @@ -579,12 +594,15 @@ success. uint32_t offset = 0; uint8_t buf[17]; -TK1_SYSCALL_WRITE_DATA, offset, (uint32_t)buf, sizeof(buf)) +syscall(TK1_SYSCALL_WRITE_DATA, offset, (uint32_t)buf, sizeof(buf)) ``` Write data in `buf` to the app's flash area at byte `offset` within the area. Returns 0 on success. +At most 4096 bytes can be written at once and `offset` must be a +multiple of 4096 bytes. + #### `READ_DATA` ``` @@ -631,9 +649,14 @@ syscall(TK1_SYSCALL_PRELOAD_STORE, offset, (uint32_t)appbinary, ``` Store an app, or possible just a block of an app, from the `appbinary` -buffer in flash slot 1 at byte `offset` If you can't find your entire -app in the buffer, call `PRELOAD_STORE` many times as you receive the -binary from the client. Returns 0 on success. +buffer in flash slot 1 at byte `offset`. + +If you can't fit your entire app in the buffer, call `PRELOAD_STORE` +many times as you receive the binary from the client. Returns 0 on +success. + +At most 4096 bytes can be written at once and `offset` must be a +multiple of 4096 bytes. Only available for the verified management app. @@ -652,7 +675,8 @@ Finalize storing of an app where the complete binary size is `app_size` in flash slot 1. Returns 0 on success. Only available for the verified management app. -Compute the `app_digest` with BLAKE2s over the entire binary. +Compute a BLAKE2s hash digest over the entire binary. Pass the result +in `app_digest`. Sign `app_digest` with your Ed25519 private key and pass the resulting signature in `app_signature`. @@ -737,7 +761,7 @@ initiated before starting for the first time. You need a [TKey Programmer Board](https://shop.tillitis.se/products/tkey-dev-kit) for this part. -1. Choose your pre-loaded app. You /must/ have a pre-loaded app, for +1. Choose your pre-loaded app. You *must* have a pre-loaded app, for example `testloadapp`. Build it with the OCI image we use. The binary needs to produce the BLAKE2s digest in `allowed_app_digest` `tk1/mgmt_app.c`.