@@ -7,7 +7,7 @@ use byteorder::{ByteOrder, LittleEndian};
77use crate :: errors:: { AttributeParseError , TockError , TockloaderError } ;
88use 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 ] ) ;
0 commit comments