Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a FLASH resident bootloader #625

Closed
jnewcomb opened this issue Apr 28, 2021 · 5 comments
Closed

Adding a FLASH resident bootloader #625

jnewcomb opened this issue Apr 28, 2021 · 5 comments

Comments

@jnewcomb
Copy link

jnewcomb commented Apr 28, 2021

Hello folks,
I'm trying to implement a FLASH resident bootloader. What are people's thoughts on the best way?
Obviously not my way.. but for completeness, I'll describe my nugatory efforts so far...

I've generated 2 separate modm builds - first call 'bootloader', second called 'app'.
bootloader resides in the first 128K and the 'app' linker file shifts everything up by the same amount.
Both projects work as expected - the bootloader jumps to the application codes reset handler... But, in order to do this, I have to download it separately - bootloader first then application code. Ideally, I want to pull the precompiled bootloader (as a static library?) into the application - and maybe even get it working on the debugger. Need to be combined in the hex file.
To this end I've prepared the app linker file:

MEMORY
{
	BOOT (rx) : ORIGIN =    0x08000000, LENGTH = 128K
	FLASH (rx) : ORIGIN =   0x08020000, LENGTH = 1920K
...
}
...
ENTRY(Reset_Handler)
...
SECTIONS
{
	.vector_bootloader :
	{
		. = ALIGN(4);
		__vector_table_bootloader_start = .;
		KEEP(*(.vector_bootloader))
		/* https://stackoverflow.com/questions/42295298/place-segments-of-external-static-library-to-specific-locations */
		*libbootloader_lib.a:*(.vector_bootloader)
		__bootrom_size = .;
		. = 0x20000;
		__vector_table_bootsection_end = .;
	} >BOOT

	.vector_rom :
	{
		. = ALIGN(4);
		__vector_table_rom_start = .;
		__vector_table_ram_load = .;
		/* Initial stack address, Reset and NMI handler */
		KEEP(*(.vector_rom))
	} >FLASH
...
}

I've pulled across uncommitted updates to CMake from @Jasa - which is quite neat #568
Then added the following to the bootloader MakeFileLists:

## Added by JN create a static library (*.a) for locating in the application code bootloader sector region
add_library(${CMAKE_PROJECT_NAME}_lib STATIC ${APP_SOURCE_FILES})
target_include_directories(${CMAKE_PROJECT_NAME}_lib PUBLIC include)
target_link_libraries(${CMAKE_PROJECT_NAME}_lib
  modm_options
  modm_warnings
  modm)

This generates a bootloader_lib.a
My aim is to pull this into the application. I have added the following to the application MakeFileLists:

target_link_libraries(${CMAKE_PROJECT_NAME}
  modm_options
  modm_warnings
  modm
  "C:/Projects/modm/examples/project/bootloader/build/VisualGDB/Debug/libbootloader_lib.a"
  )

(there are better ways - find_library() etc, but I just want to see it working before the tidy up)

From the *.map file below, obviously, it's not worked.. I've come from IAR hence my appaling use of CMake!
Are there any hints on this to be shared?
Should I make a 3rd CMakeLists and include the other two?
Or - Can anyone share the relevant CMake/linker cut & pastes for a simple FLASH resident bootloader?
Happy to share the working files here once (if!) I manage to crack this.
I am thinking of using srec 'cat' to combine the bin (or elf) files into one - but it just seems hacky to me..? Style-guide: Should I, shouldn't I? Whats the 'modm' way?!

For what it's worth I've included the projects files - (working using VisualGDB and not included *.sln dir)
project_2.zip


Memory Configuration

Name             Origin             Length             Attributes
BOOT             0x08000000         0x00020000         xr
FLASH            0x08020000         0x00060000         xr
CCM              0x10000000         0x00010000         rw
SRAM1            0x20000000         0x0001c000         xrw
SRAM2            0x2001c000         0x00004000         xrw
SRAM3            0x20020000         0x00010000         xrw
BACKUP           0x40024000         0x00001000         xrw
RAM              0x20000000         0x00030000         xrw
*default*        0x00000000         0xffffffff

Linker script and memory map

LOAD CMakeFiles/application.dir/board.cpp.obj
LOAD CMakeFiles/application.dir/main.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/ext/gcc/cabi.c.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/ext/gcc/cxxabi.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/ext/gcc/new_delete.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/architecture/driver/atomic/flag.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/io/iostream.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/io/iostream_printf.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/math/utils/bit_operation.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/math/utils/pc/operator.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/clock/rcc.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/clock/systick_timer.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/assert.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/delay.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/no_heap.c.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/reset_handler.sx.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/startup.c.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/startup_platform.c.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/vectors.c.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/flash/flash.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/gpio/enable.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/uart/uart_3.cpp.obj
LOAD C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/utils/dummy.cpp.obj
LOAD C:/Projects/modm/examples/project/bootloader/build/VisualGDB/Debug/libbootloader_lib.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libstdc++_nano.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libm.a
START GROUP
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/thumb/v7e-m+fp/hard\libgcc.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libg_nano.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a
END GROUP
START GROUP
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/thumb/v7e-m+fp/hard\libgcc.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libnosys.a
END GROUP
START GROUP
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/thumb/v7e-m+fp/hard\libgcc.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a
LOAD c:/sysgcc/arm-eabi-10/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libnosys.a
END GROUP
                0x08020000                __rom_start = ORIGIN (FLASH)
                0x08000000                __bootrom_start__ = ORIGIN (BOOT)
                0x08000000                __bootrom_size__ = LENGTH (BOOT)
                0x08020000                __approm_start__ = ORIGIN (FLASH)
                0x00060000                __approm_size__ = LENGTH (FLASH)
                0x08020000                __rom_start = ORIGIN (FLASH)
                0x00020000                BOOTLOADER_SIZE = 0x20000
                0x00008000                CONFIG_SIZE = 0x8000
                0x00000000                PROCESS_STACK_SIZE = 0x0
                0x00000c00                MAIN_STACK_SIZE = 0xc00
                0x00000c00                TOTAL_STACK_SIZE = (MAIN_STACK_SIZE + PROCESS_STACK_SIZE)

.vector_bootloader
                0x08000000    0x20000
                0x08000000                . = ALIGN (0x4)
                0x08000000                __vector_table_bootloader_start = .
                0x08000000                __vector_table_bootloader_load = .
 *(.vector_bootloader)
 *libbootloader_lib.a:*(.vector_bootloader)
                0x08000000                __vector_table_bootloader_end = .
                0x08000000                __bootrom_size__ = .
                0x00020000                . = 0x20000
 *fill*         0x08000000    0x20000 
                0x08020000                __vector_table_bootsection_end = .
.vector_rom     0x08020000      0x1ac
                0x08020000                . = ALIGN (0x4)
                0x08020000                __vector_table_rom_start = .
                0x08020000                __vector_table_ram_load = .
 *(.vector_rom)
 .vector_rom    0x08020000      0x1ac C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/core/vectors.c.obj
                0x08020000                vectorsRom

.vector_ram     0x20000000        0x0
                0x20000000                __vector_table_ram_start = .
 *(.vector_ram)
                0x20000000                . = ALIGN (0x4)
                0x20000000                __vector_table_ram_end = .

.stack          0x10000000      0xc00
                0x10000000                __stack_start = .
                0x10000c00                . = (. + MAIN_STACK_SIZE)
 *fill*         0x10000000      0xc00 
                0x10000c00                . = ALIGN (0x8)
                0x10000c00                __main_stack_top = .
                0x10000c00                . = (. + PROCESS_STACK_SIZE)
                0x10000c00                . = ALIGN (0x8)
                0x10000c00                __process_stack_top = .
                0x10000c00                __stack_end = .

.fastdata       0x10000c00        0x8 load address 0x080201ac
                0x080201ac                __fastdata_load = LOADADDR (.fastdata)
                0x10000c00                __fastdata_start = .
 *(.fastdata)
 .fastdata      0x10000c00        0x8 C:/Projects/modm/examples/project/application/build/VisualGDB/Debug/modm/CMakeFiles/modm.dir/src/modm/platform/clock/rcc.cpp.obj
                0x10000c00                SystemCoreClock
                0x10000c04                modm::platform::delay_fcpu_MHz
                0x10000c06                modm::platform::delay_ns_per_loop
                0x10000c08                . = ALIGN (0x4)
                0x10000c08                __fastdata_end = .

.heap0          0x10000c08     0xf3f8 load address 0x080201b4
 *(.heap0)
                0x10000c08                . = ALIGN (0x4)
                0x10000c08                __heap0_start = .
                0x10010000                . = (ORIGIN (CCM) + LENGTH (CCM))
 *fill*         0x10000c08     0xf3f8 
                0x10010000                __heap0_end = .

.text           0x080201c0     0x2b7c
 *(.text .text.* .gnu.linkonce.t.*)
 .text._ZN4modm8IODevice5writeEPKc
                0x080201c0       0x3e CMakeFiles/application.dir/board.cpp.obj
                0x080201c0                modm::IODevice::write(char const*)
 .text._ZN4modm8IOStreamC2ERNS_8IODeviceE
                0x080201fe       0x24 CMakeFiles/application.dir/board.cpp.obj
                0x080201fe                modm::IOStream::IOStream(modm::IODevice&)
                0x080201fe                modm::IOStream::IOStream(modm::IODevice&)
 .text._ZN4modm8IOStreamlsERKm



                0x08020222       0x20 CMakeFiles/application.dir/board.cpp.obj
                0x08020222                modm::IOStream::operator<<(unsigned long const&)
 .text._ZN4modm8IOStreamlsEPKc
                0x08020242       0x28 CMakeFiles/application.dir/board.cpp.obj
@jnewcomb jnewcomb changed the title Bootloader support Adding a FLASH resident bootloader Apr 28, 2021
@salkinium
Copy link
Member

salkinium commented Apr 28, 2021

I'm not sure you want to have one big hex/binary file, since the bootloader is probably not 128kB large, so if you want to have one continuous binary, there'll be a lot of zeros in there until the application starts.

You could however call OpenOCD manually and program both ELFs in one go:

openocd -f modm/openocd.cfg -c "program path/to/bootloader.elf verify" -c "program path/to/application.elf verify reset exit"
# or the binaries
openocd -f modm/openocd.cfg -c "program path/to/bootloader.bin verify 0x08000000" -c "program path/to/application.bin verify reset exit 0x08020000"

I'm not sure about debugging both apps at the same time, it would be really neat if you made that work though.
Intuitively you would have to merge the two ELF files incl. debug information perhaps with a Python script using pyelftools.
You may also have to rewrite relative file paths to distinuguish bootloader/main.cpp from application/main.cpp.
Perhaps you could then also just pass that shared ELF file to openocd, and it'll automatically program the two applications for you?

@salkinium
Copy link
Member

Just FYI: there's an option for flash offsets so you don't have to create your own application linkerfile.

@ghost
Copy link

ghost commented Apr 29, 2021

The CMake scripts is not relying on start-group and end-group linker flags, so creating static libraries containing modm itself is dangerous. Unreferenced objects might disappear since "used" attribute is not specified in the source and linker tables is also a problem. (eg. hardware init and assert)

@jnewcomb
Copy link
Author

jnewcomb commented Apr 30, 2021

Thanks for all your advice guys..
In the end.. I created a new sector in the application link script called vector_bootloader and merged boot binary into it.

  add_custom_command(TARGET ${project_name}
    POST_BUILD
	# JN: Although I've done my best to FILL() gaps in the linker script, they still creep in.
	# Seen this in sector .heap0 (NOLOAD), where FLASH seems to be allocated, but not initialised with a value i.e unprogrammed. This
	# can be seen as 'gaps' in the HEX files. Not good for calculating a reliable checksum!!!.. So.. the workaround is this..
	# Force fill 'unallocated' from 0x00 to 0xFF to match 'unprogrammed' FLASH. It's all rather insane if you ask me!
	# All this makes calculating and comparing checksums near impossible. We try to patch this up with OBJCOPY..
	# (This will overwrite the ELF file with a fixed one)
	COMMAND ${CMAKE_OBJCOPY} --gap-fill=0xff  ${project_name}.elf 

	# Here we need to combine the bootloader with the application. vector_bootloader will just get overwritten
	COMMAND ${CMAKE_OBJCOPY} --update-section .vector_bootloader="C:/Projects/modm/examples/project/bootloader/build/VisualGDB/Debug/bootloader.bin" ${project_name}.elf
	
	# Convert ELF file for external programming / debugging
        COMMAND ${CMAKE_OBJCOPY} --output-target=binary ${project_name}.elf ${project_name}.bin
        COMMAND ${CMAKE_OBJCOPY} --output-target=srec --srec-len 0x20 --srec-forceS3  ${project_name}.elf ${project_name}.srec
        COMMAND ${CMAKE_OBJCOPY} --input-target=srec --output-target=ihex ${project_name}.srec ${project_name}.hex
    )	

@salkinium
Copy link
Member

I'm closing this as this solution is not something we can integrate into modm.

@modm-io modm-io locked and limited conversation to collaborators Sep 29, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Development

No branches or pull requests

2 participants