您尚未登录。

楼主 #1 2020-09-16 09:25:10

你是什么傻逼玩意
会员
注册时间: 2020-09-16
已发帖子: 10
积分: 10

为F1C100S的SPI Flash制作SquashFS+JFFS2+OverlayFS的rootfs来增大空间

荔枝派标配的是16MB的W25Q128 SPI Flash,在放入荔枝派官方的uboot 内核 rootfs的情况下,可用空间一般不超过1MB。
其实仔细观察一下还是有很多可以调整的空间的。
SquashFS可以对rootfs进行压缩,但是rootfs会变成只读的。可以使用OverlayFS将只读分区和可写分区合并,这样的rootfs优先使用SquashFS里的数据并且会把更改储存到JFFS2分区里面。只要运行时没有过多修改SquashFS里的数据,那这种方案节省的空间还是很多的。大名鼎鼎的OpenWRT既是采用了这种解决方案从而能在8MB Flash的路由器上运行的。这种方案运行时修改来自SquashFS的文件时,那个文件并不会动,而是会在JFFS2里储存修改后的文件,这样会有一个文件的两个版本,OverlayFS优先使用JFFS2里的版本,但是这样会造成两个版本同时存在,反而浪费空间,但是这也没办法。有得有失嘛。
这个是我的SPI Flash的结构:
Partition    Content        Offset        Size (byte)
mtd0        uboot-bin        0            0x58000 (360448 Byte)
        uboot-env        0x58000        0x8000
mtd1        dtb            0x60000        0x4000  (16kB)
mtd2        kernel        0x64000        0x400000 (4MB)
mtd3        rootfs        0x464000        0x4FC000 (4.98MB)
mtd4        overlay        0x960000        0x500000 (5MB)
相比官方的镜像,多了一个mtd4分区,就是用于储存运行时对rootfs修改的地方。注意这个mtd4的起始地址和大小必须是擦除区块大小的整数倍,不然无法写!我用的W25Q128这个数字是0x10000(64kB)。
首先是降低uboot的空间占用, https://whycan.cn/t_2179.html 里提到了uboot本体只有270kb,我看了下,确实是这样,我的u-boot.bin是268kb。
于是激进一点,把Environment Offset从0x100000调成了0x58000,这样Uboot部分分400kB就可以了,比原版的1MB小太多了。
话说回来Uboot一般也不会在之后加太多东西了,最多变变启动参数什么的,本体大小变化不大,这个应该是安全的。
具体的Uboot配置需要在`make ARCH=arm menuconfig`里修改,一共有三处:
# [ *] Enable boot arguments
   = console=ttyS0,115200 panic=5 rootwait root=/dev/mtdblock3 rw rootfstype=squashfs init=/etc/preinit
# [ *] Enable a default value for bootcmd
   = sf probe 0 50000000; sf read 0x80C00000 0x60000 0x4000; sf read 0x80008000 0x64000 0x400000; bootz 0x80008000 - 0x80C00000
# Environment -> Environment Offset = 0x58000
分别是:
1. 指定Linux的启动参数,要点是rootfstype=squashfs init=/etc/preinit这部分,之后会说。
2. 告诉UBoot如何把dtb和内核zImage从SPI Flash装载到内存里,这部分的SPI Flash地址要和上面的表对应。
3. 修改UBoot环境变量储存区的开始位置,减小空间浪费。
UBoot不需要修改c或者h文件。



然后是修改Linux内核的配置,同样还是`make ARCH=arm menuconfig`:
<*> Overlay filesystem support
[ *] Miscellaneous filesystems  --->
--><*>   Journalling Flash File System v2 (JFFS2) support
--><*>   SquashFS 4.0 - Squashed file system support
Device Drivers:
<*> Memory Technology Device (MTD) support  --->
--><*>   Caching block device access to MTD devices

[ *] SPI support  --->
-->< >   Allwinner A10 SoCs SPI controller
--><*>   Allwinner A31 SPI controller
分别是启用了OverlayFS、JFFS2、SquashFS文件系统的支持,
启动MTD设备的缓存(这样才能用SPI Flash上启动)
然后就是修正原版.config里SPI控制器选错了的问题。
还有需要修改dts文件(arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts):
    flash: w25q128@0 {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "winbond,w25q128", "jedec,spi-nor";
        reg = <0>;
        spi-max-frequency = <50000000>;
        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            partition@0 {
                label = "u-boot";
                reg = <0x000000 0x58000>;
                read-only;
            };

            partition@60000 {
                label = "dtb";
                reg = <0x60000 0x4000>;
                read-only;
            };

            partition@64000 {
                label = "kernel";
                reg = <0x64000 0x400000>;
                read-only;
            };

            partition@464000 {
                label = "rootfs";
                reg = <0x464000 0x4FC000>;
                read-only;
            };

            partition@960000 {
                label = "overlayfs";
                reg = <0x960000 0x500000>;
            };

        };
    };
   
这里面的分区开始位置和大小要和uboot启动参数还有最上面的表对应才行。
到此为止uboot和Linux内核就修改好了。现在可以对u-boot和linux分别使用:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4
然后是编译linux的内核模块:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 INSTALL_MOD_PATH=out modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 INSTALL_MOD_PATH=out modules_install
现在可以开始制作rootfs了。首先是制作SquashFS部分,这部分是基于原版的Rootfs的。
1. 释放原来的rootfs到一个文件夹:
mkdir rootfs_new
cd rootfs_new
tar xvpzf ../rootfs.tar.gz
2. 把新编译的内核模块放进去
3. 创建映射文件夹
mkdir rootfs_new/overlay
mkdir rootfs_new/chroot
mkdir rootfs_new/rom
4. 建立一个启动脚本`rootfs_new/etc/preinit`:
#!/bin/sh

# export PATH="/usr/sbin:/usr/bin:/sbin:/bin"

# mount the new rootfs
mount -t squashfs /dev/mtdblock3 /rom
mount -t jffs2 /dev/mtdblock4 /overlay
mount -n -t overlay overlayfs:/overlay -o lowerdir=/rom,upperdir=/overlay/rw,workdir=/overlay/work /chroot

# mount /dev and /sys for chroot environment
# /dev/pts, /dev/shm, /proc, /tmp and /run will be mounted by inittab from fstab
mount -t sysfs sysfs /sys
mount --rbind /sys /chroot/sys/
mount --rbind /dev /chroot/dev/


exec chroot /chroot /sbin/init
启动参数里的init=/etc/preinit就是指这个脚本。根据Linux文档,init=这个参数会替换原本的/sbin/init被执行。
咱们的preinit首先会挂载只读分区SquashFS和可写分区JFFS2,再在/chroot文件夹中创建overlay,
然后在新的rootfs里挂在/dev和/sys,最后执行chroot并在新的root环境下执行/sbin/init,
回归系统正常的启动程序,只不过是在新的rootfs下。这样之后的程序都不会察觉rootfs发生了变化。使用如下命令打包SquashFS:
mksquashfs rootfs_new/ rootfs_new.img -no-exports -no-xattrs -all-root
最后一步是制作JFFS2的镜像:
mkdir -p overlay/work
mkdir -p overlay/rw
mkfs.jffs2 -s 0x100 -e 0x10000 --pad=0x500000 -o jffs2.img -d overlay/
work文件夹是OverlayFS需要的一个空文件夹,rw是储存增量修改的地方。


烧写入SPI Flash, 注意地址别写错:
# uboot
sudo sunxi-fel -p spiflash-write 0 u-boot/u-boot-sunxi-with-spl.bin
# dtb
sudo sunxi-fel -p spiflash-write 0x60000 linux/arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb
# kernel
sudo sunxi-fel -p spiflash-write 0x64000 linux/arch/arm/boot/zImage
# squashfs
sudo sunxi-fel -p spiflash-write 0x464000 rootfs_new.img
# jffs2
sudo sunxi-fel -p spiflash-write 0x960000 jffs2.img
推荐阅读:
https://gist.github.com/rikka0w0/f56977f81d1228fc503b00ad7b526aa7
https://gist.github.com/rikka0w0/e04eee5fa623b37866ded805c855f287
https://whycan.cn/t_2179_2.html
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn