Quest for software verification

Since more than a week now, I'm after a task which was originally
estimated to take a few days.  An experienced colleague pushed to
migrate the boot procedure from a reasonable setup based on
FIT[1] to an arrangement where the kernel and the device tree is
loaded from the root filesystem.

The reason behind this migration has to do with the convenience
of implementing the cryptographic verification of the software in
one step: only the root filesystem is verified, and this implies
the verification of kernel and device tree in it contained.

The system I'm trying to modify is using SquashFS for the root
filesystem.  SquashFS is supported by U-Boot, so it should have
been as simple as requesting the loading of a certain filesystem
path (e.g. "/boot/vmlinuz") to a designated memory area, and boot
from there.

As it turns out, the SquashFS support of U-Boot is unfortunately
quite limited.  It requires SquashFS to be constructed on the top
of the UBI[2] support.

I was suggested to fall back on using JFFS2, which should be
supported in read-only mode from U-Boot.  The unfortunate side
effect is that our root filesystem will no longer be inherently
read-only (SquashFS is read-only by design, JFFS2 can be mounted
read-write under Linux), and of course that we should migrate the
new (old) filesystem.

Ironically, the easy part was figuring out how to do so with
Yocto!  The IMAGE_FSTYPES[3] setting allows to list what formats
the build system should use for the root filesystem.

I copied the image on the designated flash partition, and tried
to load it from U-Boot.  It took me a while to find out about
'mtdids'+'mtdparts'[4], what should be the correct values for
them, and what build-time configurations to enable in order to
get the desired code activated.  All those build-time
conditionals, and the practice of silently skipping disabled
code, can make U-Boot very difficult to work with.

I reached the point where the values of 'mtdids' and 'mtdparts'
determined a promising long delay between the 'fsls' command and
a remarkably empty list of files.  Actually nothing really
prevents those pesky 'mtdids' and 'mtdparts' variables to be
still wrong.

I tried to verify if the filesystem is usable, first by
successfully mounting it on my Linux workstation, and then by
mounting it, still on Linux but on the target board.
The second step was not trivial but eventually successful.

It was not trivial because the flash erase block matters on
JFFS2, and the kernel has a configuration called
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS, active by default, which will
force our flash to use 4 KiB erase blocks.  Such configuration
does not work well with our NOR flash.

I finally managed to mount the new root filesystem under Linux
(on target) by disabled such configuration, and configured Yocto
to use 64KiB erase blocks for the image (the right knob for the
purpose is JFFS2_ERASEBLOCK[5]).  A build-time configuration with
the same name, meaning, and default value also exists under
U-Boot, so I had to disable it consistently.

Despite my efforts, I still can not access the filesystem from
U-Boot!  I can boot the kernel with the JFFS2 image as root
filesystem, which means that the problem is not in the image, nor
in the kernel.  I can also correctly load the filesystem in
memory from U-Boot (acting on the 'sf' commands, which result in
a memory transfer via the SPI bus to the main memory).  I know
the image is correct because I can dump the loaded bytes with the
'md' command, and it checks out.

The thing is, unfortunately, that the JFFS2 driver will expect
the data to be available from a memory mapped flash, and I'm not
sure if the flash can even be accessed this way.  I will now
delve into the data-sheet of our target ASIC.

Even if this battle is not yet over, it feels good to annotate
the progress made so far.  I'm no longer sure that this was a
good idea, but at least I've gained some precious know-how. :)


Additional reads:

https://en.wikipedia.org/wiki/Serial_Peripheral_Interface
https://www.embedded.com/flash-101-the-nor-flash-electrical-interface/


References

[1] Flattened Image Trees
   https://www.elinux.org/Fit-boot

[2] Unsorted Block Images
   https://en.wikipedia.org/wiki/UBIFS#UBI

[3] IMAGE_FSTYPES
   https://docs.yoctoproject.org/ref-manual/variables.html#term-IMAGE_FSTYPES

[4] mtdparts
   https://github.com/u-boot/u-boot/blob/9e804638bfe2693a908abf066ff66c251572afa7/cmd/mtdparts.c#L26

[5] JFFS2_ERASEBLOCK
   https://docs.yoctoproject.org/ref-manual/variables.html#term-IMAGE_FSTYPES