Skip to content

Scatter/gather ELF files according to segments paddr #562

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

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

danielinux
Copy link
Member

This PR adds the option ELF_SCATTERED, which allows for an ELF file to be stored in different partitions on the target flash memory.
Before starting, wolfboot will check all the scattered fragments for integreity, by calculating the digest to match the one in the header.

Also added: simulator config files to test. Still unable to stage the scattered image in the simulator, but the current wolfboot.elf application shows the working scattered store/gathered digest procedures before do_boot().

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 9 out of 16 changed files in this pull request and generated 1 comment.

Files not reviewed (7)
  • CMakeLists.txt: Language not supported
  • arch.mk: Language not supported
  • config/examples/sim-elf-scattered.config: Language not supported
  • config/examples/sim32-elf-scattered.config: Language not supported
  • options.mk: Language not supported
  • test-app/Makefile: Language not supported
  • tools/elf-parser/Makefile: Language not supported

Spotted by copilot

Co-authored-by: Copilot <[email protected]>
@danielinux danielinux requested a review from Copilot April 8, 2025 07:12
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 9 out of 16 changed files in this pull request and generated no comments.

Files not reviewed (7)
  • CMakeLists.txt: Language not supported
  • arch.mk: Language not supported
  • config/examples/sim-elf-scattered.config: Language not supported
  • config/examples/sim32-elf-scattered.config: Language not supported
  • options.mk: Language not supported
  • test-app/Makefile: Language not supported
  • tools/elf-parser/Makefile: Language not supported
Comments suppressed due to low confidence (2)

include/wolfboot/wolfboot.h:313

  • The constant IMG_STATE_ELF_LOADING is defined here and again later. Please remove the duplicate definition to avoid potential conflicts.
/* ELF loading state - only valid on boot partition so doesn't conflict with

include/wolfboot/wolfboot.h:325

  • Duplicate definition of IMG_STATE_ELF_LOADING; consider removing one instance to make the code cleaner.
#define IMG_STATE_ELF_LOADING 0x70

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff so far. In addition to my review comments, did you have integration into the signing keytool that wasn't committed? You must have in order to be able to generate images right?

@danielinux
Copy link
Member Author

Great comments, I'll work on these ASAP.

Regarding your question about sign, sign has not been modified, as there is no change in the header. The elf is 'dynamically rehashed' at runtime using the stored elf header + the scattered fragments, and eventually calculates the same digest as the full image. In fact this is also used to detect if there is no elf image at all in the fragments locations, or if the images have been only partially stored before a power failure event.

@danielinux danielinux assigned danielinux and unassigned bigbrett Apr 9, 2025
- ARCH_FLASH_OFFSET only used in simulation (dynamic 'base' address)
- Fixed the DISABLE_BACKUP case
- renamed define to WOLFBOOT_ELF_SCATTERED
- Added missing `test-app/app_sim_scattered.c`
- Added missing `test-app/sim_scattered.ld`
- Fixed comments at the end of define blocks for consistency
- Removed unused constants as indicated
@danielinux danielinux requested a review from bigbrett April 11, 2025 14:27
@danielinux danielinux assigned bigbrett and unassigned danielinux Apr 11, 2025
@danielinux
Copy link
Member Author

@bigbrett all the remarks have been addressed. I'm available to discuss further on optimizing the update time. I think it's a valid point but I'd like to prioritize design simplicity in this case. I'm open to better approaches if we find one.

I've also added a simple build-verify test case using the simulator since your last review.

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great work Daniele. I wish we had a better way to actually verify the boot, but given the dynamic library shenanigans we would need to wrangle to get this running in the simulator, I think seeing the hash verify is good enough for me to get this in.

I think we should ideally figure out a way to test the actual boot in CI at some point, whether it be on renode or on QEMU. Theoretically we should be able to load any of the elfs curently used for testing on renode via this mechanism, and they should still boot. Edit: JK no we can't, since it is linked to run from the boot partition

@bigbrett bigbrett assigned dgarske and unassigned dgarske and bigbrett Apr 11, 2025
Copy link
Contributor

@dgarske dgarske left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests out here! Nice work!

@dgarske dgarske assigned danielinux and unassigned dgarske Apr 11, 2025
@bigbrett bigbrett self-requested a review April 11, 2025 19:37
Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielinux I just spotted something. This new feature breaks wolfBoot_erase_bootloader(), which assumes the bootloader occupies all memory between ARCH_FLASH_OFFSET and WOLFBOOT_PARTITION_BOOT_ADDRESS. This is no longer an appropriate assumption when scattered elf loading is turned on, as this could be perfectly valid memory to load to. Not sure if we have a good way currently to get just the size of wolfBoot itself....would need to think about this. Thoughts? Maybe we need to introduce an additional "scatter region" or maybe just a dedicated partition region for wolfBoot itself?

Edit: At least internally, this seems to only be used by self-update. I guess that would mean the self update could potentially destroy the "active image" e.g. scattered elf, however I believe that would just cause wolfBoot to re-scatter the elf in the boot partition on the next boot?

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also found a few lingering printfs

src/elf.c Outdated
paddr = (unsigned long)ph[i].paddr;
offset = (unsigned long)ph[i].offset;
filesz = (unsigned long)ph[i].file_size;
printf("Writing section at address %lx offset %lx\n", paddr, offset);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
printf("Writing section at address %lx offset %lx\n", paddr, offset);
wolfBoot_printf("Writing section at address %lx offset %lx\n", paddr, offset);

src/elf.c Outdated
paddr = (unsigned long)ph[i].paddr;
offset = (unsigned long)ph[i].offset;
filesz = (unsigned long)ph[i].file_size;
printf("Writing section at address %lx offset %lx\n", paddr, offset);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
printf("Writing section at address %lx offset %lx\n", paddr, offset);
wolfBoot_printf("Writing section at address %lx offset %lx\n", paddr, offset);

@billphipps
Copy link
Contributor

Couple of questions:

  1. I think I'm missing some code: elf_check_image_scattered? This is where I assumed there would be a loop of hashes against each of the individual sections. It was unclear to me if each section would have a stored hash or if a single hash would be updated and only finalized at the end.
  2. Is there a reason that scattered support isn't default within the ELF support? Seems like an elf file that has a single segment should measure the same when scattered support is enabled.
  3. I think the simulator should be able test this. I'll take a quick swing at pinning memory maps and see if that can make static linkage work.

@danielinux
Copy link
Member Author

@danielinux I just spotted something. This new feature breaks wolfBoot_erase_bootloader(),

It would make sense to me to make the two features incompatible

@danielinux
Copy link
Member Author

Couple of questions:

1. I think I'm missing some code: elf_check_image_scattered?  This is where I assumed there would be a loop of hashes against each of the individual sections.  It was unclear to me if each section would have a stored hash or if a single hash would be updated and only finalized at the end.

Yes. The latter. Basically it assumes that a copy of the complete image is still available, to retrieve the image header + elf header, then the digest calculation is performed on the chunks to ensure that they correspond to the selected stored image.

2. Is there a reason that scattered support isn't default within the ELF support?  Seems like an elf file that has a single segment should measure the same when scattered support is enabled.

This is a good point. Elf support is different on other platforms though, and base address for loading may vary for relocatable images. It could be an improvement for those cases where the elf is loaded (manually) into RAM after verification.

3. I think the simulator should be able test this.  I'll take a quick swing at pinning memory maps and see if that can make static linkage work.

Thanks, that would be great. hal/sim.c uses exec with an actual executable in the 'normal' use case. I think it's mostly a matter of crafting the right linker script for the test-application, but it was becoming too much time-consuming

- Removed stray printfs from elf.c
- Updated test-configs.yml to include build tests for config files
@bigbrett
Copy link
Contributor

@danielinux @dgarske I'm going to be making some changes to this functionality as I integrate and test on TC3xx (it wont quite work written as-is at the moment). That said, since this is working in Sim, should we go ahead an merge and I will add additional changes in a subsequent PR? Or would you prefer we close this PR and I'll add additional commits on top of @danielinux 's work and create a new PR once working on TC3xx? Slight preference to just merging the work as-is, since it isn't in use by anyone yet, but up to you

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielinux I found a few other issues the more I look at this....do you want to fix/work on these or hand it over to me? If the latter, thoughts on closing the PR vs merging work as-is even if it doesn't work on AURIX?

const unsigned char *image;
int is_elf32;
unsigned short entry_count;
unsigned short entry_size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused but set variable (compiler warning)

wolfBoot_hash_t ctx;
if (wolfBoot_open_image(&boot, part) < 0)
return -1;
p = get_img_hdr(&boot);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this wont work if the image is in external flash, as get_img_hdr() returns a pointer to the RAM buffer if the partition is external. Later we do things like elf_h = p + IMAGE_HEADER_SIZE which will break if p is the RAM buffer.

Comment on lines +227 to +240
if (ext_flash) {
ext_flash_unlock();
ext_flash_erase(paddr + BASE_OFF, filesz);
ext_flash_write(paddr + BASE_OFF, image + offset, filesz);
ext_flash_lock();
}
else
#endif
{
hal_flash_unlock();
hal_flash_erase(paddr + BASE_OFF, filesz);
hal_flash_write(paddr + BASE_OFF, image + offset, filesz);
hal_flash_lock();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes that the HAL implementation of {ext,hal}_flash_write() can handle reading from flash as well, which I'm not sure all of our HALs do (at least TC3xx does not). Normally when ext flash is enabled we do this via wolfBoot_copy_sector() which copies between flash and swap through a RAM buffer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants