From ac015d147387ee902a5e4c49f4b575f6cfdb0e07 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 12 Jul 2024 10:44:41 +0200 Subject: [PATCH] continue flash loader --- flashloader/image-loader.py | 91 ++++++++++++++++++++++++++++++++++-- flashloader/requirements.txt | 1 + scripts/memory_app_a.x | 24 ++++++++++ scripts/memory_app_b.x | 24 ++++++++++ 4 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 scripts/memory_app_a.x create mode 100644 scripts/memory_app_b.x diff --git a/flashloader/image-loader.py b/flashloader/image-loader.py index 66029a0..29c6a59 100755 --- a/flashloader/image-loader.py +++ b/flashloader/image-loader.py @@ -1,14 +1,19 @@ #!/usr/bin/env python3 +from dataclasses import dataclass from spacepackets.ecss.defs import PusService import toml +import struct import logging import argparse +from typing import List import time from tmtccmd.com.serial_base import SerialCfg from tmtccmd.com.serial_cobs import SerialCobsComIF from tmtccmd.com.ser_utils import prompt_com_port from spacepackets.ecss.tc import PusTc from pathlib import Path +import dataclasses +from elftools.elf.elffile import ELFFile BAUD_RATE = 115200 @@ -27,10 +32,24 @@ APP_B_SIZE_ADDR = 0x3FFF8 APP_B_CRC_ADDR = 0x3FFFC APP_IMG_SZ = 0x1E000 +CHUNK_SIZE = 896 + +MEMORY_SERVICE = 6 +RAW_MEMORY_WRITE_SUBSERVICE = 2 +BOOT_NVM_MEMORY_ID = 1 + _LOGGER = logging.getLogger(__name__) -def main(): +@dataclasses.dataclass +class LoadableSegment: + name: str + offset: int + size: int + data: bytes + + +def main() -> int: print("Python VA416XX Image Loader Application") logging.basicConfig( format="[%(asctime)s] [%(levelname)s] %(message)s", level=logging.DEBUG @@ -65,13 +84,78 @@ def main(): ) com_if = SerialCobsComIF(serial_cfg) com_if.open() - if args.flash and not args.path: - _LOGGER.error("App Path needs to be specified for the flash process") + file_path = None + if args.flash: + if not args.path: + _LOGGER.error("App Path needs to be specified for the flash process") + return -1 + file_path = Path(args.path) + if not file_path.exists(): + _LOGGER.error("File does not exist") + return -1 ping_tc = PusTc(apid=0x00, service=PusService.S17_TEST, subservice=1) if args.ping: _LOGGER.info("Sending ping command") com_if.send(ping_tc.pack()) if args.flash: + assert file_path is not None + loadable_segments = [] + _LOGGER.info("Parsing ELF file for loadable sections") + with open(file_path, "rb") as app_file: + elf_file = ELFFile(app_file) + + for segment in elf_file.iter_segments("PT_LOAD"): + if segment.header.p_filesz == 0: + continue + name = None + for section in elf_file.iter_sections(): + if ( + section.header.sh_offset == segment.header.p_offset + and section.header.sh_size > 0 + ): + name = section.name + if name is None: + _LOGGER.warning("no fitting section found for segment") + continue + # print(f"Segment Addr: {segment.header.p_paddr}") + # print(f"Segment Offset: {segment.header.p_offset}") + # print(f"Segment Filesize: {segment.header.p_filesz}") + loadable_segments.append( + LoadableSegment( + name=name, + offset=segment.header.p_paddr, + size=segment.header.p_filesz, + data=segment.data(), + ) + ) + for idx, segment in enumerate(loadable_segments): + _LOGGER.info( + f"Loadable section {idx} {segment.name} with offset {segment.offset} and size {segment.size}" + ) + for segment in loadable_segments: + current_addr = segment.offset + while current_addr < segment.offset + segment.size: + next_chunk_size = segment.offset + segment.size - current_addr + if next_chunk_size > CHUNK_SIZE: + next_chunk_size = CHUNK_SIZE + app_data = bytearray() + app_data.append(BOOT_NVM_MEMORY_ID) + # N parameter is always 1 here. + app_data.append(1) + app_data.extend(struct.pack("!I", current_addr)) + app_data.extend(struct.pack("!I", next_chunk_size)) + app_data.extend( + segment.data[current_addr : current_addr + next_chunk_size] + ) + current_addr += next_chunk_size + next_packet = PusTc( + apid=0, + service=MEMORY_SERVICE, + subservice=RAW_MEMORY_WRITE_SUBSERVICE, + app_data=app_data, + ) + com_if.send(next_packet.pack()) + time.sleep(0.5) while True: data_available = com_if.data_available(0.4) if data_available: @@ -80,6 +164,7 @@ def main(): print("Received replies: {}", reply) break com_if.close() + return 0 if __name__ == "__main__": diff --git a/flashloader/requirements.txt b/flashloader/requirements.txt index e25be91..fe0cdf5 100644 --- a/flashloader/requirements.txt +++ b/flashloader/requirements.txt @@ -1,3 +1,4 @@ spacepackets == 0.24 tmtccmd == 8.0.1 toml == 0.10 +pyelftools == 0.31 diff --git a/scripts/memory_app_a.x b/scripts/memory_app_a.x new file mode 100644 index 0000000..9d8c317 --- /dev/null +++ b/scripts/memory_app_a.x @@ -0,0 +1,24 @@ +/* Special linker script for application slot A with an offset at address 0x4000 */ +MEMORY +{ + FLASH : ORIGIN = 0x00004000, LENGTH = 256K + /* RAM is a mandatory region. This RAM refers to the SRAM_0 */ + RAM : ORIGIN = 0x1FFF8000, LENGTH = 32K + SRAM_1 : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */ +/* SRAM_0 can be used for all busses: Instruction, Data and System */ +/* SRAM_1 only supports the system bus */ +_stack_start = ORIGIN(RAM) + LENGTH(RAM); + +/* Define sections for placing symbols into the extra memory regions above. */ +/* This makes them accessible from code. */ +SECTIONS { + .sram1 (NOLOAD) : ALIGN(8) { + *(.sram1 .sram1.*); + . = ALIGN(4); + } > SRAM_1 +}; diff --git a/scripts/memory_app_b.x b/scripts/memory_app_b.x new file mode 100644 index 0000000..4a9dcb0 --- /dev/null +++ b/scripts/memory_app_b.x @@ -0,0 +1,24 @@ +/* Special linker script for application slot B with an offset at address 0x22000 */ +MEMORY +{ + FLASH : ORIGIN = 0x00022000, LENGTH = 256K + /* RAM is a mandatory region. This RAM refers to the SRAM_0 */ + RAM : ORIGIN = 0x1FFF8000, LENGTH = 32K + SRAM_1 : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */ +/* SRAM_0 can be used for all busses: Instruction, Data and System */ +/* SRAM_1 only supports the system bus */ +_stack_start = ORIGIN(RAM) + LENGTH(RAM); + +/* Define sections for placing symbols into the extra memory regions above. */ +/* This makes them accessible from code. */ +SECTIONS { + .sram1 (NOLOAD) : ALIGN(8) { + *(.sram1 .sram1.*); + . = ALIGN(4); + } > SRAM_1 +};