Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tbf-parser/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ pub struct TbfHeaderV2 {
// Clippy suggests we box TbfHeaderV2. We can't really do that, since
// we are runnning under no_std, and I don't think it's that big of a issue.
#[allow(clippy::large_enum_variant)]
#[derive(Clone)]
pub enum TbfHeader {
TbfHeaderV2(TbfHeaderV2),
Padding(TbfHeaderV2Base),
Expand Down
30 changes: 16 additions & 14 deletions tockloader-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,12 @@ async fn open_connection(user_options: &ArgMatches) -> Result<TockloaderConnecti
.context("No device is connected.")?
};

let mut conn: TockloaderConnection =
SerialConnection::new(path, get_serial_target_info(user_options)).into();
let mut conn: TockloaderConnection = SerialConnection::new(
path,
get_serial_target_info(user_options),
get_board_settings(user_options),
)
.into();
conn.open()
.await
.context("Failed to open serial connection.")?;
Expand All @@ -124,8 +128,12 @@ async fn open_connection(user_options: &ArgMatches) -> Result<TockloaderConnecti
.prompt()
.context("No debug probe is connected.")?;

let mut conn: TockloaderConnection =
ProbeRSConnection::new(ans, get_probe_target_info(user_options)).into();
let mut conn: TockloaderConnection = ProbeRSConnection::new(
ans,
get_probe_target_info(user_options),
get_board_settings(user_options),
)
.into();

conn.open()
.await
Expand Down Expand Up @@ -199,19 +207,17 @@ async fn main() -> Result<()> {
cli::validate(&mut cmd, sub_matches);

let mut conn = open_connection(sub_matches).await?;
let settings = get_board_settings(sub_matches);

let app_details = conn.list(&settings).await.context("Failed to list apps.")?;
let app_details = conn.list().await.context("Failed to list apps.")?;

display::print_list(&app_details).await;
}
Some(("info", sub_matches)) => {
cli::validate(&mut cmd, sub_matches);
let mut conn = open_connection(sub_matches).await?;
let settings = get_board_settings(sub_matches);

let mut attributes = conn
.info(&settings)
.info()
.await
.context("Failed to get data from the board.")?;

Expand All @@ -223,20 +229,16 @@ async fn main() -> Result<()> {
.context("Failed to use provided tab file.")?;

let mut conn = open_connection(sub_matches).await?;
let settings = get_board_settings(sub_matches);

conn.install_app(&settings, tab_file)
conn.install_app(tab_file)
.await
.context("Failed to install app.")?;
}
Some(("erase-apps", sub_matches)) => {
cli::validate(&mut cmd, sub_matches);
let mut conn = open_connection(sub_matches).await?;
let settings = get_board_settings(sub_matches);

conn.erase_apps(&settings)
.await
.context("Failed to erase apps.")?;
conn.erase_apps().await.context("Failed to erase apps.")?;
}
_ => {
println!("Could not run the provided subcommand.");
Expand Down
1 change: 1 addition & 0 deletions tockloader-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ serde = { version = "1.0.210", features = ["derive"] }
thiserror = "1.0.63"
async-trait = "0.1.88"
log = "0.4.27"
itertools = "0.14.0"
41 changes: 21 additions & 20 deletions tockloader-lib/src/attributes/app_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ use crate::errors::{TockError, TockloaderError};
/// See also <https://book.tockos.org/doc/tock_binary_format>
#[derive(Debug)]
pub struct AppAttributes {
pub address: u64,
pub tbf_header: TbfHeader,
pub tbf_footers: Vec<TbfFooter>,
}

/// This structure represents a footer of a Tock application. Currently, footers
/// only contain credentials, which are used to verify the integrity of the
/// application.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct TbfFooter {
pub credentials: TbfFooterV2Credentials,
pub size: u32,
Expand All @@ -41,8 +42,13 @@ impl TbfFooter {
// TODO(george-cosma): Could take advantages of the trait rework

impl AppAttributes {
pub(crate) fn new(header_data: TbfHeader, footers_data: Vec<TbfFooter>) -> AppAttributes {
pub(crate) fn new(
address: u64,
header_data: TbfHeader,
footers_data: Vec<TbfFooter>,
) -> AppAttributes {
AppAttributes {
address,
tbf_header: header_data,
tbf_footers: footers_data,
}
Expand Down Expand Up @@ -117,13 +123,10 @@ impl AppAttributes {
// crash the process.
let binary_end_offset = header.get_binary_end();

match &header {
TbfHeader::TbfHeaderV2(_hd) => {}
_ => {
appaddr += total_size as u64;
continue;
}
};
if !header.is_app() {
appaddr += total_size as u64;
continue;
}

let mut footers: Vec<TbfFooter> = vec![];
let total_footers_size = total_size - binary_end_offset;
Expand All @@ -137,9 +140,9 @@ impl AppAttributes {
// binary_end_offset`) , even if we overread.
let mut appfooter =
vec![0u8; (total_footers_size - (footer_offset - binary_end_offset)) as usize];

// log::info!("footer init {:?}", appfooter);
board_core.read(appaddr + footer_offset as u64, &mut appfooter)?;

// log::info!("footer read {:?}", appfooter);
let footer_info =
parse_tbf_footer(&appfooter).map_err(TockError::InvalidAppTbfHeader)?;

Expand All @@ -150,7 +153,7 @@ impl AppAttributes {
footer_offset += footer_info.1 + 4;
}

let details: AppAttributes = AppAttributes::new(header, footers);
let details: AppAttributes = AppAttributes::new(appaddr, header, footers);

apps_details.insert(apps_counter, details);
apps_counter += 1;
Expand Down Expand Up @@ -240,15 +243,13 @@ impl AppAttributes {
log::debug!("App #{apps_counter}: Header data: {header_data:?}");
let header = parse_tbf_header(&header_data, tbf_version)
.map_err(TockError::InvalidAppTbfHeader)?;

let binary_end_offset = header.get_binary_end();

match &header {
TbfHeader::TbfHeaderV2(_hd) => {}
_ => {
appaddr += total_size as u64;
continue;
}
};
if !header.is_app() {
appaddr += total_size as u64;
continue;
}

let mut footers: Vec<TbfFooter> = vec![];
let total_footers_size = total_size - binary_end_offset;
Expand Down Expand Up @@ -289,7 +290,7 @@ impl AppAttributes {
footer_offset += footer_info.1 + 4;
}

let details: AppAttributes = AppAttributes::new(header, footers);
let details: AppAttributes = AppAttributes::new(appaddr, header, footers);

apps_details.insert(apps_counter, details);
apps_counter += 1;
Expand Down
5 changes: 5 additions & 0 deletions tockloader-lib/src/board_settings.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#[derive(Clone)]
pub struct BoardSettings {
pub arch: Option<String>,
pub start_address: u64,
pub page_size: u64,
pub ram_start_address: u64,
}

// TODO(george-cosma): Does a default implementation make sense for this? Is a
Expand All @@ -10,6 +13,8 @@ impl Default for BoardSettings {
Self {
arch: None,
start_address: 0x30000,
page_size: 512,
ram_start_address: 0x20000000,
}
}
}
7 changes: 4 additions & 3 deletions tockloader-lib/src/bootloader_serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// The "X" commands are for external flash

use crate::errors::{self, InternalError, TockError};
use bytes::BytesMut;
use bytes::{BufMut, BytesMut};
use errors::TockloaderError;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
Expand All @@ -17,7 +17,7 @@ pub const SYNC_MESSAGE: [u8; 3] = [0x00, 0xFC, 0x05];
// "This was chosen as it is infrequent in .bin files" - immesys
pub const ESCAPE_CHAR: u8 = 0xFC;

pub const DEFAULT_TIMEOUT: Duration = Duration::from_millis(500);
pub const DEFAULT_TIMEOUT: Duration = Duration::from_millis(5000);

#[allow(dead_code)]
pub enum Command {
Expand Down Expand Up @@ -217,7 +217,7 @@ pub async fn issue_command(
}

if response_len != 0 {
let input = read_bytes(port, response_len, DEFAULT_TIMEOUT).await?;
let mut input = read_bytes(port, response_len, DEFAULT_TIMEOUT).await?;
let mut result = Vec::with_capacity(input.len());

// De-escape and add array of read in the bytes
Expand All @@ -227,6 +227,7 @@ pub async fn issue_command(
while i < input.len() {
if i + 1 < input.len() && input[i] == ESCAPE_CHAR && input[i + 1] == ESCAPE_CHAR {
// Found consecutive ESCAPE_CHAR bytes, add only one
input.put(read_bytes(port, 1, DEFAULT_TIMEOUT).await?);
result.push(ESCAPE_CHAR);
i += 2; // Skip both bytes
} else {
Expand Down
13 changes: 13 additions & 0 deletions tockloader-lib/src/command_impl/erase_apps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use async_trait::async_trait;

use crate::connection::{Connection, TockloaderConnection};
use crate::errors::TockloaderError;
use crate::{CommandEraseApps, IO};

#[async_trait]
impl CommandEraseApps for TockloaderConnection {
async fn erase_apps(&mut self) -> Result<(), TockloaderError> {
self.write(self.get_settings().start_address, &[0u8])
.await
}
}
50 changes: 16 additions & 34 deletions tockloader-lib/src/command_impl/generalized.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,41 @@
use async_trait::async_trait;

use crate::attributes::app_attributes::AppAttributes;
use crate::attributes::general_attributes::GeneralAttributes;
use crate::board_settings::BoardSettings;
use crate::attributes::system_attributes::SystemAttributes;
use crate::connection::TockloaderConnection;
use crate::errors::TockloaderError;
use crate::tabs::tab::Tab;
use crate::{CommandEraseApps, CommandInfo, CommandInstall, CommandList};
use crate::{IOCommands, IO};

#[async_trait]
impl CommandList for TockloaderConnection {
async fn list(
&mut self,
settings: &BoardSettings,
) -> Result<Vec<AppAttributes>, TockloaderError> {
impl IO for TockloaderConnection {
async fn read(&mut self, address: u64, size: usize) -> Result<Vec<u8>, TockloaderError> {
match self {
TockloaderConnection::ProbeRS(conn) => conn.list(settings).await,
TockloaderConnection::Serial(conn) => conn.list(settings).await,
TockloaderConnection::ProbeRS(conn) => conn.read(address, size).await,
TockloaderConnection::Serial(conn) => conn.read(address, size).await,
}
}
}

#[async_trait]
impl CommandInfo for TockloaderConnection {
async fn info(
&mut self,
settings: &BoardSettings,
) -> Result<GeneralAttributes, TockloaderError> {
async fn write(&mut self, address: u64, pkt: &[u8]) -> Result<(), TockloaderError> {
match self {
TockloaderConnection::ProbeRS(conn) => conn.info(settings).await,
TockloaderConnection::Serial(conn) => conn.info(settings).await,
TockloaderConnection::ProbeRS(conn) => conn.write(address, pkt).await,
TockloaderConnection::Serial(conn) => conn.write(address, pkt).await,
}
}
}

#[async_trait]
impl CommandInstall for TockloaderConnection {
async fn install_app(
&mut self,
settings: &BoardSettings,
tab_file: Tab,
) -> Result<(), TockloaderError> {
impl IOCommands for TockloaderConnection {
async fn read_installed_apps(&mut self) -> Result<Vec<AppAttributes>, TockloaderError> {
match self {
TockloaderConnection::ProbeRS(conn) => conn.install_app(settings, tab_file).await,
TockloaderConnection::Serial(conn) => conn.install_app(settings, tab_file).await,
TockloaderConnection::ProbeRS(conn) => conn.read_installed_apps().await,
TockloaderConnection::Serial(conn) => conn.read_installed_apps().await,
}
}
}

#[async_trait]
impl CommandEraseApps for TockloaderConnection {
async fn erase_apps(&mut self, settings: &BoardSettings) -> Result<(), TockloaderError> {
async fn read_system_attributes(&mut self) -> Result<SystemAttributes, TockloaderError> {
match self {
TockloaderConnection::ProbeRS(conn) => conn.erase_apps(settings).await,
TockloaderConnection::Serial(conn) => conn.erase_apps(settings).await,
TockloaderConnection::ProbeRS(conn) => conn.read_system_attributes().await,
TockloaderConnection::Serial(conn) => conn.read_system_attributes().await,
}
}
}
15 changes: 15 additions & 0 deletions tockloader-lib/src/command_impl/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use async_trait::async_trait;

use crate::attributes::general_attributes::GeneralAttributes;
use crate::connection::TockloaderConnection;
use crate::errors::TockloaderError;
use crate::{CommandInfo, IOCommands};

#[async_trait]
impl CommandInfo for TockloaderConnection {
async fn info(&mut self) -> Result<GeneralAttributes, TockloaderError> {
let installed_apps = self.read_installed_apps().await.unwrap();
let system_atributes = self.read_system_attributes().await.unwrap();
Ok(GeneralAttributes::new(system_atributes, installed_apps))
}
}
49 changes: 49 additions & 0 deletions tockloader-lib/src/command_impl/install.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use async_trait::async_trait;

use crate::attributes::app_attributes::AppAttributes;
use crate::command_impl::reshuffle_apps::{create_pkt, reshuffle_apps, TockApp};
use crate::connection::{Connection, TockloaderConnection};
use crate::errors::TockloaderError;
use crate::tabs::tab::Tab;
use crate::{CommandInstall, CommandList, IO};

#[async_trait]
impl CommandInstall for TockloaderConnection {
async fn install_app(&mut self, tab: Tab) -> Result<(), TockloaderError> {
let settings = self.get_settings();
let app_attributes_list: Vec<AppAttributes> = self.list().await.unwrap();
let mut tock_app_list = app_attributes_list
.iter()
.map(TockApp::from_app_attributes)
.collect::<Vec<TockApp>>();

// obtain the binaries in a vector
let mut app_binaries: Vec<Vec<u8>> = Vec::new();

let mut address = settings.start_address;
for app in app_attributes_list.iter() {
app_binaries.push(
self.read(address, app.tbf_header.total_size() as usize)
.await
.unwrap(),
);
address += app.tbf_header.total_size() as u64;
}

let mut app = TockApp::from_tab(&tab, &settings).unwrap();

app.replace_idx(tock_app_list.len());
tock_app_list.push(app.clone());

app_binaries.push(tab.extract_binary(settings.arch.clone().unwrap()).unwrap());

let configuration = reshuffle_apps(&settings, tock_app_list).unwrap();

// create the pkt, this contains all the binaries in a vec
let pkt = create_pkt(configuration, app_binaries);

// write the pkt
let _ = self.write(settings.start_address, &pkt).await;
Ok(())
}
}
Loading
Loading