Atmosic Secure Journal Tool
Overview
The secure journal is a write-once, append-only data storage area that provides OTP-like behavior. Implementation varies across platforms:
ATM34: The secure journal is a dedicated block of RRAM that replaces traditional OTP memory. This region is located near the end of the RRAM storage array at 0x8F800 – 0x8FEEF (1776 bytes). It is contained entirely in RRAM, and a secure ratchet ensures that no data already committed is deleted.
ATM5: The secure journal is split between OTP and external (stacked) Flash memory. The portion in OTP can never be modified once written. The portion in Flash can be modified until software applies a sticky write lock to it. There is no ratchet on ATM5.
The remainder of this document describes ATM34 behavior unless stated otherwise. Differences for ATM5 are described in the “ATM5 Secure Journal” section and in notes throughout.
The secure journal region contains variable-length TLV (Type, Length, Value) data tuples.
The secure journal may contain:
Bluetooth Device BD Address (can be configured by customers)
Per-chip or per-board calibration data (can be configured by customers, or through Tools, such as MPTools)
ATE test information at the chip test/assembly (cannot be configured by customers)
The secure journal is intended to be programmed during manufacturing. The application firmware can only read tag data stored in the journal; it cannot update or append data.
The secure journal’s protection properties are activated during chip test/assembly via an OTP bit setting. This setting is configured for all production chips. (ATM34)
Theory of Operation
ATM34 (Ratchet)
The secure journal data updates are controlled by a secure counter (address ratchet). The counter determines the next writable location at an offset from the start of the journal. An offset greater than the counter value is writable while any offset below or equal to the counter is locked from updates. The counter can only increment monotonically and cannot be rolled back. This provides the immutability of OTP as well as the flexibility to append new data items or override past items using a find the latest TLV search.
Using the following as an example, the secure journal start address is at 0x8F800, and the ratchet is currently set to 4. This data between the start of the secure journal and the ratchet value (non-inclusive) is locked, i.e., 0x8F800-0x8F803.
Figure 1 - Secure Journal Example
To append new data, an additional byte can be written at the ratchet position, and the ratchet is incremented by 1 (now becomes 5). This locks down 1 additional byte of the secure journal.
Figure 2 - Add New Data to Secure Journal
Memory between the start of the secure journal and the ratchet is now write-protected (0x8F800-0x8F804). RRAM memory after the new ratchet value can still be freely programmed. Since the ratchet counter value cannot be rolled back, all data before the ratchet cannot be updated.
A new tag or an override to an existing tag can be added to the journal without committing it (i.e., incrementing the ratchet). The tag is non-volatile; however, it is not permanent due to the position of the ratchet. This is useful for testing purposes without having to permanently add and eventually exhaust the available space in the journal. This is only recommended for development testing and should not be used in the final end product. Manufacturing processes should install and increment the ratchet to protect data. See the “SDK Tooling” section for additional information.
ATM5 Secure Journal
ATM5 does not have a secure ratchet. Instead, the secure journal is split into two parts with different mutability:
OTP portion: Written once and can never be modified or erased. This is analogous to the ratcheted (locked) region of the ATM34 journal.
Flash portion: Can be written and erased, for example via SWD or by secure-domain software (MCUBOOT or the SPE). Software applies a sticky write lock to the Flash portion before the non-secure application starts. Sticky locks are applied by secure software before the application boots. This is analogous to the non-ratcheted region of the ATM34 journal, except that it is not protected from modification until that lock is applied.
Unlike ATM34, the boundary between the two parts cannot move. There is no equivalent of advancing the ratchet to commit Flash data. Data can only be made permanent by writing it to OTP (see --storage otp below).
Both parts hold the same TLV format and are read with the same find the latest TLV search described in “Tag Types”.
Warning
Before the sticky write lock is applied, errant software or SWD access can modify or erase the Flash portion. After production, put all data that must never change in OTP.
The --storage option of the west secjrnl subcommands selects which part is accessed:
--storage nvds(default): Accesses the non-volatile data storage journal. On ATM34 this is the RRAM journal. On ATM5 this is the Flash portion.--storage otp: Accesses the OTP portion (ATM5 only). Writes are permanent.
Behavior |
ATM34 |
ATM5 |
|---|---|---|
Journal storage |
RRAM only |
OTP + Flash |
Immutable region |
Below the ratchet |
OTP portion |
Mutable region |
Above the ratchet |
Flash portion (until sticky write lock) |
Commit data permanently |
|
|
Ratchet |
Advances monotonically |
Cannot be advanced |
Tag Types
The journal contains two classes of tags: Overridable and Immutable. The main difference is a tag header flag that denotes a tag as being immutable (i.e., locked).
SDK Tooling
The Secure Journal is intended to be read-only during application execution. Zephyr standard west tooling has been enhanced to include support for manipulating Secure Journal. west secjrnl... extensions can be used to dump contents, get tag data, erase, append a new tag, or create a local secure journal copy.
Python Requirements
The following setup procedures are not required when using atmoautil (see OpenAir Utility).
The Atmosic Secure Journal Tool requires Python packages of Zephyr.
To install with the Zephyr requirements file:
pip install -r zephyr/scripts/requirements.txt
If needed, create a symbolic link or use a Python virtual environment:
For Linux:
sudo ln -s $(which python3) /usr/bin/python
For Windows:
mklink "C:\Path\To\Python\python3.exe" "C:\Path\To\Python\python.exe"
Note
On Windows:
you can use
where python3to locate the path of the Python executable.Ensure that the symlink or Python installation directory is included in the system PATH environment variable, or place the symlink in a directory that is already in the PATH.
Type in west secjrnl --help to know the list of supported options, as shown below:
user@domain:~/zephyrproject-05-22-2025$ west secjrnl --help
usage: west secjrnl [-h]
{dump,get,erase,get_ratchet,append,ratchet_jrnl,create,burn}
...
Interface with secure journal on supported chips. Allows users to manage the
secure journal through a variety of sub commands.
positional arguments:
{dump,get,erase,get_ratchet,append,ratchet_jrnl,create,burn}
sub-command to run
dump Dump all TLVs from the secure journal
get Get individual TLV from secure journal
erase Erase all non-ratcheted TLVs from the secure journal
get_ratchet Return secure ratchet index
append Appends a single TLV to the secure journal
ratchet_jrnl Increment secure ratchet index
create Build a local secure journal binary file
burn Burn a full secure journal to the chip
options:
-h, --help show this help message and exit
Required parameters:
Note
--jlink Specify if using a J-Link interface. If omitted, the FTDI interface is assumed.
--dl Specify if using a Download Board (DL) interface.
Note that all examples provided below assume a --jlink board. If using an FTDI or DL board instead, change the parameters as appropriate.
Creating a Secure Journal
Creating a new secure journal can be done with the create subcommand. Adding additional tags will extend the data in the created journal. The data formats supported are described below in the “Data Format Examples” section.
west secjrnl create ---board <board> --tag <TAG_1> --data <TAG_1_DATA> --tag <TAG_2> --data <TAG_2_DATA> -o <outfile>
This will create a new secure journal and store it in a local file ‘<outfile>’.
Dumping Secure Journal
To dump all the TLV tags located in the secure journal:
west secjrnl dump --device <DEVICE_ID> --jlink --board <BOARD>
west secjrnl dump --device <DEVICE_ID> --dl --board <BOARD>
Here is a sample:
west secjrnl dump --device 900038948 --jlink --board ATMEVK-3430e-YQN-5
Using ATM OpenOCD '/data/user/zephyrproject_05_08_2025/modules/hal/atmosic_lib/tools/openocd/bin/Linux/openocd'
['ATM34xx-5', 'ATM34xx-5/no_TZ']
@0007 ATE [V][L][!E] data: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8f e4 29 10 02 00 07 00 00 00 00 00]
@0026 CHIP_INFO [V][L][!E] data: [0d 00 06 06 02 19 00 00 01]
@0032 RIF_CAL [V][L][!E] data: [a1 1d 00 00 d8 05 00 00 9f 80 25 02 4f 80 12 01 13 00 00 00 c3 c9 16 00 20 08 00 00]
@0051 MDM_CAL [V][L][!E] data: [18 cd 0c 28 01 02 00 00 16 11 18 80 e0 a7 00 00 d1 6b 00 00]
@0068 tag:(c2) [V][L][!E] data: [fc 92 16 0b]
@006f tag:(c3) [V][L][!E] data: [b9 18 e5 03 db d6 1f 00 52 84 20 05 db e6 1f 00]
@0082 tag:(c4) [V][L][!E] data: [00 80 26 00 7d c5 0a 00 55 c1 0d 00 7e c0 10 00 43 c0 13 00 9d c8 0a 00 6b c2 0d 00 b8 c0 10 00 57 c0 13 00 4f fd 00 00 c3 fd 00 00 01 fe 00 00 1f fe 00 00]
@00b9 tag:(01) [V][!L][!E] data: [02 10 84 6b 69 7c]
@00c2 tag:(de) [V][!L][!E] data: [64 61 74 61]
The dump subcommand can also take the --binary, --binfile or --hex flags to change the output format to something that is easier to store. See “Dump Output Formats” below.
Dump Output Formats
The dump subcommand supports the following output formats. If more than one option is given, --binary takes precedence over --binfile, which takes precedence over --hex. On ATM5, the default behavior is to only dump the secure jounral data in flash. Add --storage otp to dump the OTP portion instead.
Option |
Output goes to |
Description |
|---|---|---|
(none) |
Console |
Human-readable list of TLVs, one per line (the default, shown above). |
|
Console |
A single string of hex digits containing the journal contents, with no spaces. The string ends after the end of the journal data (including its tail padding), so it is shorter than the full journal region. |
|
Console |
The raw journal bytes exactly as read from the device, printed as a Python |
|
File |
Writes the raw journal bytes exactly as read from the device to |
Each line of the default output has the following layout:
@<offset> <tag name or tag:(id)> [<V>][<L>][<E>] data: [<bytes in hex>]
@<offset>: Hex offset of the TLV from the start of the journal.Tag name, or
tag:(id)if the tag has no known name.Status flags:
Vvalid,Llocked (cannot be overridden),Eerased. A!prefix means the flag is not set, for example[!L]is not locked.data: The tag value as space-separated hex bytes.
Examples:
west secjrnl dump --device <DEVICE_ID> --jlink --board <BOARD> --hex
west secjrnl dump --device <DEVICE_ID> --jlink --board <BOARD> --binfile secjrnl.bin
Use --binfile to save a journal that can later be written with west secjrnl burn --sec-jrnl secjrnl.bin.
Appending a Tag to the Secure Journal
The secure journal uses a find latest search algorithm to allow overrides. If the passed tag should NOT be overridden in the future, add the flag --locked to the append command. See the following section for more information regarding locking a tag.
To append a new tag to the secure journal:
west secjrnl append --device <DEVICE_ID> --jlink --board <BOARD> --tag <tag_id> --data <tag_data>
tag_idappropriate tag ID (Ex:0xde)tag_datathe data for the tag. This is passed as a string with ASCII-only characters (0-127). To pass raw byte values format it like so:\xde\xad\xbe\xef. As such,--data "data"will result in the same output as--data "\x64\x61\x74\x61".
Data Format Examples
The --data parameter supports ASCII text and escape sequences for binary data. The --json parameter supports formatted JSON data for tags which have their schema defined in sec_jrnl_tlv.py.
ASCII text:
--data "hello world"(characters 0-127 only)Binary bytes:
--data "\xde\xad\xbe\xef"(any byte value 0-255)Mixed data:
--data "text\x00\xfabinary"(ASCII text with binary bytes)Special characters:
--data "line1\nline2\ttab"(newlines, tabs, etc.)JSON data:
--json "{\"bd_addr\": [46, 0, 83, 107, 105, 124]}"(valid JSON)
Important
Use
\xabformat for hex bytes, not\0xab. Each byte is represented as\xfollowed by exactly two hex digits.ASCII characters (0-127) can be typed directly. Non-ASCII characters must use
\xescape sequences.Example: Use
\xe9instead of typingédirectly to avoid encoding issues.
Complete Example
Here’s a complete example showing how mixed ASCII text and binary data is processed:
west secjrnl append --device <DEVICE_ID> --jlink --board <BOARD> --tag 0x15 --data "text\x00\x01binary\n" --dry-run
This command will result in the following output:
@00b9 tag:(15) [V][!L][!E] data: [74 65 78 74 00 01 62 69 6e 61 72 79 0a]
Data breakdown:
- text → 74 65 78 74 (ASCII: ‘t’, ‘e’, ‘x’, ‘t’)
- \x00 → 00 (null byte)
- \x01 → 01 (binary byte value 1)
- binary → 62 69 6e 61 72 79 (ASCII: ‘b’, ‘i’, ‘n’, ‘a’, ‘r’, ‘y’)
- \n → 0a (newline character)
Example with byte values:
west secjrnl append --device <DEVICE_ID> --jlink --board <BOARD> --tag 0x16 --data "abcd\xfa\xff" --dry-run
Results in: [61 62 63 64 fa ff] (ASCII ‘abcd’ + bytes 250, 255)
Note that passing --dry-run to append operation only prints the secure journal, but does not write the data into secure journal.
Note
BD Address Configuration
When setting a BD address in the secure journal, the byte sequence must be reversed from the standard representation. The BD address uses tag ID 0x1.
Tag ID:
0x1(BD address)Standard BD Address Format:
AA:BB:CC:DD:EE:FFSecure Journal Format:
\xFF\xEE\xDD\xCC\xBB\xAA(reversed byte order)
Example: If your intended BD address is 12:34:56:78:9A:BC, you must provide it as:
west secjrnl append --device <DEVICE_ID> --jlink --board <BOARD> --tag 0x1 --data "\xBC\x9A\x78\x56\x34\x12"
This reversal is required because the secure journal stores the BD address in little-endian byte order, while the standard representation uses big-endian format.
Note
On ATM34, the append command does NOT increment the ratchet. The newly appended tag is still unprotected from erasing.
On ATM5, append writes to the journal selected by --storage. With the default --storage nvds the tag goes to the Flash portion and remains modifiable until the sticky write lock is applied. With --storage otp the tag is permanent.
Locking Down a Tag
The secure journal provides a secure method of storing data while still providing options to update the data if needed. However, there are key data entries that should never be updated across the life of the device (e.g. UUID).
This support is provided by software and can be enabled for a tag by passing the --locked to the command when appending a new tag.
It is important to understand, that once a tag is locked and made permanent (ratcheted on ATM34, or written to OTP on ATM5), the specific tag can never be updated in the future - Appending a new tag of the same value will be ignored.
Erasing Non-ratcheted Data From the Secure Journal
Appended tags are not ratcheted down. This allows for prototyping with the secure journal before needing to lock down the TLVs. The secure journal has limited erasing capabilities. Due to the nature of the security ratchet, only non-ratcheted data can be erased. Erase should only be used in testing to remove the test values. All data in production should be secured by using the ratchet mechanism.
Note
ATM5: There is no ratchet. erase clears the Flash portion of the journal, which is possible only until the sticky write lock is applied. The OTP portion can never be erased.
To support prototyping, you can erase non-ratcheted data easily through:
west secjrnl erase --device <DEVICE_ID> --jlink --board <BOARD>
Ratcheting Secure Journal
Note
ATM34 only. ATM5 has no secure ratchet and it cannot be advanced, so ratchet_jrnl and get_ratchet do not apply. To permanently commit data on ATM5, write it to OTP with west secjrnl burn --storage otp.
This will list the non-ratcheted tags and confirm that you want to ratchet the tags. Confirm by typing ‘yes’.
To ratchet data, run the command:
west secjrnl ratchet_jrnl --device <DEVICE_ID> --jlink --board <BOARD>
Note
This process is non-reversible. Once ratcheted, that region of the secure journal cannot be modified.
Writing a full Secure Journal
Writing the secure journal to a device may be done with the west secjrnl burn subcommand. This subcommand will attempt to write the full journal, which may be impossible on chips that already have ratcheted the journal, or on chips that have burned data into OTP. Use with care.
This command expects the journal to be a file containing only the binary data that should be written to the device. This binary can be created either by a west secjrnl create command, or by storing the binary string output of west secjrnl dump --binary into a file.
west secjrnl burn --device <DEVICE_ID> --jlink --board <BOARD> --sec-jrnl <JOURNAL_BINARY>
On ATM5, in order to write the journal to OTP, also provide the --storage otp flag. Without it, the journal is written to the Flash portion.
Warning
Writing OTP is permanent and cannot be undone. The tool asks for a yes confirmation before writing to OTP. --storage otp is also accepted by dump, get and append to read or write the OTP portion.