Skip to content

pkg/xipfs: add XIPFS as vfs module#21197

Closed
GGuche-2XS-Univ-Lille wants to merge 20 commits intoRIOT-OS:2025.01-branchfrom
GGuche-2XS-Univ-Lille:2024.10-xipfs-pull-request
Closed

pkg/xipfs: add XIPFS as vfs module#21197
GGuche-2XS-Univ-Lille wants to merge 20 commits intoRIOT-OS:2025.01-branchfrom
GGuche-2XS-Univ-Lille:2024.10-xipfs-pull-request

Conversation

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor

@GGuche-2XS-Univ-Lille GGuche-2XS-Univ-Lille commented Feb 7, 2025

Contribution description

This PR aims at integrating the eXecutable In-Place FileSystem into RIOT operating system.

XIPFS implements regular filesystem storage manipulation capabilities, but also allows
to run code almost directly from the FLASH memory.
Just a little bit of RAM is used to relocate what's needed for the execution (data and bss).

It is provided like any other vfs module, and can be called through the defined vfs API.
Nonetheless, it can also be called directly through its own API (xipfs_* functions).

No matter the actual file size is, XIPFS deals with Flash pages granularity of 4KiB.
That means that with two files with different sizes less than 4 Kib, vfs df will display
8 Kib used.

Due to XIPFS design, directories and files are stored in a similar way.
Echoing the remark above, that also means that an empty directory will cost 4 Kib to the
Flash memory.

This implementation has been developed and tested on a Decawave DW1001 board (Quorvo).
However, the Flash memory handling relies on available periph/flashpage.h, and should thus
run on any platform supporting addressable Flash memory.

Testing procedure

Manual and automated tests are provided.
Both are great resources to showcase XIPFS api and abilities.
Manual tests also demonstrate the integration of XIPFS as a VFS submodule.

To run the automated tests :

  • Please open a terminal with a pyterm, listening to the device.
  • Open another one and move to the examples\xipfs-tests directory.
  • Now, please enter the following in this shell :
    BOARD=dwm1001 QUIET=0 make flash
  • The first terminal should display something along the lines of following :
    > 2025-02-06 14:04:16,367 # main(): This is RIOT! (Version: 2025.01)
    2025-02-06 14:04:16,373 # Tests started, awaiting for normal termination or assertion...
    2025-02-06 14:04:57,197 # Tests finished.
    This can take a little while, around 40-ish seconds for 130 tests.

To run the manual tests :

  • Please open a terminal with a pyterm, listening to the device.

  • Open another one and move to the examples\xipfs directory.

  • Now, please enter the following in this shell :

    BOARD=dwm1001 QUIET=0 make flash
  • Come back to the pyterm terminal.
    The first time XIPFS is run onto the board the resulting display should be similar to :

    2025-02-06 11:23:04,736 # main(): This is RIOT! (Version: 2025.01)
    2025-02-06 11:23:04,743 # vfs_mount: "/dev/nvme0p0": file system has not been initialized or is corrupted
    2025-02-06 11:23:04,747 # vfs_format: "/dev/nvme0p0": try initializing it
    2025-02-06 11:23:04,766 # vfs_format: "/dev/nvme0p0": OK
    2025-02-06 11:23:04,772 # vfs_mount: "/dev/nvme0p0": OK
    2025-02-06 11:23:04,784 # vfs_mount: "/dev/nvme0p1": file system has not been initialized or is corrupted
    2025-02-06 11:23:04,789 # vfs_format: "/dev/nvme0p1": try initializing it
    2025-02-06 11:23:04,815 # vfs_format: "/dev/nvme0p1": OK
    2025-02-06 11:23:04,823 # vfs_mount: "/dev/nvme0p1": OK

    , or to

    2025-02-06 14:06:05,692 # main(): This is RIOT! (Version: 2025.01)
    2025-02-06 14:06:05,696 # vfs_mount: "/dev/nvme0p0": OK
    2025-02-06 14:06:05,703 # vfs_mount: "/dev/nvme0p1": OK

    when XIPFS has already be run and has initialized the two mount points of the filesystem.

  • Now, please enter help

    2025-02-06 14:06:35,765 # help
    2025-02-06 14:06:35,768 # Command              Description
    2025-02-06 14:06:35,771 # ---------------------------------------
    2025-02-06 14:06:35,775 # exec                 Execute Hello World
    2025-02-06 14:06:35,780 # pm                   interact with layered PM subsystem
    2025-02-06 14:06:35,785 # ps                   Prints information about running threads.
    2025-02-06 14:06:35,790 # version              Prints current RIOT_VERSION
    2025-02-06 14:06:35,793 # reboot               Reboot the node
    2025-02-06 14:06:35,797 # vfs                  virtual file system operations
    2025-02-06 14:06:35,800 # ls                   list files
    2025-02-06 14:06:35,805 # create_executable    Create an XIPFS executable file
    2025-02-06 14:06:35,809 # execute              Execute an XIPFS file
  • exec is a more a demonstration than a regular shell command.
    However it will :

    • dump an executable file named hello-world.bin, when none is stored onto /dev/nvme0p0;
    • run hello-world.bin then.
    • Display :
    > exec
    2025-02-06 11:23:59,085 # exec
    2025-02-06 11:23:59,682 # Hello World!
  • execute is the XIPFS execution shell command to run an executable file.

    > execute /dev/nvme0p0/hello-world.bin Lorem ipsum dolor sit amet
    2025-02-07 09:41:02,366 # execute /dev/nvme0p0/hello-world.bin Lorem ipsum dolor sit amet
    2025-02-07 09:41:02,367 # Hello World!
    2025-02-07 09:41:02,368 # Lorem
    2025-02-07 09:41:02,369 # ipsum
    2025-02-07 09:41:02,369 # dolor
    2025-02-07 09:41:02,369 # sit
    2025-02-07 09:41:02,370 # amet
  • create_executable is the shell command to create an executable_file.
    Though create_executable takes a name and a bytesize, please remember that it will contain no code until filled by a write command.

     > create_executable /dev/nvme0p0/titi_exec 256
     2025-02-07 10:07:54,970 # create_executable /dev/nvme0p0/titi_exec 256
     > ls
     > ls /dev/nvme0p0
     2025-02-07 10:10:23,591 # ls /dev/nvme0p0
     2025-02-07 10:10:23,593 # hello-world.bin       896 B
     2025-02-07 10:10:23,601 # ploki//
     2025-02-07 10:10:23,601 # titi_exec
     2025-02-07 10:10:23,602 # total 2 files

@github-actions github-actions bot added Area: network Area: Networking Area: doc Area: Documentation Area: build system Area: Build system Area: pkg Area: External package ports Area: CoAP Area: Constrained Application Protocol implementations Area: sys Area: System Area: examples Area: Example Applications labels Feb 7, 2025
@kaspar030
Copy link
Copy Markdown
Contributor

Interesting!

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Feb 7, 2025

I think something with your rebase went wrong, you have two commits in the PR that are part of the master branch from benpicco and maribu.

Damien Amara and others added 5 commits February 7, 2025 14:25
@github-actions github-actions bot removed Area: network Area: Networking Area: CoAP Area: Constrained Application Protocol implementations labels Feb 7, 2025
@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

I think something with your rebase went wrong, you have two commits in the PR that are part of the master branch from benpicco and maribu.

Yeah I should have checked twice, I tried a a git rebase -i and dropped the two commits you cited.

Is it ok with you ?

@mguetschow mguetschow changed the title XIPFS Pull request pkg/xipfs: add XIPFS as vfs module Feb 7, 2025
@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Feb 7, 2025

Yes, it looks good now.

Unfortunately I don't have a dwm1001 board for testing this. I'm not a maintainer, so this is not an official review.

I took a quick look at the code and I think it would be possible to eliminate the need for dedicated board header files in your xipfs package.
The contants XIPFS_NVM_NUMOF, XIPFS_NVM_WRITE_BLOCK_ALIGNMENT, XIPFS_NVM_WRITE_BLOCK_SIZE and XIPFS_NVM_PAGE_SIZE can be read from the CPU configuration (for example: https://github.com/RIOT-OS/RIOT/blob/master/cpu/nrf52/include/cpu_conf.h#L89-L113 )

And the rest of the constants seem to be pretty much the same for all platforms.


There is also a bug that it won't allow you to build for other boards than the dwm1001 and refuses to download the package. However once you compiled it for the dwm1001 once, it has downloaded the package and throws errors when you try to compile it for other boards (in my case an nRF52840DK from Nordic).

Before compiling for the dwm1001
~/xipfs-riot/RIOT/examples/xipfs$ BOARD=nrf52840dk make
Building application "xipfs" for "nrf52840dk" with CPU "nrf52".

"make" -C /home/cbuec/xipfs-riot/RIOT/pkg/cmsis/ 
"make" -C /home/cbuec/xipfs-riot/RIOT/pkg/xipfs/ 
/home/cbuec/xipfs-riot/RIOT/build/pkg/xipfs/configure.sh --board=nrf52840dk
Usage: /home/cbuec/xipfs-riot/RIOT/build/pkg/xipfs/configure.sh <MANDATORY ARGUMENT>

  MANDATORY ARGUMENT:

    --board=<name> Specify the name of the board to build xipfs for. Supported
                   boards can be found in the "boards" directory.
make[1]: *** [Makefile:15: /home/cbuec/xipfs-riot/RIOT/build/pkg/xipfs/toolchain.mk] Error 1
make: *** [/home/cbuec/xipfs-riot/RIOT/examples/xipfs/../../Makefile.include:811: pkg-build] Error 2
After compiling for the dwm1001
~/xipfs-riot/RIOT/examples/xipfs$ BOARD=nrf52840dk make
Building application "xipfs" for "nrf52840dk" with CPU "nrf52".

"make" -C /home/cbuec/xipfs-riot/RIOT/pkg/cmsis/ 
"make" -C /home/cbuec/xipfs-riot/RIOT/pkg/xipfs/ 
"make" -C /home/cbuec/xipfs-riot/RIOT/build/pkg/xipfs
make[2]: Nothing to be done for 'all'.
cc1: error: /home/cbuec/xipfs-riot/RIOT/build/pkg/xipfs/boards/nrf52840dk: No such file or directory [-Werror=missing-include-dirs]
In file included from /home/cbuec/xipfs-riot/RIOT/examples/xipfs/main.c:25:
/home/cbuec/xipfs-riot/RIOT/sys/include/fs/xipfs_fs.h:27:10: fatal error: xipfs_config.h: No such file or directory
   27 | #include "xipfs_config.h"
      |          ^~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
compilation terminated.
make[1]: *** [/home/cbuec/xipfs-riot/RIOT/Makefile.base:149: /home/cbuec/xipfs-riot/RIOT/examples/xipfs/bin/nrf52840dk/application_xipfs/main.o] Error 1
make: *** [/home/cbuec/xipfs-riot/RIOT/examples/xipfs/../../Makefile.include:747: application_xipfs.module] Error 2

If the package only supports certain boards, it would be best to add a whitelist for supported boards: https://doc.riot-os.org/creating-an-application.html However I am not sure if that is intended to work for packages as well, I guess a maintainer could answer that.

Adding BOARD_WHITELIST = dwm1001 to the Makefile.dep of your xipfs packages, the following error will be thrown, which is more like the expected behavior.

~/xipfs-riot/RIOT/examples/xipfs$ BOARD=nrf52840dk make
The selected BOARD=nrf52840dk is not whitelisted: dwm1001
/home/cbuec/xipfs-riot/RIOT/examples/xipfs/../../Makefile.include:1006: *** You can let the build continue on expected errors by setting CONTINUE_ON_EXPECTED_ERRORS=1 to the command line.  Stop.

But in general I think it would be better to add general support for all boards (that support flashpage).

@aabadie
Copy link
Copy Markdown
Contributor

aabadie commented Feb 7, 2025

Unfortunately I don't have a dwm1001 board for testing this. I'm not a maintainer, so this is not an official review.

There are some dwm1001 boards deployed in the IoT-LAB testbed (in Lille and Toulouse sites). You can:

  1. start an experiment (assuming that you already created an account, configured your SSH access and installed the IoT-LAB cli-tools):
iotlab-experiment submit -d 20 -l 1,archi=dwm1001:dw1000+site=lille
iotlab-experiment wait --timeout 30 --cancel-on-timeout
  1. build, flash and access the terminal using the RIOT build system:
make BOARD=dwm1001 IOTLAB_NODE=auto -C examples/default flash term

(I just tried and it still works!)

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

For starters, thanks to @crasbe and @aabadie for their feeback; they are much appreciated.

We were, and still are, quite newbies into the RIOT community.
There is surely room for improvement in different departments on our side; the build system coming first in line.
We would gladly accept guidance and advices.


@crasbe :
We are not willing to constrain XIPFS to a sole platform, nor to "bind" XIPFS too closely to RIOT.
That being said, RIOT OS is great and dwm1001 is the only board we have to test XIPFS before releasing it to the wild.

I am giving a try at the generic code path that you propose, ie relying to FLASH definitions in cpu_conf.h.
If I am not mistaking, the "INCLUDES" variable contains a path to this file such as -I/somewhere/RIOT/cpu/nrf52/include, which should be enough at compilation time to find the FLASH defines.
If I understood correctly, it should work also for other platforms.

But now, I am facing an error from the build system where my CPU type is not found anymore :
error: #error "The CPU_MODEL of your board is currently not supported".

I've searched into RIOT only to find a definition in generated /somewhere/RIOT/examples/xipfs.bin/dwm1001/riotbuild/riotbuild.h, which is not reliable to my eyes.

Am I missing something ?
Or is there another way to access to proper defines which would let the build system sets the appropriate CPU model too ?

Thanks for reading.

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Feb 11, 2025

I think you don't have to make any significant changes to the original project to be compatible with the RIOT definitions.
There are different possibilities like checking for some environment variables that are only set by the RIOT build system in your makefiles and conditionally skipping the include of the boards-specific xipfs_config.h and instead using one with the RIOT definitions.


I can't reproduce the issue you're describing. The error comes from the cpu/nrf52/include/cpu_conf.h file, that is correct:

#error "The CPU_MODEL of your board is currently not supported"

What's odd is that the CPU_MODEL is defined for the DWM1001 board (otherwise pretty much nothing would work):

CPU_MODEL = nrf52832xxaa

To reproduce the issue I included cpu.h in your examples/xipfs/main.c file and added a printf("Flashpage Size: %d\n", FLASHPAGE_SIZE); in the execution_handler function. It compiles without any issues, so the compiler can find the macro.

If you include cpu.h, you should have access to FLASHPAGE_SIZE etc from the nrf52-specific cpu_conf.h. The RIOT build system will do everything for you to include the right one for your CPU based on what's set in the board definition.

You could try to run make clean and delete the /somewhere/RIOT/examples/xipfs/bin folder. Sometimes there's something from previous build runs that causes issues, especially when working with packages.

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

@crasbe
Sorry for the latency.

I scratched my head a bit to get how the build system works, while keeping at the same time the riot integration code as a template for other ones.

I don't know if changes will be ok for reviewers, but now when building xipfs for RIOT, xipfs relies on cpu.h flashpage defines as you mentioned.
The old build path has been kept as a reminder and template for ports in other environments/os, if they occur; hoping it won't bother people.

I compiled both examples/xipfs and examples/xipfs-tests with this compilation path, and it worked as expected.
I run both of them without any problem too.

Please, could you give it a try for your board (nRF52840DK) and let me know if the compilation works for you now ?

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Feb 19, 2025

I gave this a test with an nRF52DK devboard and the tests run successfully:

Then I tested the example and it did work for small executables (10 bytes), but resulted in a stack overflow for larger executables (123 bytes).

In this log, the file test already existed and therefore the error happened. I guess that error=-2 is expected for an empty executeable?

main(): This is RIOT! (Version: 2025.01)
vfs_mount: "/dev/nvme0p0": OK
vfs_mount: "/dev/nvme0p1": OK
> help
Command              Description
---------------------------------------
pm                   interact with layered PM subsystem
ps                   Prints information about running threads.
version              Prints current RIOT_VERSION
reboot               Reboot the node
vfs                  virtual file system operations
ls                   list files
create_executable    Create an XIPFS executable file
execute              Execute an XIPFS file
> create_executable /dev/nvme0p0/test 10
Failed to create '/dev/nvme0p0/test' as an XIPFS executable file.
> create_executable /dev/nvme0p0/test2 10
> execute /dev/nvme0p0/test1
Failed to execute '/dev/nvme0p0/test1', error=-2
> vfs r /dev/nvme0p0/test 10
-- EOF --
> 
main(): This is RIOT! (Version: 2025.01)
vfs_mount: "/dev/nvme0p0": OK
vfs_mount: "/dev/nvme0p1": OK
> help
Command              Description
---------------------------------------
pm                   interact with layered PM subsystem
ps                   Prints information about running threads.
version              Prints current RIOT_VERSION
reboot               Reboot the node
vfs                  virtual file system operations
ls                   list files
create_executable    Create an XIPFS executable file
execute              Execute an XIPFS file
> create_executable /dev/nvme0p0/test 123
> ls /dev/nvme0p0
test
total 1 files
> execute /dev/nvme0p0/test

Context before hardfault:
   r0: 0x20001e5c
   r1: 0x0000b1a4
   r2: 0x2000226c
   r3: 0x20001e58
  r12: 0x00000000
   lr: 0x00004127
   pc: 0x0000b1a4
  psr: 0x21030200

FSR/FAR:
 CFSR: 0x00010000
 HFSR: 0x40000000
 DFSR: 0x00000000
 AFSR: 0x00000000
Misc
EXC_RET: 0xfffffffd
Active thread: 1 "main"
Attempting to reconstruct state for debugging...
In GDB:
  set $pc=0xb1a4
  frame 0
  bt

ISR stack overflowed by at least 16 bytes.
*** RIOT kernel panic:
HARD FAULT HANDLER

<9>pid | name                 | state    Q | pri | stack  ( used) ( free) | base addr  | current     
<9>  - | isr_stack            | -        - |   - |    512 (  492) (   20) | 0x20000000 | 0x2000220c
<9>  1 | main                 | running  Q |   7 |   1536 ( 1096) (  440) | 0x200013d8 | 0x2000195c 
<9>    | SUM                  |            |     |   2048 ( 1588) (  460)

*** halted.

Inside isr -13

What's a bit odd is that vfs ls only shows one file, even though multiple files exist. In this case, the file test and test2 exist and XIPFS throws an error when I try to create another test2 file. The test1 doesn't exist yet, so it is successfully created, but only test shows up in the ls command.

> create_executable /dev/nvme0p0/test2 10
Failed to create '/dev/nvme0p0/test2' as an XIPFS executable file.
> create_executable /dev/nvme0p0/test1 10
> vfs ls /dev/nvme0p0
test
total 1 files
> vfs r /dev/nvme0p0/test1 10
Error opening file "/dev/nvme0p0/test1": -ENOENT
> 

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

@crasbe :
Thanks for the try and feedback 👍 .
I had little time this week to work on the PR; but it should be better on Monday.

I gave this a test with an nRF52DK devboard and the tests run successfully

That's good news, and we are quite happy to have XiPFS running on other platforms than DWM1001.


About the example.
"Naming is difficult" but I guess that some points would have benefited from more explanations.

create_executable creates an entry within the filesystem and marks it as executable.
At the same time, flash memory space is reserved but no other operation is performed.
And that's it, no actual code nor startup sequence or whatever is added to the entry.

execute command only checks if such a file exists and is marked as executable within XiPFS, then simply branches/jumps into the first bytes of the file.
If the file has not been filled with actual code, we are landing in undefined behaviors territory.
Then, one can expect crashes or anything, depending on what lies in the first bytes of the file.

This is why we provided the hello-world.fae binary blob in the example for DWM1001 reviewers , in order to have something to test/play with. The second reason is that XiPFS is a filesystem, and does not bring a transport layer to upload files on boards. The third one is that the PR is already quite big.

So to sum it up, as the example shows and tries to explain (too briefly), to have a viable executable file within XiPFS, please follows these steps :

  • create a file with executable flag.
  • fill it with actual compiled code in an appropriate file format, here XiPFS-Format.
    This is where the actual startup sequence and relocation happen.
  • call execute on it with appropriate args (at least the executable filename should be passed along).

About the ls command.
I have reproduced your use case, and I think you have found a bug in the display code.
Although I am not familiar with that part, I built quickly a version where this function is removed, and got then what we would expect :

> vfs ls /dev/nvme0p0
2025-02-21 10:35:39,308 # vfs ls /dev/nvme0p0
2025-02-21 10:35:39,308 # test
2025-02-21 10:35:39,309 # test2
2025-02-21 10:35:39,310 # test3//
2025-02-21 10:35:39,311 # total 2 files

2 files + 1 directory are shown here.

I need to confirm my guess to prevent from unwanted side effects, with other teammates on vacation this week.

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Feb 21, 2025

Perhaps you can add some of the remarks to the README in the examples folder. Especially the explanation how to create a .bin/.fae file should (also) be part of the README.

I was totally expecting the execute function not to work or to crash, I was just playing around, testing and writing down the observations I made in the process :)


Some remarks about the documentation:

Currently this PR introduces two new Doxygen errors, which shouldn't be too hard to address.

~/riot-xip/RIOT$ make doc |& grep -i xipfs
/home/cbuec/riot-xip/RIOT/sys/include/fs/xipfs_fs.h:77: warning: Member xipfs_extended_driver_execv(const char *full_path, char *const argv[]) (function) of group sys_xipfs is not documented.
/home/cbuec/riot-xip/RIOT/sys/include/vfs.h:230: warning: Member XIPFS_VFS_FILE_BUFFER_SIZE (macro definition) of group sys_vfs is not documented.

Furthermore I would propose adding some documentation to the headers, because the documentation that will be accessible from the website is not that verbose. This is your free space for "advertising" your XIPFS.
You should at least add references to the examples, because the README.md files are not included into the official Doxygen documentation. They are just present in Github.

Screenshot 2025-02-21 141722
Screenshot 2025-02-21 141735

void xipfs_nvm_write(void *target_addr, const void *data, size_t len)
{
flashpage_write(target_addr, data, len);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How do you determine the start sector of your filesystem / how do you avoid overwriting the firmware?

We have the AUX slot mechanism to reserve a portion of the internal flash for use by the application, maybe this also works for you?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @benpicco ,

Thanks for the question.

Historically, XiPFS has been started circa 2022/2023 and mimics what we have observed from other filesystems in RIOT at that time.
We are using the flashpage mechanism/API as depicted in the quoted code snippet.

This XiPFS macro initializes the mount point with respect to FLASH_WRITABLE_INIT.

To the best of our understanding, we were thinking that it would prevent from silent firmware corruption and provide safe flash allocation.

Now, we are not against trying to behave and make XiPFS support AUX slot mechanism.
However, after a quick reading, wrapping our head around it is not that obvious.
Could we discuss about it in RIOT's forum please ?

Either way, we'll try to get back to you asap.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@benpicco
First of all, sorry for the delay; partly because I was on sick leave for a few days.

  • About the AUX mechanism :
    it would have been a lot of changes to make XIPFS follow the way other filesystems in RIOT support AUX mechanism; something we could not afford.
    However, we decided to provide a way to construct a vfs_xipfs_mount_t from a mtd_flashpage_t, and thus enabling XIPFS to be compatible with the AUX slot mechanism.
    This feature is showcased in 'tests/pkg/xipfs`.
    Tests are run once from flash_writable section and a second time from mtd_flash_aux_slot.

  • We find out also that there was a memory fault when flushing an internal page buffer on the last page of the flash memory.
    Long story short, we fixed the problem and we are now using aligned memory with flashpage memory API.
    As a bonus, tests now runs 4 times faster than the previous version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@benpicco Do you agree with XIPFS changes about the AUX mechanism ?

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Apr 25, 2025

@GGuche-2XS-Univ-Lille what's the current status?
I now have a DWM1001 module and could give this another test.

@crasbe crasbe added Type: new feature The issue requests / The PR implemements a new feature for RIOT CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Apr 25, 2025
@riot-ci
Copy link
Copy Markdown

riot-ci commented Apr 25, 2025

Murdock results

FAILED

3f4751d fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! pkg/xipfs : RIOT integration of xipfs

Success Failures Total Runtime
1147 0 9376 02m:38s

Artifacts

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

@GGuche-2XS-Univ-Lille what's the current status? I now have a DWM1001 module and could give this another test.

@crasbe Please feel free to give a try at this PR. The embedded executable should work.

We were busy to make the file format evolve.
Long story short, currently, we are encountering some problems with the new CRT0, our startup sequence which performs relocations and manages the bss segment.
Then, for now, we are debugging it and XiPFS Format cannot be used to test XiPFS with your own code.
We are very sorry about that.
Of course, we'll keep you posted when the debugging is finished.

We'll be looking as well to the CI failure, which seems to concern msp430 and 16 bits platforms at first sight.

As a side note, is it allowed to kindly ping other reviewers to confirm that changes we made are ok with their remarks ?
For example, benpicco's remark about the AUX mechanism and our take on the suggestion...

Thank you for your time !

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Apr 28, 2025

Okay, I'll take a look at it again soon.

About the CI failure on MSP430: this is caused by this line:
https://github.com/2xs/xipfs/blob/cd45f5d60bab584c47f603470fb4768688704d3c/include/xipfs.h#L61

On the MSP430, the values for #defines are not automatically unsigned long (aka 32-bit), therefore the number does not fit.
However, you can tell the compiler to choose an unsigned long by adding an UL suffix. That should solve the build failure.

-#define XIPFS_MAGIC (0xf9d3b6cb)
+#define XIPFS_MAGIC (0xf9d3b6cbUL)

Of course you can ping maintainers, as long as it is not daily 🤣

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

About commit 8adcfe3, two fixes were done :

  • Now we have a pair of mutexes per mount point instead of a sole static one. It allows to use XiPFS in a fae file that has been launched by xipfs_execv, otherwise a deadlock would occur.
  • A bug in xipfs_new_file has been fixed, that led to corrupt files under some circumstances.

This commit is synchronized with modifications done on file format, and thus XiPFS Format can be used again to generate your own fae file.

@crasbe I have two questions if you don't mind.

  1. Now that 2025-04 is out, I guess that I should track this branch instead of 2025-01, shouldn't I ?
    I've read CONTRIBUTING.md and PR related documentation, but I've failed to find something.
    Should I go for a set-upstream + git fetch/rebase, or is there another way ?

  2. The PR is quite old now, and we would like to not make it older, or let's say much older.
    From your perspective, is there any blocker we could act on to make the review process a bit faster ?
    We know that the PR is quite big, and we cannot change that alas.
    But maybe there are other painpoints we could modify to ease PR reviewers contributions ?

@kfessel
Copy link
Copy Markdown
Contributor

kfessel commented May 27, 2025

  • Please have a look at the Murdock build results

  • If possible try building for msp430 locally / docker build

image

Copy link
Copy Markdown
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

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

There are some compilation errors because the code assumes a 32 bit platform to run on. See inline for the compilation fixes.

But even with that, it will still not link due to:

/opt/riot-toolchain/msp430-elf/10.1.0-18/bin/../lib/gcc/msp430-elf/10.1.0/../../../../msp430-elf/bin/ld: /data/riotbuild/riotbase/tests/pkg/xipfs/bin/z1/xipfs.a: error adding symbols: file in wrong format

Comment on lines +79 to +81
vfs_mount_t vfs_mp; /**< VFS mount point */
unsigned magic; /**< xipfs magic number */
const char *mount_path; /**< mount point path */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
vfs_mount_t vfs_mp; /**< VFS mount point */
unsigned magic; /**< xipfs magic number */
const char *mount_path; /**< mount point path */
vfs_mount_t vfs_mp; /**< VFS mount point */
uint32_t magic; /**< xipfs magic number */
const char *mount_path; /**< mount point path */

This will fix this particular issue:

In file included from /data/riotbuild/riotbase/sys/include/fs/xipfs_fs.h:29,
                 from /data/riotbuild/riotbase/tests/pkg/xipfs/main.c:23:
/data/riotbuild/build/pkg/xipfs/include/xipfs.h:63:21: error: conversion from 'long unsigned int' to 'unsigned int' changes value from '4191401675' to '46795' [-Werror=overflow]
   63 | #define XIPFS_MAGIC (0xf9d3b6cbUL)
      |                     ^
/data/riotbuild/riotbase/sys/include/fs/xipfs_fs.h:59:18: note: in expansion of macro 'XIPFS_MAGIC'
   59 |         .magic = XIPFS_MAGIC,                         \
      |                  ^~~~~~~~~~~

XIPFS_ASSERT(ret == 0);

/* test */
ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0, 0xffffffff);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0, 0xffffffff);
ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0, -1);

fixes this error:

/data/riotbuild/riotbase/tests/pkg/xipfs/main.c: In function 'test_xipfs_lseek_einval_whence':
/data/riotbuild/riotbase/tests/pkg/xipfs/main.c:573:48: error: overflow in conversion from 'long unsigned int' to 'int' changes value from '4294967295' to '-1' [-Werror=overflow]
  573 |     ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0, 0xffffffff);
      |                                                ^~~~~~~~~~

Comment on lines +595 to +596
ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0xffffffff,
SEEK_SET);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0xffffffff,
SEEK_SET);
ret = xipfs_open(xipfs_nvme0p0, &desc, "/toto",
-1, 0);

fixes this error:

/data/riotbuild/riotbase/tests/pkg/xipfs/main.c: In function 'test_xipfs_lseek_einval_whence':
/data/riotbuild/riotbase/tests/pkg/xipfs/main.c:573:48: error: overflow in conversion from 'long unsigned int' to 'int' changes value from '4294967295' to '-1' [-Werror=overflow]
  573 |     ret = xipfs_lseek(xipfs_nvme0p0, &desc, 0, 0xffffffff);
      |                                                ^~~~~~~~~~

@miri64
Copy link
Copy Markdown
Member

miri64 commented May 28, 2025

  1. Now that 2025-04 is out, I guess that I should track this branch instead of 2025-01, shouldn't I ?
    I've read CONTRIBUTING.md and PR related documentation, but I've failed to find something.
    Should I go for a set-upstream + git fetch/rebase, or is there another way ?

For development, we would recommend in general to track the master branch. And yes, if there is a merge conflict, please rebase. However, at the moment there is none, so we are fine (Murdock, our CI, rebases before each build).

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

GGuche-2XS-Univ-Lille commented May 28, 2025

@kfessel , @maribu , @miri64 : thanks a lot for your comments !

To tell you the truth, we just realized the following obvious fact : there is 0 chance for XiPFS to compile on a non ARM cpu for now, because of these assembly lines in the library.
It somehow got forgotten when we took the decision to address as many platforms as we could.

So to sum it up, for now, XiPFS needs two requirements :

  1. A 32 bits ARM CPU,
  2. Addressable flash memory.

The latter is already handled by XiPFS package Makefile.dep.
For the first requirement, I guess that this line should filter correctly the different boards :

FEATURES_REQUIRED += arch_32bit arch_arm

Is that correct ?

Thank you for your time and remarks.

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

I am currently fixing the faulty CI checks in this PR, and most of them are straightforward to solve.

There is this commit-msg check that is failing : Error: Commit message is longer than 72 characters: "fixup! static-tests : Fixed missing doc, invalid USEMODULE, example README.md"

Please correct me if I'm wrong, but is it wanted that fixup messages length are checked ?

If I read correctly man git-rebase, matching is performed according to message content, meaning that I can't modify the faulty message with git rebase -i.
Excerpt : When the commit log message begins with "squash! ..." or "fixup! ..." or "amend! ...", and there is already a commit in the todo list that matches the same ..., automatically modify the todo list of rebase -i etc...

Moreover, on autosquash, those messages will disappear in the matching commit, rendering corresponding checks obsolete.

Please, do you have any recommendations in such a case ?

@kfessel
Copy link
Copy Markdown
Contributor

kfessel commented Jun 2, 2025

no need to care for commit title length error due to "fixup" as you said it will be gone anyway.

and you are right we shall probably filter them from message length check (as there is already a warning in place to not accidentally merge fixups.

the other tests are more relevant atm Murdock and Static tests

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

I am puzzled by this compilation failure.

Probably something we do or don't do on our side; please let us know.

It seems to be a cross-compilation instance with llvm toolchain for the samr21-xpro, guessed from the build title and the -target arm-none-eabi option that is to be found in makefiles/toolchain/llvm.inc.mk, but the selected compiler is arm-none-eabi-gcc, despite the compiler setting in llvm toolchain makefile for CC.

Excerpt :
"arm-none-eabi-gcc -Wall -Wextra -Werror -ffreestanding -mthumb -Os etc... -DCPU_CORE_CORTEX_M0PLUS -target arm-none-eabi -Wno-atomic-alignment etc... -c src/buffer.c -o src/buffer.o"

Do you have any ideas about what's going on, please ?

PS : I'll be out of office from June 9 to June 23 2025, included, but I will reply as soon as I'm back.

@GGuche-2XS-Univ-Lille
Copy link
Copy Markdown
Contributor Author

Dear RIOT reviewers (@kfessel, @miri64, @benpicco, @maribu, @mguetschow, @crasbe),

Let's face it, this PR became quite awful.
I was new to your workflow and should have paid even more attention to the contributing guidelines.

Would it be ok with you if I close this PR to open a new clean one ?
I would track properly RIOT's master, this would solve the static tests failure on Docker image repo digest.
I would also collect all the commits within a single one to restart anew and fresh, without loosing all the benefits your reviews provided.

Sorry for the noise, and please let me know if you agree with this proposal.

@crasbe
Copy link
Copy Markdown
Contributor

crasbe commented Jun 26, 2025

Of course you can start with a new PR, no worries :)

Working with git and GitHub can be quite a steep learning curve and unfortunately sometimes a clean start is the only good solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: build system Area: Build system Area: doc Area: Documentation Area: examples Area: Example Applications Area: pkg Area: External package ports Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants