Alpine Linux Porting (一点三?)

今天,我们要来作Alpine Linux的initramfs bootstrapping。
在近代的大型distro中,多半都会善用early stage userspace,去进行比较复杂的rootfs初始化;各家的initramfs风格、打造方式可以差距到非常大,例如Arch Linux的工具是mkinitcpio、Gentoo的则是Dracut、Debian体系则是initramfs-tools

可是虽然风格回异,这些initramfs的基本精神与流程皆是:从/proc/cmdline去拿到kernel boot arguements,然後爬看看有没有initramfs要预处理的option,例如可能是nbd啦、或着initramfs特有的特技,例如Gentoo可以支援livenet这个透过http去拿rootfs的方式;然後处理好rootfs mounting後,便会透过 switch_root 或着 pivot_root的方式去更换root node、然後启动rootfs上的 init system ,例如 systemd 或着 openrc 等等。

然而,这边一样有个鸡蛋问题,那就是这些initramfs的生成,通常是在一个native的环境底下,进行self-bootstrapping的;但是我们现在还没有native的环境可以用,那怎麽办呢?依笔者前年的作法,那便是去偷Alpine on ARMv7的来用XDDDDD

首先我们去 Alpine 官网下载 Generic ARM (ARMv7) 的 tar 包下来,解压缩完,可以在boot资料夹底下看到 initramfs-lts 这个gzip压缩过的cpio档案。那麽,就来拆包吧:

mkdir extract
cd extract
cat ../initramfs-lts | gzip -d -c | cpio -idv

接着 tree 一下来看有哪些东西:

├── bin
│   ├── busybox
│   └── sh -> /bin/busybox
├── dev
├── etc
│   ├── apk
│   │   └── keys
│   │       ├── [email protected]
│   │       └── [email protected]
│   ├── fstab
│   ├── group
│   ├── mdev.conf
│   ├── modprobe.d
│   │   ├── aliases.conf
│   │   ├── blacklist.conf
│   │   ├── i386.conf
│   │   └── kms.conf
│   └── passwd
├── init
├── lib
│   ├── firmware
│   │   ├── ene-ub6250
│   │   │   ├── ms_init.bin
│   │   │   ├── msp_rdwr.bin
│   │   │   ├── ms_rdwr.bin
│   │   │   ├── sd_init1.bin
│   │   │   ├── sd_init2.bin
│   │   │   └── sd_rdwr.bin
│   │   └── qcom
│   ├── libcryptsetup.so.12 -> libcryptsetup.so.12.6.0
│   ├── libcryptsetup.so.12.6.0
│   ├── libdevmapper.so.1.02
│   ├── libkmod.so.2 -> libkmod.so.2.3.7
│   ├── libkmod.so.2.3.7
│   ├── libssl.so.1.1
│   ├── libuuid.so.1 -> libuuid.so.1.3.0
│   ├── libuuid.so.1.3.0
│   ├── libz.so.1 -> libz.so.1.2.11
│   ├── libz.so.1.2.11
│   ├── mdev
│   │   ├── dvbdev
│   │   ├── ide_links
│   │   ├── usbdev
│   │   ├── usbdisk_link
│   │   └── xvd_links
│   └── modules
│       └── 5.10.61-0-lts
│           ├── kernel
│           │   ├── arch
│           │   │   └── arm
│           │   │       └── lib
│           │   │           └── xor-neon.ko
│           │   ├── block
│           │   │   └── t10-pi.ko
......

此时,因为我们只要最基础的骨架,firmwaremodules这部份是给wifi firmware还有一些driver的,就直接大刀阔斧的干掉。紧接着开始去我们之前千辛万苦打出来Alpine package repo捞出对应的骨干来用:
sudo apk -vv --allow-untrusted -X /path/to/packages/main/ -U --arch riscv32 --root $PWD/tmp_rootfs --initdb add alpine-base mkinitfs

紧接着就是非常手工艺地,把busybox、各式 shared object一个个换进去ARM initramfs里面。

做完替换後,我们先把这份initramfs扔进一个loop dev image里面,给之前buildroot的rv32 qemu virt试验看看:
``
$ qemu-system-riscv32 -M virt -bios output/images/fw_jump.elf -kernel output/images/Image -append "rootwait root=/dev/vda rw init=/init" -drive file=/path/to/images.ext2,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,id=net0 -device virtio-net-device,netdev=net0 -nographic

OpenSBI v0.9


/ __ \ / | _ _ |
| | | |
__ ___ _ __ | (
| |
) || |
| | | | '_ \ / _ \ '_ \ ___ | _ < | |
| |__| | |) | __/ | | |) | |) || |
_
/| ./ _|| ||/|____/__|
| |
|_|

Platform Name : riscv-virtio,qemu
Platform Features : timer,mfdeleg
Platform HART Count : 1
Firmware Base : 0x80000000
Firmware Size : 124 KB
Runtime SBI Version : 0.2

Domain0 Name : root
Domain0 Boot HART : 0
Domain0 HARTs : 0*
Domain0 Region00 : 0x80000000-0x8001ffff ()
Domain0 Region01 : 0x00000000-0xffffffff (R,W,X)
Domain0 Next Address : 0x80400000
Domain0 Next Arg1 : 0x82200000
Domain0 Next Mode : S-mode
Domain0 SysReset : yes

Boot HART ID : 0
Boot HART Domain : root
Boot HART ISA : rv32imafdcsu
Boot HART Features : scounteren,mcounteren,time
Boot HART PMP Count : 16
Boot HART PMP Granularity : 4
Boot HART PMP Address Bits: 32
Boot HART MHPM Count : 0
Boot HART MHPM Count : 0
Boot HART MIDELEG : 0x00000222
Boot HART MEDELEG : 0x0000b109
[ 0.000000] Linux version 5.10.7 (ruinland@ruinland-x1c) (riscv32-buildroot-linux-gnu-gcc.br_real (Buildroot 2021.08-235-g287a359090) 10.3.0, GNU ld (GNU Binutils) 2.36.1) #2 SMP Sun Sep 12 22:40:18 CST 2021
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80400000
[ 0.000000] efi: UEFI not found.
[ 0.000000] Zone ranges:
[ 0.000000] Normal [mem 0x0000000080400000-0x0000000087ffffff]
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000080400000-0x0000000087ffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000080400000-0x0000000087ffffff]
[ 0.000000] SBI specification v0.2 detected
[ 0.000000] SBI implementation ID=0x1 Version=0x9
[ 0.000000] SBI v0.2 TIME extension detected
[ 0.000000] SBI v0.2 IPI extension detected
[ 0.000000] SBI v0.2 RFENCE extension detected
[ 0.000000] SBI v0.2 HSM extension detected

...

[ 0.669946] EXT4-fs (vda): mounting ext2 file system using the ext4 subsystem
[ 0.679685] EXT4-fs (vda): warning: mounting unchecked fs, running e2fsck is recommended
[ 0.697676] EXT4-fs (vda): mounted filesystem without journal. Opts: (null)
[ 0.699126] ext2 filesystem being mounted at /root supports timestamps until 2038 (0x7fffffff)
[ 0.700403] VFS: Mounted root (ext2 filesystem) on device 254:0.
[ 0.706050] devtmpfs: mounted
[ 0.761174] Freeing unused kernel memory: 204K
[ 0.763022] Run /init as init process
[ 1.348089] Alpine Init 3.5.0-r0
Alpine Init 3.5.0-r0
[ 1.362497] Loading boot drivers...

  • Loading boot drivers: [ 1.418605] Loading boot drivers: ok.
    ok.
    ln: /etc/mtab: File exists
    [ 1.450453] Mounting root...
  • Mounting root: [ 1.472526] nlplug-findfs[59]: unhandled signal 7 code 0x2 at 0x95a7a5b0 in ld-musl-riscv32-sf.so.1[95a7d000+c7000]
    [ 1.473890] CPU: 0 PID: 59 Comm: nlplug-findfs Not tainted 5.10.7 #2
    [ 1.474513] epc: 95af03dc ra : 95afe6e0 sp : 9db524e0
    [ 1.474891] gp : 95a7d000 tp : 95b46f28 t0 : 00000002
    [ 1.475260] t1 : 0004b8c7 t2 : 00000007 s0 : 9db52998
    [ 1.475645] s1 : 0004b000 a0 : 95a7a5b0 a1 : 00000000
    [ 1.476089] a2 : 00000a50 a3 : 00000fff a4 : fffff000
    [ 1.476551] a5 : 00000000 a6 : 00000000 a7 : 000000de
    [ 1.477002] s2 : 95a30000 s3 : 00000000 s4 : 95a30000
    [ 1.477654] s5 : 000000c0 s6 : 00000000 s7 : 00000003
    [ 1.478050] s8 : 00000005 s9 : 95b45a6c s10: 0004b000
    [ 1.478450] s11: 9db5254c t3 : 95b45288 t4 : 00000000
    [ 1.478868] t5 : 00000000 t6 : 00000020
    [ 1.479148] status: 00004020 badaddr: 95a7a5b0 cause: 0000000f
    Bus error
    mount: mounting /dev/vda on /sysroot failed: No such file or directory
    [ 1.575751] Mounting root: failed.
    failed.
    initramfs emergency recovery shell launched. Type 'exit' to continue boot
    sh: can't access tty; job control turned off
    / #

虽然 `nlplug-findfs` 这只Alpine initramfs拿来rootfs find and mount的helper会trigger runtime failure,但那可能是因为我们还没有给他正确root dev的关系,我们下一章,就来debug吧~

<<:  Day10 在 Next.js 安装 apollo-graphql,串接 WordPress GraphQL API(下)

>>:  [第十天]从0开始的UnityAR手机游戏开发-Vuforia多张图卡辨识

Day24 资料的续传

由於Object一般都很大,几十GB都属於正常现象,所以上传或下载的过程中难免回遇到网路不稳的问题导...

JavaScript Day22 - setTimeout、setInterval

setTimeout setTimeout:定时器,只执行一次,属於非同步,因此就算设定 0 秒执行...

DAY 18 - 九尾狐妹妹 (2) 线稿

大家好~ 我是五岁~ 今天来继续改善昨天的九尾狐草图吧~ 首先把耳朵厚度加厚了,并且加上毛茸茸的前饰...

[前端/JavaScript] 实作汇出excel下载按钮的超好用套件:ExcelJS(上)- 基础介绍与教学

简介 官方github连结: 英文文档 、 中文文档 ExcelJS 这个套件可以高弹性的将资料汇出...

Day-30: 设计转工程师这趟旅程,一些感言

从刚开始看程序码总觉得他们是蚯蚓, 我终於找到一件比做设计还难的事, 当然学习的过程, 没有我想像中...