big progress
Some checks failed
Rust/va416xx-rs/pipeline/pr-main There was a failure building this commit
Some checks failed
Rust/va416xx-rs/pipeline/pr-main There was a failure building this commit
This commit is contained in:
parent
daa181d1de
commit
ac601d06cc
@ -115,6 +115,8 @@ fn main() -> ! {
|
|||||||
let nvm = Nvm::new(&mut dp.sysconfig, dp.spi3, &clocks);
|
let nvm = Nvm::new(&mut dp.sysconfig, dp.spi3, &clocks);
|
||||||
|
|
||||||
if FLASH_SELF {
|
if FLASH_SELF {
|
||||||
|
let mut first_four_bytes: [u8; 4] = [0; 4];
|
||||||
|
read_four_bytes_at_addr_zero(&mut first_four_bytes);
|
||||||
let bootloader_data = {
|
let bootloader_data = {
|
||||||
unsafe {
|
unsafe {
|
||||||
&*core::ptr::slice_from_raw_parts(
|
&*core::ptr::slice_from_raw_parts(
|
||||||
@ -123,15 +125,6 @@ fn main() -> ! {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut first_four_bytes: [u8; 4] = [0; 4];
|
|
||||||
unsafe {
|
|
||||||
core::arch::asm!(
|
|
||||||
"ldr r0, [{0}]", // Load 4 bytes from src into r0 register
|
|
||||||
"str r0, [{1}]", // Store r0 register into first_four_bytes
|
|
||||||
in(reg) BOOTLOADER_START_ADDR as *const u8, // Input: src pointer (0x0)
|
|
||||||
in(reg) &mut first_four_bytes as *mut [u8; 4], // Input: destination pointer
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut digest = CRC_ALGO.digest();
|
let mut digest = CRC_ALGO.digest();
|
||||||
digest.update(&first_four_bytes);
|
digest.update(&first_four_bytes);
|
||||||
digest.update(bootloader_data);
|
digest.update(bootloader_data);
|
||||||
@ -173,17 +166,22 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
||||||
let crc_exp = unsafe { *(BOOTLOADER_CRC_ADDR as *const u32) };
|
let crc_exp = unsafe { (BOOTLOADER_CRC_ADDR as *const u32).read_unaligned().to_be() };
|
||||||
wdt.feed();
|
wdt.feed();
|
||||||
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic
|
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic
|
||||||
// because the address of the bootloader is 0x0, so the NULL check fails and the functions
|
// because the address of the bootloader is 0x0, so the NULL check fails and the functions
|
||||||
// panics.
|
// panics.
|
||||||
let crc_calc = CRC_ALGO.checksum(unsafe {
|
let mut first_four_bytes: [u8; 4] = [0; 4];
|
||||||
|
read_four_bytes_at_addr_zero(&mut first_four_bytes);
|
||||||
|
let mut digest = CRC_ALGO.digest();
|
||||||
|
digest.update(&first_four_bytes);
|
||||||
|
digest.update(unsafe {
|
||||||
&*core::ptr::slice_from_raw_parts(
|
&*core::ptr::slice_from_raw_parts(
|
||||||
BOOTLOADER_START_ADDR as *const u8,
|
(BOOTLOADER_START_ADDR + 4) as *const u8,
|
||||||
(BOOTLOADER_END_ADDR - BOOTLOADER_START_ADDR - 4) as usize,
|
(BOOTLOADER_END_ADDR - BOOTLOADER_START_ADDR - 8) as usize,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
let crc_calc = digest.finalize();
|
||||||
wdt.feed();
|
wdt.feed();
|
||||||
if crc_exp == 0x0000 || crc_exp == 0xffff {
|
if crc_exp == 0x0000 || crc_exp == 0xffff {
|
||||||
if DEBUG_PRINTOUTS {
|
if DEBUG_PRINTOUTS {
|
||||||
@ -191,18 +189,33 @@ fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
|||||||
}
|
}
|
||||||
// Blank CRC, write it to NVM.
|
// Blank CRC, write it to NVM.
|
||||||
nvm.write_data(BOOTLOADER_CRC_ADDR, &crc_calc.to_be_bytes());
|
nvm.write_data(BOOTLOADER_CRC_ADDR, &crc_calc.to_be_bytes());
|
||||||
// The Vorago bootloader resets here. I am not sure why this is done, just continue with
|
// The Vorago bootloader resets here. I am not sure why this is done but I think it is
|
||||||
// the regular boot process..
|
// necessary because somehow the boot will not work if we just continue as usual.
|
||||||
|
// cortex_m::peripheral::SCB::sys_reset();
|
||||||
} else if crc_exp != crc_calc {
|
} else if crc_exp != crc_calc {
|
||||||
// Bootloader is corrupted. Try to run App A.
|
// Bootloader is corrupted. Try to run App A.
|
||||||
if DEBUG_PRINTOUTS {
|
if DEBUG_PRINTOUTS {
|
||||||
rprintln!("bootloader CRC corrupt. booting image A immediately");
|
rprintln!(
|
||||||
|
"bootloader CRC corrupt, read {} and expected {}. booting image A immediately",
|
||||||
|
crc_calc,
|
||||||
|
crc_exp
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// TODO: Shift out minimal CCSDS frame to notify about bootloader corruption.
|
// TODO: Shift out minimal CCSDS frame to notify about bootloader corruption.
|
||||||
boot_app(AppSel::A, cp);
|
boot_app(AppSel::A, cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_four_bytes_at_addr_zero(buf: &mut [u8; 4]) {
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"ldr r0, [{0}]", // Load 4 bytes from src into r0 register
|
||||||
|
"str r0, [{1}]", // Store r0 register into first_four_bytes
|
||||||
|
in(reg) BOOTLOADER_START_ADDR as *const u8, // Input: src pointer (0x0)
|
||||||
|
in(reg) buf as *mut [u8; 4], // Input: destination pointer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
fn check_app_crc(app_sel: AppSel, wdt: &OptWdt) -> bool {
|
fn check_app_crc(app_sel: AppSel, wdt: &OptWdt) -> bool {
|
||||||
if DEBUG_PRINTOUTS {
|
if DEBUG_PRINTOUTS {
|
||||||
rprintln!("Checking image {:?}", app_sel);
|
rprintln!("Checking image {:?}", app_sel);
|
||||||
@ -220,8 +233,13 @@ fn check_app_given_addr(
|
|||||||
image_size_addr: u32,
|
image_size_addr: u32,
|
||||||
wdt: &OptWdt,
|
wdt: &OptWdt,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let crc_exp = unsafe { *(crc_addr as *const u32) };
|
let crc_exp = unsafe { (crc_addr as *const u32).read_unaligned().to_be() };
|
||||||
let image_size = unsafe { *(image_size_addr as *const u32) };
|
let image_size = unsafe { (image_size_addr as *const u32).read_unaligned().to_be() };
|
||||||
|
// Sanity check.
|
||||||
|
if image_size > APP_A_END_ADDR - APP_A_START_ADDR - 8 {
|
||||||
|
rprintln!("detected invalid app size {}", image_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
wdt.feed();
|
wdt.feed();
|
||||||
let crc_calc = CRC_ALGO.checksum(unsafe {
|
let crc_calc = CRC_ALGO.checksum(unsafe {
|
||||||
core::slice::from_raw_parts(start_addr as *const u8, image_size as usize)
|
core::slice::from_raw_parts(start_addr as *const u8, image_size as usize)
|
||||||
@ -234,6 +252,9 @@ fn check_app_given_addr(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn boot_app(app_sel: AppSel, cp: &cortex_m::Peripherals) -> ! {
|
fn boot_app(app_sel: AppSel, cp: &cortex_m::Peripherals) -> ! {
|
||||||
|
if DEBUG_PRINTOUTS {
|
||||||
|
rprintln!("booting app {:?}", app_sel);
|
||||||
|
}
|
||||||
let clkgen = unsafe { pac::Clkgen::steal() };
|
let clkgen = unsafe { pac::Clkgen::steal() };
|
||||||
clkgen
|
clkgen
|
||||||
.ctrl0()
|
.ctrl0()
|
||||||
|
@ -5,6 +5,7 @@ import struct
|
|||||||
import logging
|
import logging
|
||||||
import argparse
|
import argparse
|
||||||
import time
|
import time
|
||||||
|
import enum
|
||||||
from tmtccmd.com.serial_base import SerialCfg
|
from tmtccmd.com.serial_base import SerialCfg
|
||||||
from tmtccmd.com.serial_cobs import SerialCobsComIF
|
from tmtccmd.com.serial_cobs import SerialCobsComIF
|
||||||
from tmtccmd.com.ser_utils import prompt_com_port
|
from tmtccmd.com.ser_utils import prompt_com_port
|
||||||
@ -34,9 +35,17 @@ APP_IMG_SZ = 0x1E000
|
|||||||
CHUNK_SIZE = 896
|
CHUNK_SIZE = 896
|
||||||
|
|
||||||
MEMORY_SERVICE = 6
|
MEMORY_SERVICE = 6
|
||||||
|
ACTION_SERVICE = 8
|
||||||
|
|
||||||
RAW_MEMORY_WRITE_SUBSERVICE = 2
|
RAW_MEMORY_WRITE_SUBSERVICE = 2
|
||||||
BOOT_NVM_MEMORY_ID = 1
|
BOOT_NVM_MEMORY_ID = 1
|
||||||
|
|
||||||
|
|
||||||
|
class ActionId(enum.IntEnum):
|
||||||
|
CORRUPT_APP_A = 128
|
||||||
|
CORRUPT_APP_B = 129
|
||||||
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -57,11 +66,12 @@ def main() -> int:
|
|||||||
prog="image-loader", description="Python VA416XX Image Loader Application"
|
prog="image-loader", description="Python VA416XX Image Loader Application"
|
||||||
)
|
)
|
||||||
parser.add_argument("-p", "--ping", action="store_true", help="Send ping command")
|
parser.add_argument("-p", "--ping", action="store_true", help="Send ping command")
|
||||||
|
parser.add_argument("-c", "--corrupt", action="store_true", help="Corrupt a target")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-f",
|
"-t",
|
||||||
"--flash",
|
"--target",
|
||||||
choices=["bl", "a", "b"],
|
choices=["bl", "a", "b"],
|
||||||
help="Flash target (Bootloader or slot A or B)",
|
help="Target (Bootloader or slot A or B)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"path", nargs="?", default=None, help="Path to the App to flash"
|
"path", nargs="?", default=None, help="Path to the App to flash"
|
||||||
@ -84,7 +94,8 @@ def main() -> int:
|
|||||||
com_if = SerialCobsComIF(serial_cfg)
|
com_if = SerialCobsComIF(serial_cfg)
|
||||||
com_if.open()
|
com_if.open()
|
||||||
file_path = None
|
file_path = None
|
||||||
if args.flash:
|
if args.target:
|
||||||
|
if not args.corrupt:
|
||||||
if not args.path:
|
if not args.path:
|
||||||
_LOGGER.error("App Path needs to be specified for the flash process")
|
_LOGGER.error("App Path needs to be specified for the flash process")
|
||||||
return -1
|
return -1
|
||||||
@ -92,11 +103,31 @@ def main() -> int:
|
|||||||
if not file_path.exists():
|
if not file_path.exists():
|
||||||
_LOGGER.error("File does not exist")
|
_LOGGER.error("File does not exist")
|
||||||
return -1
|
return -1
|
||||||
ping_tc = PusTc(apid=0x00, service=PusService.S17_TEST, subservice=1)
|
|
||||||
if args.ping:
|
if args.ping:
|
||||||
_LOGGER.info("Sending ping command")
|
_LOGGER.info("Sending ping command")
|
||||||
|
ping_tc = PusTc(apid=0x00, service=PusService.S17_TEST, subservice=1)
|
||||||
com_if.send(ping_tc.pack())
|
com_if.send(ping_tc.pack())
|
||||||
if args.flash:
|
if args.corrupt:
|
||||||
|
if not args.target:
|
||||||
|
_LOGGER.error("target for corruption command required")
|
||||||
|
return -1
|
||||||
|
if args.target == "bl":
|
||||||
|
_LOGGER.error("can not corrupt bootloader")
|
||||||
|
if args.target == "a":
|
||||||
|
packet = PusTc(
|
||||||
|
apid=0,
|
||||||
|
service=ACTION_SERVICE,
|
||||||
|
subservice=ActionId.CORRUPT_APP_A,
|
||||||
|
)
|
||||||
|
com_if.send(packet.pack())
|
||||||
|
if args.target == "b":
|
||||||
|
packet = PusTc(
|
||||||
|
apid=0,
|
||||||
|
service=ACTION_SERVICE,
|
||||||
|
subservice=ActionId.CORRUPT_APP_B,
|
||||||
|
)
|
||||||
|
com_if.send(packet.pack())
|
||||||
|
else:
|
||||||
assert file_path is not None
|
assert file_path is not None
|
||||||
loadable_segments = []
|
loadable_segments = []
|
||||||
_LOGGER.info("Parsing ELF file for loadable sections")
|
_LOGGER.info("Parsing ELF file for loadable sections")
|
||||||
@ -110,19 +141,19 @@ def main() -> int:
|
|||||||
# Basic validity checks of the base addresses.
|
# Basic validity checks of the base addresses.
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
if (
|
if (
|
||||||
args.flash == "bl"
|
args.target == "bl"
|
||||||
and segment.header.p_paddr != BOOTLOADER_START_ADDR
|
and segment.header.p_paddr != BOOTLOADER_START_ADDR
|
||||||
):
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
|
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
|
||||||
f"bootloader, expected {BOOTLOADER_START_ADDR}"
|
f"bootloader, expected {BOOTLOADER_START_ADDR}"
|
||||||
)
|
)
|
||||||
if args.flash == "a" and segment.header.p_paddr != APP_A_START_ADDR:
|
if args.target == "a" and segment.header.p_paddr != APP_A_START_ADDR:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
|
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
|
||||||
f"App A, expected {APP_A_START_ADDR}"
|
f"App A, expected {APP_A_START_ADDR}"
|
||||||
)
|
)
|
||||||
if args.flash == "b" and segment.header.p_paddr != APP_B_START_ADDR:
|
if args.target == "b" and segment.header.p_paddr != APP_B_START_ADDR:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
|
f"detected possibly invalid start address {segment.header.p_paddr:#08x} for "
|
||||||
f"App B, expected {APP_B_START_ADDR}"
|
f"App B, expected {APP_B_START_ADDR}"
|
||||||
@ -150,11 +181,11 @@ def main() -> int:
|
|||||||
)
|
)
|
||||||
total_size += segment.header.p_filesz
|
total_size += segment.header.p_filesz
|
||||||
context_str = None
|
context_str = None
|
||||||
if args.flash == "bl":
|
if args.target == "bl":
|
||||||
context_str = "Bootloader"
|
context_str = "Bootloader"
|
||||||
elif args.flash == "a":
|
elif args.target == "a":
|
||||||
context_str = "App Slot A"
|
context_str = "App Slot A"
|
||||||
elif args.flash == "b":
|
elif args.target == "b":
|
||||||
context_str = "App Slot B"
|
context_str = "App Slot B"
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
f"Flashing {context_str} with image {file_path} (size {total_size})"
|
f"Flashing {context_str} with image {file_path} (size {total_size})"
|
||||||
@ -181,7 +212,7 @@ def main() -> int:
|
|||||||
current_addr += next_chunk_size
|
current_addr += next_chunk_size
|
||||||
pos_in_segment += next_chunk_size
|
pos_in_segment += next_chunk_size
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
if args.flash == "bl":
|
if args.target == "bl":
|
||||||
_LOGGER.info("Blanking the bootloader checksum")
|
_LOGGER.info("Blanking the bootloader checksum")
|
||||||
# Blank the checksum. For the bootloader, the bootloader will calculate the
|
# Blank the checksum. For the bootloader, the bootloader will calculate the
|
||||||
# checksum itself on the initial run.
|
# checksum itself on the initial run.
|
||||||
@ -192,10 +223,10 @@ def main() -> int:
|
|||||||
else:
|
else:
|
||||||
crc_addr = None
|
crc_addr = None
|
||||||
size_addr = None
|
size_addr = None
|
||||||
if args.flash == "a":
|
if args.target == "a":
|
||||||
crc_addr = APP_A_CRC_ADDR
|
crc_addr = APP_A_CRC_ADDR
|
||||||
size_addr = APP_A_SIZE_ADDR
|
size_addr = APP_A_SIZE_ADDR
|
||||||
elif args.flash == "b":
|
elif args.target == "b":
|
||||||
crc_addr = APP_B_CRC_ADDR
|
crc_addr = APP_B_CRC_ADDR
|
||||||
size_addr = APP_B_SIZE_ADDR
|
size_addr = APP_B_SIZE_ADDR
|
||||||
assert crc_addr is not None
|
assert crc_addr is not None
|
||||||
|
@ -33,6 +33,10 @@ const COBS_RX_DEBUGGING: bool = false;
|
|||||||
|
|
||||||
const BOOT_NVM_MEMORY_ID: u8 = 1;
|
const BOOT_NVM_MEMORY_ID: u8 = 1;
|
||||||
|
|
||||||
|
pub enum ActionId {
|
||||||
|
CorruptImageA = 128,
|
||||||
|
CorruptImageB = 129,
|
||||||
|
}
|
||||||
pub trait WdtInterface {
|
pub trait WdtInterface {
|
||||||
fn feed(&self);
|
fn feed(&self);
|
||||||
}
|
}
|
||||||
@ -49,6 +53,11 @@ impl WdtInterface for OptWdt {
|
|||||||
|
|
||||||
static CLOCKS: OnceCell<Clocks> = OnceCell::new();
|
static CLOCKS: OnceCell<Clocks> = OnceCell::new();
|
||||||
|
|
||||||
|
pub const APP_A_START_ADDR: u32 = 0x4000;
|
||||||
|
pub const APP_A_END_ADDR: u32 = 0x22000;
|
||||||
|
pub const APP_B_START_ADDR: u32 = 0x22000;
|
||||||
|
pub const APP_B_END_ADDR: u32 = 0x40000;
|
||||||
|
|
||||||
#[rtic::app(device = pac, dispatchers = [U1, U2, U3])]
|
#[rtic::app(device = pac, dispatchers = [U1, U2, U3])]
|
||||||
mod app {
|
mod app {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -303,6 +312,31 @@ mod app {
|
|||||||
cx.shared.decode_buffer_busy.lock(|busy| *busy = false);
|
cx.shared.decode_buffer_busy.lock(|busy| *busy = false);
|
||||||
match PusTcReader::new(cx.local.read_buf) {
|
match PusTcReader::new(cx.local.read_buf) {
|
||||||
Ok((pus_tc, _)) => {
|
Ok((pus_tc, _)) => {
|
||||||
|
if pus_tc.service() == PusServiceId::Action as u8 {
|
||||||
|
let mut corrupt_image = |base_addr: u32| {
|
||||||
|
// Safety: We only use this for NVM handling and we only do NVM
|
||||||
|
// handling here.
|
||||||
|
let mut sys_cfg = unsafe { pac::Sysconfig::steal() };
|
||||||
|
let nvm = Nvm::new(
|
||||||
|
&mut sys_cfg,
|
||||||
|
cx.local.rom_spi.take().unwrap(),
|
||||||
|
CLOCKS.get().as_ref().unwrap(),
|
||||||
|
);
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
nvm.read_data(base_addr + 32, &mut buf);
|
||||||
|
buf[0] += 1;
|
||||||
|
nvm.write_data(base_addr + 32, &buf);
|
||||||
|
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
|
||||||
|
};
|
||||||
|
if pus_tc.subservice() == ActionId::CorruptImageA as u8 {
|
||||||
|
rprintln!("corrupting App Image A");
|
||||||
|
corrupt_image(APP_A_START_ADDR);
|
||||||
|
}
|
||||||
|
if pus_tc.subservice() == ActionId::CorruptImageB as u8 {
|
||||||
|
rprintln!("corrupting App Image B");
|
||||||
|
corrupt_image(APP_B_START_ADDR);
|
||||||
|
}
|
||||||
|
}
|
||||||
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
|
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
|
||||||
log::info!(target: "TC Handler", "received ping TC");
|
log::info!(target: "TC Handler", "received ping TC");
|
||||||
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
|
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user