Skip to content

Commit af65e15

Browse files
committed
chore: document general and app attributes
Signed-off-by: Mohamed Daoudo <mohamed.daoudo@stud.fils.upb.ro>
1 parent 76b9397 commit af65e15

3 files changed

Lines changed: 160 additions & 20 deletions

File tree

tockloader-lib/src/attributes/app_attributes.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@ use tokio_serial::SerialStream;
1212
use crate::bootloader_serial::{issue_command, Command, Response};
1313
use crate::errors::TockloaderError;
1414

15+
/// This structure contains all relevant information about a tock application.
16+
///
17+
/// All data is stored either within [TbfHeader]s, or [TbfFooter]s.
18+
///
19+
/// See also <https://book.tockos.org/doc/tock_binary_format>
1520
#[derive(Debug)]
1621
pub struct AppAttributes {
1722
pub tbf_header: TbfHeader,
1823
pub tbf_footers: Vec<TbfFooter>,
1924
}
2025

26+
/// This structure represents a footer of a Tock application. Currently, footers
27+
/// only contain credentials, which are used to verify the integrity of the
28+
/// application.
2129
#[derive(Debug)]
2230
pub struct TbfFooter {
2331
pub credentials: TbfFooterV2Credentials,
@@ -40,7 +48,19 @@ impl AppAttributes {
4048
}
4149
}
4250

43-
// TODO: Document this function
51+
/// Retrieve all application attributes from the device's memory using a
52+
/// probe-rs connection.
53+
///
54+
/// Applications are layed out in memory sequentially, starting from the
55+
/// `appaddr` address. This function will attempt to read all applications
56+
/// until it fails to parse.
57+
///
58+
/// # Parameters
59+
/// - `board_core`: Core access, obtained from a
60+
/// [ProbeRSConnection](crate::connection::ProbeRSConnection)
61+
/// - `addr`: The starting address of the first application in memory.
62+
/// Board-specific. See also
63+
/// [BoardSettings](crate::board_settings::BoardSettings).
4464
pub(crate) fn read_apps_data_probe(
4565
board_core: &mut Core,
4666
addr: u64,
@@ -49,6 +69,8 @@ impl AppAttributes {
4969
let mut apps_counter = 0;
5070
let mut apps_details: Vec<AppAttributes> = vec![];
5171

72+
// All applications are stored sequentially in memory, so we read until
73+
// we fail to parse.
5274
loop {
5375
let mut appdata = vec![0u8; 8];
5476

@@ -60,6 +82,11 @@ impl AppAttributes {
6082
let header_size: u16;
6183
let total_size: u32;
6284

85+
// The first 8 bytes of the application data contain the TBF header
86+
// lengths and version.
87+
//
88+
// Note on expect: `read` always fills up the entire buffer, which
89+
// was previously declared as 8 bytes.
6390
match parse_tbf_header_lengths(
6491
&appdata
6592
.try_into()
@@ -81,14 +108,24 @@ impl AppAttributes {
81108
let header = parse_tbf_header(&header_data, tbf_version)
82109
.map_err(TockloaderError::ParsingError)?;
83110

111+
// The end of the application binary marks the beginning of the
112+
// footer.
113+
//
114+
// TODO(george-cosma): This is not always true, `get_binary_end`
115+
// does not make sense if the application is just padding. This can
116+
// crash the process.
84117
let binary_end_offset = header.get_binary_end();
85118

86119
let mut footers: Vec<TbfFooter> = vec![];
87120
let total_footers_size = total_size - binary_end_offset;
88121
let mut footer_offset = binary_end_offset;
89122
let mut footer_number = 0;
90123

124+
// Try to parse footers until we reach the end of the application.
91125
loop {
126+
// We don't know the size of the current footer, so we read the
127+
// remaining bytes in the application (`footer_offset -
128+
// binary_end_offset`) , even if we overread.
92129
let mut appfooter =
93130
vec![0u8; (total_footers_size - (footer_offset - binary_end_offset)) as usize];
94131

@@ -102,6 +139,7 @@ impl AppAttributes {
102139
footers.insert(footer_number, TbfFooter::new(footer_info.0, footer_info.1));
103140

104141
footer_number += 1;
142+
// we add 4 because that is the size of TL part of the TLV header (2 bytes type + 2 bytes length)
105143
footer_offset += footer_info.1 + 4;
106144

107145
if footer_offset == total_size {
@@ -117,7 +155,19 @@ impl AppAttributes {
117155
}
118156
}
119157

120-
// TODO: Document this function
158+
/// Retrieve all application attributes from the device's memory using a
159+
/// serial connection.
160+
///
161+
/// Applications are layed out in memory sequentially, starting from the
162+
/// `appaddr` address. This function will attempt to read all applications
163+
/// until it fails to parse.
164+
///
165+
/// # Parameters
166+
/// - `port`: Serial access, obtained from a
167+
/// [SerialConnection](crate::connection::SerialConnection)
168+
/// - `addr`: The starting address of the first application in memory.
169+
/// Board-specific. See also
170+
/// [BoardSettings](crate::board_settings::BoardSettings).
121171
pub(crate) async fn read_apps_data_serial(
122172
port: &mut SerialStream,
123173
addr: u64,
@@ -126,20 +176,30 @@ impl AppAttributes {
126176
let mut apps_counter = 0;
127177
let mut apps_details: Vec<AppAttributes> = vec![];
128178

179+
// All applications are stored sequentially in memory, so we read until
180+
// we fail to parse.
129181
loop {
182+
// The tockloader protocol only supports 32-bit architectures,
183+
// though in the future support will be extended to 64-bit.
130184
let mut pkt = (appaddr as u32).to_le_bytes().to_vec();
131185
let length = (8_u16).to_le_bytes().to_vec();
132186
for i in length {
133187
pkt.push(i);
134188
}
135189

190+
// Read the first 8 bytes, which is the length of a TLV header.
136191
let (_, appdata) =
137192
issue_command(port, Command::ReadRange, pkt, true, 8, Response::ReadRange).await?;
138193

139194
let tbf_version: u16;
140195
let header_size: u16;
141196
let total_size: u32;
142197

198+
// The first 8 bytes of the application data contain the TBF header
199+
// lengths and version.
200+
//
201+
// Note on expect: `read` always fills up the entire buffer, which
202+
// was previously declared as 8 bytes.
143203
match parse_tbf_header_lengths(
144204
&appdata[0..8]
145205
.try_into()
@@ -159,6 +219,7 @@ impl AppAttributes {
159219
pkt.push(i);
160220
}
161221

222+
// Read the rest of the header
162223
let (_, header_data) = issue_command(
163224
port,
164225
Command::ReadRange,
@@ -178,7 +239,11 @@ impl AppAttributes {
178239
let mut footer_offset = binary_end_offset;
179240
let mut footer_number = 0;
180241

242+
// Try to parse footers until we reach the end of the application.
181243
loop {
244+
// We don't know the size of the current footer, so we read the
245+
// remaining bytes in the application (`footer_offset -
246+
// binary_end_offset`) , even if we overread.
182247
let mut pkt = (appaddr as u32 + footer_offset).to_le_bytes().to_vec();
183248
let length = ((total_footers_size - (footer_offset - binary_end_offset)) as u16)
184249
.to_le_bytes()
@@ -187,6 +252,7 @@ impl AppAttributes {
187252
pkt.push(i);
188253
}
189254

255+
// Read the next header (and perhaps data beyond it)
190256
let (_, appfooter) = issue_command(
191257
port,
192258
Command::ReadRange,
@@ -203,6 +269,7 @@ impl AppAttributes {
203269
footers.insert(footer_number, TbfFooter::new(footer_info.0, footer_info.1));
204270

205271
footer_number += 1;
272+
// we add 4 because that is the size of TL part of the TLV header (2 bytes type + 2 bytes length)
206273
footer_offset += footer_info.1 + 4;
207274

208275
if footer_offset == total_size {

tockloader-lib/src/attributes/decode.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33
// Copyright OXIDOS AUTOMOTIVE 2024.
44

5+
/// Attributes are key-value pairs that describe hardware configuration, stored
6+
/// in a fixed 64-byte format:
7+
///
8+
/// 1. Bytes 0–7: UTF-8 key string with null-byte padding for shorter strings
9+
/// 2. Byte 8: Value length (Must be between 1 and 55)
10+
/// 3. Bytes 9–63: UTF-8 value string. Null-padded to length.
11+
///
12+
/// See also <https://book.tockos.org/doc/kernel_attributes.html?highlight=attributes#header-format>
513
#[derive(Debug)]
614
pub struct DecodedAttribute {
715
pub key: String,
@@ -17,7 +25,15 @@ impl DecodedAttribute {
1725
}
1826
}
1927

20-
// TODO: explain what is happening here
28+
/// Internal function used to decode the raw data into a [DecodedAttribute].
29+
///
30+
/// # Params
31+
/// - `step` - byte array of at least 64 bytes.
32+
///
33+
/// # Returns
34+
/// - `None` for an invalid property (invalid value length or invalid utf-8
35+
/// data).
36+
/// - `Some(_)` otherwise
2137
pub(crate) fn decode_attribute(step: &[u8]) -> Option<DecodedAttribute> {
2238
let raw_key = &step[0..8];
2339

@@ -47,7 +63,14 @@ pub(crate) fn decode_attribute(step: &[u8]) -> Option<DecodedAttribute> {
4763
Some(DecodedAttribute::new(key, value))
4864
}
4965

50-
// TODO: explain what is happening here
66+
// TODO(george-cosma) replace this function with std::str::from_utf8(...). It
67+
// does the same thing.
68+
69+
/// Transform a byte-slice into a String.
70+
///
71+
/// # Panics
72+
///
73+
/// This code panics if the given bytes are not utf-8 representable
5174
pub(crate) fn bytes_to_string(raw: &[u8]) -> String {
5275
let decoder = utf8_decode::Decoder::new(raw.iter().cloned());
5376

0 commit comments

Comments
 (0)