Skip to content

Commit 022dafa

Browse files
committed
feat: add start_address and change system_atributes to conform
1 parent 8985e2c commit 022dafa

9 files changed

Lines changed: 124 additions & 84 deletions

File tree

tockloader-lib/src/attributes/decode.rs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ pub(crate) fn decode_attribute(step: &[u8]) -> Option<DecodedAttribute> {
4141

4242
let mut key = String::new();
4343
for n in decoder_key {
44-
key.push(n.expect("Error getting key for attributes."));
44+
// TODO: This should not expect, we should return none in case the chip doesn't have a bootloader
45+
match n {
46+
Ok(c) => key.push(c),
47+
Err(_) => return None,
48+
}
4549
}
4650

4751
key = key.trim_end_matches('\0').to_string();
@@ -56,27 +60,13 @@ pub(crate) fn decode_attribute(step: &[u8]) -> Option<DecodedAttribute> {
5660
let mut value = String::new();
5761

5862
for n in decoder_value {
59-
value.push(n.expect("Error getting key for attributes."));
63+
// TODO: This should not expect, we should return none in case the chip doesn't have a bootloader
64+
match n {
65+
Ok(c) => value.push(c),
66+
Err(_) => return None,
67+
}
6068
}
6169

6270
value = value.trim_end_matches('\0').to_string();
6371
Some(DecodedAttribute::new(key, value))
6472
}
65-
66-
// TODO(eva-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
74-
pub(crate) fn bytes_to_string(raw: &[u8]) -> String {
75-
let decoder = utf8_decode::Decoder::new(raw.iter().cloned());
76-
77-
let mut string = String::new();
78-
for n in decoder {
79-
string.push(n.expect("Error getting key for attributes."));
80-
}
81-
string
82-
}

tockloader-lib/src/attributes/system_attributes.rs

Lines changed: 93 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use byteorder::{ByteOrder, LittleEndian};
77
use crate::errors::{AttributeParseError, TockError, TockloaderError};
88
use crate::IO;
99

10-
use super::decode::{bytes_to_string, decode_attribute};
10+
use super::decode::decode_attribute;
1111

1212
/// This structure contains all relevant information about board that is stored
1313
/// in the bootloader ROM.
@@ -48,12 +48,28 @@ impl SystemAttributes {
4848
}
4949
}
5050

51-
/// Read system attributes using a generalized connection. A bootloader must be
52-
/// present on this board for this function to work properly.
53-
///
51+
/// Check if the bootloader is present on the version of Tock
52+
pub(crate) async fn bootloader_is_present(
53+
conn: &mut dyn IO,
54+
flash_address: u64,
55+
) -> Result<bool, TockloaderError> {
56+
// If a bootloader is present, the start of 0x400 will read
57+
// "TOCKBOOTLOADER", which is exactly 14 bytes long, so we'll read
58+
// 14 bytes starting from 0x400.
59+
let flag = conn.read(flash_address + 0x400, 14).await?;
60+
if flag == "TOCKBOOTLOADER".as_bytes() {
61+
Ok(true)
62+
} else {
63+
Ok(false)
64+
}
65+
}
66+
/// Read system and kernel attributes.
67+
/// System attributes are read only if the board has
68+
/// a bootloader present.
5469
/// # Parameters
55-
/// - `conn` : Either a SerialConnection or a ProbeRSConnection
56-
///
70+
/// - `conn` : Either a SerialConnection or a ProbeRSConnection.
71+
/// - `flash_address` : The start of flash memory.
72+
/// - `start_address` : The start of User Space Applications in flash memory.
5773
/// # Returns
5874
/// - Ok(result): if attributes were read successfully
5975
/// - Err(TockloaderError::MisconfiguredBoard): if no start address is found or valid
@@ -62,74 +78,91 @@ impl SystemAttributes {
6278
/// - Err(TockloaderError::SerialReadError): if reading fails on Serial
6379
pub(crate) async fn read_system_attributes(
6480
conn: &mut dyn IO,
81+
flash_address: u64,
82+
start_address: u64,
6583
) -> Result<SystemAttributes, TockloaderError> {
6684
let mut result = SystemAttributes::new();
6785
// System attributes start at 0x600 and up to 0x9FF. See:
6886
// https://book.tockos.org/doc/memory_layout#flash-1
69-
let address = 0x600;
87+
let address = flash_address + 0x600;
7088

7189
let buf = conn.read(address, 64 * 16).await?;
7290

7391
let mut data = buf.chunks(64);
7492

75-
for current_slot in 0..data.len() {
76-
let slot_data = match data.next() {
77-
Some(data) => data,
78-
None => break,
79-
};
80-
81-
// If the attribute chunk was successfully decoded, assign its value
82-
// to the corresponding field in `result` based on the index:
83-
// - 0 = board name,
84-
// - 1 = architecture,
85-
// - 2 = application start address (parsed from hex string),
86-
// - 3 = boot hash, _ = invalid or missing data is skipped.
87-
// NOTE: this can also be done by looping directly through the key attributes.
88-
if let Some(decoded_attributes) = decode_attribute(slot_data) {
89-
match current_slot {
90-
0 => {
91-
result.board = Some(decoded_attributes.value.to_string());
92-
}
93-
1 => {
94-
result.arch = Some(decoded_attributes.value.to_string());
95-
}
96-
2 => {
97-
// Parse hex string like "0x40000" into actual u64 value
98-
result.appaddr = Some(
99-
u64::from_str_radix(
100-
decoded_attributes
101-
.value
102-
.to_string()
103-
.trim_start_matches("0x"),
104-
16,
105-
)
106-
.map_err(|e| {
107-
TockError::AttributeParsing(AttributeParseError::InvalidNumber(e))
108-
})?,
109-
);
110-
}
111-
3 => {
112-
result.boothash = Some(decoded_attributes.value.to_string());
93+
let has_bootloader = Self::bootloader_is_present(conn, flash_address)
94+
.await
95+
.unwrap_or(false);
96+
97+
if !has_bootloader {
98+
// TODO: Chain: CLI arguments -> hardcoded start_address -> calculate from kernel app start address
99+
result.appaddr = Some(start_address);
100+
} else {
101+
for current_slot in 0..data.len() {
102+
let slot_data = match data.next() {
103+
Some(data) => data,
104+
None => break,
105+
};
106+
107+
// If the attribute chunk was successfully decoded, assign its value
108+
// to the corresponding field in `result` based on the index:
109+
// - 0 = board name,
110+
// - 1 = architecture,
111+
// - 2 = application start address (parsed from hex string),
112+
// - 3 = boot hash, _ = invalid or missing data is skipped.
113+
// NOTE: this can also be done by looping directly through the key attributes.
114+
if let Some(decoded_attributes) = decode_attribute(slot_data) {
115+
match current_slot {
116+
0 => {
117+
result.board = Some(decoded_attributes.value.to_string());
118+
}
119+
1 => {
120+
result.arch = Some(decoded_attributes.value.to_string());
121+
}
122+
2 => {
123+
// Parse hex string like "0x40000" into actual u64 value
124+
result.appaddr = Some(
125+
u64::from_str_radix(
126+
decoded_attributes
127+
.value
128+
.to_string()
129+
.trim_start_matches("0x"),
130+
16,
131+
)
132+
.map_err(|e| {
133+
TockError::AttributeParsing(AttributeParseError::InvalidNumber(
134+
e,
135+
))
136+
})?,
137+
);
138+
}
139+
3 => {
140+
result.boothash = Some(decoded_attributes.value.to_string());
141+
}
142+
_ => {}
113143
}
114-
_ => {}
144+
} else {
145+
continue;
115146
}
116-
} else {
117-
continue;
118147
}
119-
}
120-
121-
// TODO(eva-cosma): separate kernel attributes from kernel flags.
122148

123-
let address = 0x40E;
149+
// At this address lives the version of the bootloader we are using.
150+
// Trying to read this when no bootloader is present will result in a panic.
151+
// So we first verify if we have a bootloader, if not we just skip this and
152+
// return None for the bootloader version.
153+
let address = flash_address + 0x40E;
124154

125-
let buf = conn.read(address, 8).await?;
155+
let buf = conn.read(address, 8).await?;
126156

127-
let string = String::from_utf8(buf.to_vec())
128-
.map_err(|e| TockError::AttributeParsing(AttributeParseError::InvalidString(e)))?;
157+
let string = String::from_utf8(buf.to_vec())
158+
.map_err(|e| TockError::AttributeParsing(AttributeParseError::InvalidString(e)))?;
129159

130-
let string = string.trim_matches(char::from(0));
160+
let string = string.trim_matches(char::from(0));
131161

132-
result.bootloader_version = Some(string.to_owned());
162+
result.bootloader_version = Some(string.to_owned());
163+
}
164+
165+
// TODO(eva-cosma): separate kernel attributes from kernel flags.
133166

134167
// The 100 bytes prior to the application start address are reserved for the kernel attributes and flags
135168
let kernel_attr_addr = result
@@ -138,7 +171,9 @@ impl SystemAttributes {
138171
- 100;
139172
let kernel_attr_binary = conn.read(kernel_attr_addr, 100).await?;
140173

141-
let sentinel = bytes_to_string(&kernel_attr_binary[96..100]);
174+
let sentinel = std::str::from_utf8(&kernel_attr_binary[96..100])
175+
.unwrap_or("unknown")
176+
.to_string();
142177
let kernel_version = LittleEndian::read_uint(&kernel_attr_binary[95..96], 1);
143178

144179
let app_memory_len = LittleEndian::read_u32(&kernel_attr_binary[84..92]);

tockloader-lib/src/board_settings.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[derive(Clone)]
22
pub struct BoardSettings {
33
pub arch: Option<String>,
4+
pub flash_address: u64,
45
pub start_address: u64,
56
pub page_size: u64,
67
pub ram_start_address: u64,
@@ -12,6 +13,7 @@ impl Default for BoardSettings {
1213
fn default() -> Self {
1314
Self {
1415
arch: None,
16+
flash_address: 0x00000, // this would be actually like -0x10000
1517
start_address: 0x30000,
1618
page_size: 512,
1719
ram_start_address: 0x20000000,

tockloader-lib/src/bootloader_serial.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ async fn write_bytes(
156156
.map_err(|_| TockError::BootloaderTimeout)?
157157
}
158158

159-
#[allow(dead_code)]
160159
pub async fn ping_bootloader_and_wait_for_response(
161160
port: &mut SerialStream,
162161
) -> Result<(), TockloaderError> {

tockloader-lib/src/command_impl/info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use crate::{CommandInfo, IOCommands};
88
#[async_trait]
99
impl CommandInfo for TockloaderConnection {
1010
async fn info(&mut self) -> Result<GeneralAttributes, TockloaderError> {
11-
let installed_apps = self.read_installed_apps().await.unwrap();
12-
let system_atributes = self.read_system_attributes().await.unwrap();
11+
let installed_apps = self.read_installed_apps().await?;
12+
let system_atributes = self.read_system_attributes().await?;
1313
Ok(GeneralAttributes::new(system_atributes, installed_apps))
1414
}
1515
}

tockloader-lib/src/command_impl/probers/io.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ impl IOCommands for ProbeRSConnection {
5353
if !self.is_open() {
5454
return Err(InternalError::ConnectionNotOpen.into());
5555
}
56-
let system_attributes = SystemAttributes::read_system_attributes(self).await?;
56+
let flash_address = self.get_settings().flash_address;
57+
let start_address = self.get_settings().start_address;
58+
let system_attributes =
59+
SystemAttributes::read_system_attributes(self, flash_address, start_address).await?;
5760
Ok(system_attributes)
5861
}
5962
}

tockloader-lib/src/command_impl/reshuffle_apps.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ mod tests {
511511
fn install_new_c_app() {
512512
let settings: &BoardSettings = &BoardSettings {
513513
arch: Some("cortex-m4".to_string()),
514+
flash_address: 0x00000000,
514515
start_address: 0x00040000,
515516
page_size: 512,
516517
ram_start_address: 0x20000000,
@@ -568,6 +569,7 @@ mod tests {
568569
fn install_new_rust_app() {
569570
let settings: &BoardSettings = &BoardSettings {
570571
arch: Some("cortex-m4".to_string()),
572+
flash_address: 0x00000000,
571573
start_address: 0x00040000,
572574
page_size: 512,
573575
ram_start_address: 0x20000000,
@@ -604,6 +606,7 @@ mod tests {
604606
fn install_more_rust_apps() {
605607
let settings: &BoardSettings = &BoardSettings {
606608
arch: Some("cortex-m4".to_string()),
609+
flash_address: 0x00000000,
607610
start_address: 0x00040000,
608611
page_size: 512,
609612
ram_start_address: 0x20000000,
@@ -678,6 +681,7 @@ mod tests {
678681
fn insert_c_app_between_rust_apps() {
679682
let settings: &BoardSettings = &BoardSettings {
680683
arch: Some("cortex-m4".to_string()),
684+
flash_address: 0x00000000,
681685
start_address: 0x00040000,
682686
page_size: 512,
683687
ram_start_address: 0x20000000,

tockloader-lib/src/command_impl/serial/io.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ impl IOCommands for SerialConnection {
8484

8585
ping_bootloader_and_wait_for_response(stream).await?;
8686

87-
let system_attributes = SystemAttributes::read_system_attributes(self).await?;
87+
let flash_address = self.get_settings().flash_address;
88+
let start_address = self.get_settings().start_address;
89+
let system_attributes =
90+
SystemAttributes::read_system_attributes(self, flash_address, start_address).await?;
8891
Ok(system_attributes)
8992
}
9093
}

tockloader-lib/src/known_boards.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ impl KnownBoard for NucleoF4 {
2424
fn get_settings(&self) -> BoardSettings {
2525
BoardSettings {
2626
arch: Some("cortex-m4".to_string()),
27+
flash_address: 0x08000000,
2728
start_address: 0x08040000,
2829
page_size: 512,
2930
ram_start_address: 0x20000000,
@@ -48,6 +49,7 @@ impl KnownBoard for MicrobitV2 {
4849
fn get_settings(&self) -> BoardSettings {
4950
BoardSettings {
5051
arch: Some("cortex-m4".to_string()),
52+
flash_address: 0x00000000,
5153
start_address: 0x00040000,
5254
page_size: 512,
5355
ram_start_address: 0x20000000,
@@ -72,6 +74,7 @@ impl KnownBoard for Nrf52840dk {
7274
fn get_settings(&self) -> BoardSettings {
7375
BoardSettings {
7476
arch: Some("cortex-m4".to_string()),
77+
flash_address: 0x00000000,
7578
start_address: 0x00040000,
7679
page_size: 4096,
7780
ram_start_address: 0x20008000,
@@ -96,7 +99,8 @@ impl KnownBoard for NucleoU545ReQ {
9699
fn get_settings(&self) -> BoardSettings {
97100
BoardSettings {
98101
arch: Some("cortex-m4".to_string()),
99-
start_address: 0x08000000,
102+
flash_address: 0x08000000,
103+
start_address: 0x08040000,
100104
page_size: 8192,
101105
ram_start_address: 0x20000000,
102106
}

0 commit comments

Comments
 (0)