[记录] Boot JH7110 From Scratch

非教程,仅记录操作流程与思路,以供参考。

Day 1

目的是从0开始,一级一级构建启动所需的固件,直到加载内核进入系统。因而选择不使用SDK一步完成所有步骤构建,而是逐级构建,手动引导启动。

参考文档: Overview

根据文档描述,SoC片上固化的BootROM是第一级引导程序,能够将第二级引导加载到SRAM,而SDK的实现则是将UBoot SPL作为二级引导交给BootROM启动。

决定启动模式的bootstrap pin有两个,但是似乎只有2/4的case是被BootROM识别的(即:从UART XMODEM或SPI NOR FLASH)。待验证

接UART到电脑,minicom 115200连接至UART针脚:

上电,看到了输出:

Welcome to minicom 2.8

OPTIONS: I18n
Port /dev/ttyACM0, 16:32:33

Press CTRL-A Z for help on special keys


(C)StarFive
CCC
(C)StarFive
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

接下来研究如何构建UBoot SPL。

SDK入手开始研究。阅读Makefile可知构建SPL的目标为spl_bin_normal_out,涉及先构建UBoot再对SPL使用spl_tool做header两步。

首先构建Uboot。继续追踪Makefile目标:all -> uboot_fit -> (sbi_bin, uboot_its_file, uboot)

sbi暂且不管,先看看uboot_its_file是什么东西。追进去发现是UBoot FIT的uImage相关的构建描述。参考:Flattened uImage Tree (FIT) Images – The Good Penguin

再去追uboot本身的构建:uboot := $(uboot_wrkdir)/u-boot.bin, $(uboot): $(uboot_srcdir) $(target_gcc)锁定了构建时执行的命令与环境。

整个构建流程使用的是buildroot体系下构建的交叉编译工具链。我先试试ubuntu软件包中的rv64gc编译器能不能用。

首先将uboot源码拖到本地。我直接选择使用最新源码,而非sdk指定的commit

git clone git@github.com:starfive-tech/u-boot.git

再创建构建目录,执行out of tree build:

mkdir -p build/u-boot

make -C u-boot O=$(pwd)/build/u-boot CROSS_COMPILE=riscv64-linux-gnu- starfive_visionfive2_defconfig

也可以顺手看一眼menuconfig:make -C u-boot O=$(pwd)/build/u-boot CROSS_COMPILE=riscv64-linux-gnu- menuconfig

加上并行开始编译:make -C u-boot O=$(pwd)/build/u-boot CROSS_COMPILE=riscv64-linux-gnu- -j12

挺顺畅就完成了,只有一些小warning。

再解决spl_bin_normal_out的另一个依赖spl_tool

git clone git@github.com:starfive-tech/Tools.git
pushd Tools/spl_tool
make
popd

最后用这个工具处理之前编译uboot时产生的spl:

./Tools/spl_tool/spl_tool -c -f build/u-boot/spl/u-boot-spl.bin

接下来查看如何使用UART启动模式加载这个固件。参考:GitHub - starfive-tech/Tools

直接在之前开启的minicom中摁下CTRL+A再摁S,上下选择xmodem,选择生成的u-boot-spl.bin.normal.out,Okay。

成功看到了SPL执行输出:

U-Boot SPL 2021.10 (Jan 27 2024 - 17:52:34 +0800)                                                  
LPDDR4: 4G version: g8ad50857.                                                                     
SPL: Unsupported Boot Device!                                                                      
SPL: failed to boot from all boot devices

盲猜是因为调整bootstrap pin为串口启动,导致SPL内的判断逻辑异常。这次尝试上电后先重新配置bootstrap pin为SPI FLASH,再xmodem上传SPL。

U-Boot SPL 2021.10 (Jan 27 2024 - 17:52:34 +0800)                                                  
LPDDR4: 4G version: g8ad50857.                                                                     
Trying to boot from SPI                                                                            
                                                                                                   
OpenSBI v1.2                                                                                       
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|                                                       
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : StarFive VisionFive V2
Platform Features         : medeleg
Platform HART Count       : 5
Platform IPI Device       : aclint-mswi

看来是成功使用串口上传的SPL引导了FLASH上的OpenSBI。再对比一下直接以FLASH模式上电:

U-Boot SPL 2021.10 (Feb 28 2023 - 21:44:53 +0800)
DDR version: dc2e84f0.
Trying to boot from SPI

OpenSBI v1.2
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : StarFive VisionFive V2
Platform Features         : medeleg
Platform HART Count       : 5
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 4000000Hz

可以确定使用的SPL是编译的新版本

去确认了下upstream状态,visionfive2的支持似乎已经完全合入上游了,那就试试主线uboot的spl是什么情况。

U-Boot SPL 2024.01-01078-ge7f9e5eb58 (Jan 27 2024 - 18:41:35 +0800)
DDR version: dc2e84f0.
SPL: failed to boot from all boot devices
### ERROR ### Please RESET the board ###

可以,很爽的体验,有upstream support实在是太舒适了。甚至还集成了打包opensbi(当然我还没构建,这块就报错了)

https://rvspace.org/en/project/JH7110_Upstream_Plan

看来接下来处理opensbi的时候也可以直接使用上游仓库了。包括官方SDK在内的这些老仓库可以认为是过时的了。上游uboot的文档里已经提供了构建fit的方法,甚至还有emmc/sd部署方法,可以跳过NOR FLASH需求…?

Day 2

又去看了看debian的rv64 port,意识到bootrom大概是支持直接启动emmc/sd的,但是文档里又写不推荐sd/emmc启动…先去论坛上提问了,看看什么时候能得到回复。debian的系统镜像是依赖sd/emmc启动的,那看来我需要研究如何走NOR FLASH去引导位于sd的内核与系统。走这个思路的话,很像是标准PC体系…也在用一块NOR FLASH存储BIOS,去引导外部存储设备上的OS。

现在的问题是如何将生成的SPL+OpenSBI+UBoot在不拆除FLASH的情况下写入(当然我还没构建OpenSBI,待会就做)。理论来说可以UART上传执行代码就已经能够通过上传的代码来修改FLASH,也有这个工具了( https://github.com/starfive-tech/Tools/tree/master/recovery ),但是还没开源…总之先用用看。

回到之前停下来的地方,编译OpenSBI先。顺手把之前编译的UBoot给删了(包括构建目录),干干净净的弄一个release版本的。

参考: https://github.com/u-boot/u-boot/blob/master/doc/board/starfive/visionfive2.rst

git clone git@github.com:riscv-software-src/opensbi.git
pushd opensbi
git checkout v1.4
make PLATFORM=generic FW_TEXT_START=0x40000000 FW_OPTIONS=0 CROSS_COMPILE=riscv64-linux-gnu-
popd

额外阅读:

猜测目前的流程是由uboot打包封装opensbi,因此选择generic搭配FW_DYNAMIC,由SPL提供payload信息(实际是UBoot)。那么FW_TEXT_START应该是来自于UBoot的配置。

再编译UBoot:

git clone git@github.com:u-boot/u-boot.git
pushd u-boot/
git checkout v2024.01
popd
make -C u-boot O=$(pwd)/build/u-boot CROSS_COMPILE=riscv64-linux-gnu- starfive_visionfive2_defconfig

顺手去menuconfig里检查了一下FW_TEXT_START,果然对应的配置在CONFIG_SPL_OPENSBI_LOAD_ADDR。那么其实如果稍微让SPL变大一些,也不是不能通过UART上传SPL,再在SPL里利用uboot工具写入flash。

make -C u-boot O=$(pwd)/build/u-boot CROSS_COMPILE=riscv64-linux-gnu- OPENSBI=$(pwd)/opensbi/build/platform/generic/firmware/fw_dynamic.bin -j12

编译是编译完了,但是文档是针对sd/emmc启动的…研究一下怎么适配首次NOR FLASH启动…

重新看了看uboot的menuconfig,spl有打开FLASH支持(同时开了emmc)。但是估计需要配置CONFIG_SYS_SPI_U_BOOT_OFFS给到正确的offset,然后需要自己构建一个raw image。

看了眼spl不到140kB,修改CONFIG_SYS_SPI_U_BOOT_OFFS40000,即256kB。重新编译。不知道MKIMAGE u-boot.img是个什么image,之后查一下。

制作FLASH上要刷的image:

cp build/u-boot/spl/u-boot-spl.bin.normal.out build/spiflash.img
dd if=/dev/null of=build/spiflash.img bs=1 count=1 seek=262144
dd if=build/u-boot/u-boot.itb bs=1 >> build/spiflash.img

下载那个不开源的recovery镜像:https://github.com/starfive-tech/Tools/blob/master/recovery/jh7110-recovery-20230322.bin ,走minicom+xmodem上传。

使用这个recovery上传刚刚制作的img,xmodem有点慢…

突然发现文档里给16M的flash给的推荐布局,SPL后面是uboot env…待会核验一下吧

把开关拨到flash启动,看看输出。怎么没变呢…上传原始的u-boot-spl.bin.normal.out看看。这次有反应了,spl变成了最新版,看来是这个recovery对输入文件还有要求。先检查一下env的地址区间吧。CONFIG_ENV_OFFSETCONFIG_ENV_SIZE确实如同文档描述一致。

也就是说我CONFIG_SYS_SPI_U_BOOT_OFFS值是错误的,那spl是怎么启动的flash之前的payload的…给改回0再编译一份看看。这回使用那个recovery里两个选项分别上传spl和u-boot.itb

嗯这回spl,opensbi和uboot都是编译版本了。但是没搞清楚offset的问题还是不爽,以及还是在依赖不开源的那个看起来像工厂测试固件一样的玩意。

追了一下CONFIG_SYS_SPI_U_BOOT_OFFS,发现这个选项可以运行时被OF_REAL绕过,通过dts的u-boot,spl-payload-offset这个config。果然一搜就搜到在u-boot/arch/riscv/dts/jh7110-starfive-visionfive-2-u-boot.dtsi中配置成了0x100000,符合逻辑。

之后大概可以增加一些binman描述,自动生成一个大一点的完整raw image,包含spl+opensbi+uboot的完整包,作为firmware整体发布。

接下来就要研究uboot引导linux的流程了。大概看现在的uboot是已经支持了一大堆引导方式,包括但不限于usb,nvme的efi,以及bootp。需要仔细检查一下现行逻辑,选择一个合适的方式部署linux内核与rootfs。

通过一些搜索得知uboot default env可以在编译期直接生成出来:

make -C u-boot O=$(pwd)/build/u-boot CROSS_COMPILE=riscv64-linux-gnu- u-boot-initial-env

会在构建目录下生成u-boot-initial-env文件。所有启动相关的逻辑读这里就好了。

Day 3

书接上回,但是在着手阅读启动脚本之前,先找了一些拓展阅读来进行BFS式学习(解决bug时推荐DFS,学习新知识时推荐BFS):

看到一半去测试了下,发现当前uboot的env命令支持有一点问题,没有load,save也失败,先研究一下。

先直接在menuconfig里启用CONFIG_CMD_NVEDIT_LOADCONFIG_CMD_NVEDIT_SELECT,编译上传了试试。顺带,当前config下启用了nowhere和nor flash,所以也带上了select支持。

StarFive # env select
Select Environment on <NULL>: Unhandled exception: Load access fault
EPC: 00000000fffac76a RA: 00000000fff8a040 TVAL: 0000000000000000
EPC: 000000004026776a RA: 0000000040245040 reloc adjusted

Code: e311 8082 98e3 fec7 8023 0007 8082 87aa (c703 0005)

没实现,怎么回事…这个难道也是平台相关嘛…reset了抱着侥幸再试试:

StarFive # env select SPIFlash
Select Environment on SPIFlash: OK

大无语。env reset然后摁reset按钮看看启动之后有没有报crc异常。

Loading Environment from SPIFlash... SF: Detected gd25lq128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
OK

行看来能用,就是为什么这个命令cmdline本身没有处理NULL input啊。顺带。这几个命令和nowhereSPIFlash这几个关键字都是在uboot文档里从env命令那页看到的。继续滚去看文档了。

然后是bootflowbootmeths两个命令,前者没有完整版,后者没有启用。总之先打包进去。顺带启用了CONFIG_BOOTSTD_BOOTCOMMANDCONFIG_BOOTSTD_DEFAULTS,看看能消除多少env条目。在生成固件之前先重新生成了default env看看。env里的legacy脚本实在是不想读,看看能不能直接迁移到新的框架去。

迁移流程也会顺带把板子之前的配置头文件给动了,参考:U-Boot Standard Boot — Das U-Boot unknown version documentation

消灭deprecated真是令人开心呐(x

StarFive # bootflow scan -la
Scanning for bootflows in all bootdevs
Seq  Method       State   Uclass    Part  Name                      Filename
---  -----------  ------  --------  ----  ------------------------  ----------------
Scanning global bootmeth 'efi_mgr':
  0  efi_mgr      base    (none)       0  <NULL>                    
No bootdevs for 'nvme0'
No bootdevs for 'usb0'
Scanning bootdev 'mmc@16010000.bootdev':
Card did not respond to voltage select! : -110
Scanning bootdev 'mmc@16020000.bootdev':
Card did not respond to voltage select! : -110
EQOS_DMA_MODE_SWR stuckFAILED: -110EQOS_DMA_MODE_SWR stuckFAILED: -110No more bootdevs
---  -----------  ------  --------  ----  ------------------------  ----------------
(1 bootflow, 0 valid)

改了一些bsp之后成功从legacy scripts迁移到了bootstd,但是可以确定的是扔掉了之前的固定uuid引导sd/emmc的策略(是好事)。但是不确定还丢了哪些特性。不过丢了的这些特性也应该就是目前bootstd和distro_boot的子集。还顺手消灭了preboot,cleanup的很爽。

现在可以开始着手处理sd卡相关的东西了,内核稍微放一放。首先拿一张存储卡,重建分区表成gpt,创建一个efi分区…挂上去测试,认了。再随便建个普通分区弄一个extlinux.conf试试。啊还不能随便弄,得有boot标记。结果就变成了一个盘上两个efi区…

StarFive # bootflow scan -l 
Scanning for bootflows in all bootdevs
Seq  Method       State   Uclass    Part  Name                      Filename
---  -----------  ------  --------  ----  ------------------------  ----------------
Scanning global bootmeth 'efi_mgr':
No bootdevs for 'nvme0'
No bootdevs for 'usb0'
Scanning bootdev 'mmc@16010000.bootdev':
Card did not respond to voltage select! : -110
Scanning bootdev 'mmc@16020000.bootdev':
  0  extlinux     ready   mmc          2  mmc@16020000.bootdev.part /boot/extlinux/extlinux.conf

认了,且如同描述的lazy行为一致。那也可以认为efi也有效吧。接下来先走一遍extlinux流程,再试试efi方法。从构建内核开始。

Day 4

先下载内核。根据上游支持页的描述,clone对应仓库并切换去对应分支。这回我准备直接追到最新commit试试,也就是starfive官方的integeration tree。这个tree的历史不是稳定的,之后更新的话需要准备好git功夫去应对…等剩下这几个under review的提交合并之后应该就能直接拉拖袜子的仓库用了

git clone git@github.com:starfive-tech/linux.git
pushd linux
git checkout JH7110_VisionFive2_upstream
popd

简单配置一下编译条件

make -C linux O=$(pwd)/build/linux ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- starfive_visionfive2_defconfig
make -C linux O=$(pwd)/build/linux ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- menuconfig

为我自己的用例大概启用了:

  • CONFIG_PREEMPT
  • CONFIG_PREEMPT_DYNAMIC不确定架构优化有没有,先打开,之后有机会对比下性能
  • CONFIG_CPU_ISOLATION

其它通用的比如fuse啊overlayfs先不管了。编译试试:

time make -C linux O=$(pwd)/build/linux ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j12

...
real	4m10.457s
user	40m27.878s
sys	3m51.238s

还挺快…构造个extlinux.conf试试水。还是之前那张卡,总之先把第二个分区扬了。由于esp区的特殊性,桌面环境不会把它当作挂载目标,因此手动挂一下:

udisksctl mount --block-device /dev/sdc1

写入的/extlinux/extlinux.conf:

menu title Select Boot Target
timeout 100

label Pure Kernel Test
    kernel /Image
    fdt /jh7110-starfive-visionfive-2-v1.3b.dtb

Image和dtb在这个分区的根目录。

发现并没有构建出vmlinuz来…再menuconfig给启用了。但还是先拿Image起了(搜索了vmlinux、vmlinuz、Image等等格式的差异和用途)。总之起了,主控烫手…

** Booting bootflow 'mmc@16020000.bootdev.part_1' with extlinux
Select Boot Target
1:      Pure Kernel Test
Enter choice: 1
1:      Pure Kernel Test
Retrieving file: /Image
Retrieving file: /jh7110-starfive-visionfive-2-v1.3b.dtb
## Flattened Device Tree blob at 46000000
   Booting using the fdt blob at 0x46000000
Working FDT set to 46000000
   Loading Device Tree to 00000000fe6ea000, end 00000000fe6f767f ... OK
Working FDT set to fe6ea000

Starting kernel ...

Linux version 6.6.0-g13eb70da2a73 (salimterryli@stl-laptop) (riscv64-linux-gnu-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.04
Machine model: StarFive VisionFive 2 v1.3B
SBI specification v2.0 detected
SBI implementation ID=0x1 Version=0x10004
SBI TIME extension detected
SBI IPI extension detected
SBI RFENCE extension detected
efi: UEFI not found.

给conf加上了default,下次应该就自动启动该项了,顺带试试vmlinuz:

menu title Select Boot Target
timeout 3

default Pure Kernel Test

label Pure Kernel Test
    kernel /vmlinuz
    fdt /jh7110-starfive-visionfive-2-v1.3b.dtb

看到了Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0),放心了。接下来就看怎么去弄个rootfs。个人想弄个发行版base,先看看debian。

参考:https://wiki.debian.org/RISC-V#Creating_a_riscv64_chroot

总结:

  • debian主仓库已经支持rv64gc,但是没进bookworm,还是只能用sid
  • qemu也应该发布到stable分支了
  • debootstrapmmdebstrap都可用

思路:我直接在sd卡上弄个新分区当rootfs,bootstrap进去。先只给4G,做成了ext4,现在是/dev/sdc2,没有挂载。

这台开发机之前已经装过了qemu-user-static所以有qemu-riscv64-static

sudo apt-get install debian-keyring debian-archive-keyring
sudo mkdir /tmp/rv64chroot
sudo mount /dev/sdc2 /tmp/rv64chroot
sudo debootstrap --arch riscv64 sid /tmp/rv64chroot https://mirrors.ustc.edu.cn/debian

看一眼结果:

salimterryli@stl-laptop:~$ sudo ls -l /tmp/rv64chroot/sbin/init
lrwxrwxrwx 1 root root 22 Jan 29 18:46 /tmp/rv64chroot/sbin/init -> ../lib/systemd/systemd

行了,试试。

sudo umount /tmp/rv64chroot
blkid | grep sdc2

记下uuid,修改extlinux.conf,把root分区加到内核cmdline:

menu title Select Boot Target
timeout 3

default Debian (sid)

label Pure Kernel Test
    kernel /vmlinuz
    fdt /jh7110-starfive-visionfive-2-v1.3b.dtb

label Debian (sid)
    kernel /vmlinuz
    fdt /jh7110-starfive-visionfive-2-v1.3b.dtb
    append rw root=UUID=e27677fa-c9ee-4ecd-93bf-42f085784c84

没认。根据:linux - Why can't I specify my root fs with a UUID? - Unix & Linux Stack Exchange ,我没给initrd,可能只能用partuuid。重新改成partuuid启动,成功了,但是登录不了,刚刚bootstrap完没配用户…重新把盘挂电脑上,chroot进去创建用户。看了眼另一个文档决定试试来自systemd-containersystemd-nspawn

sudo systemd-nspawn -D /tmp/rv64chroot -M debian --bind-ro=/etc/resolv.conf

adduser xxx
apt-get update
apt-get install sudo
usermod -aG sudo xxx

这样避开配置root密码,直接用自己的账户。CTRL+D出来,unmount,再在板子上启动。可以走串口登录了。启动到系统之后soc就不烫了。

然后配网,执行ip link能看到两个网口正确识别了。那就写interfaces配网:sudo nano /etc/network/interfaces.d/end0:

allow-hotplug end0
iface end0 inet dhcp
iface end0 inet6 auto

再复制一份给end1:

sudo cp /etc/network/interfaces.d/end0 /etc/network/interfaces.d/end1
sudo sed -i 's/end0/end1/g' /etc/network/interfaces.d/end1
sudo systemctl restart networking

也要修改hostname,我直接改了/etc/hostname,看了眼,/etc/hosts里没有主机名,那不管了。

还要做ntp,先拿date -s "20240130 19:48:00"顶一下,不然apt都没法用…然后直接装了sudo apt-get install systemd-timesyncd

再就是几个必装软件:sudo apt-get install bash-completion openssh-server avahi-daemon,直接开始ssh操作…minicom的键盘快捷键不甚友好…

salimterryli@stl-laptop:~$ ssh stl-rv64.local
Linux stl-rv64 6.6.0-g13eb70da2a73 #2 SMP PREEMPT_DYNAMIC Tue Jan 30 17:20:27 CST 2024 riscv64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Jan 30 19:56:12 2024 from 192.168.198.167
salimterryli@stl-rv64:~$ uname -a
Linux stl-rv64 6.6.0-g13eb70da2a73 #2 SMP PREEMPT_DYNAMIC Tue Jan 30 17:20:27 CST 2024 riscv64 GNU/Linux
salimterryli@stl-rv64:~$

总之是跑起来了,但是还有很多需要改的地方,包括initramfs也要配,需要拿它加载固件,等等,以及还要好多内核feature都没启用,想个办法看看怎么把常用feature一把抓了。

sudo reboot,然后无事发生…串口也死了。

Day 4 Night

补上EXT4_FS_POSIX_ACL,解决了ssh登录就在串口打印的报错后,reboot和poweroff也好了…(实际没有,还是随机出问题)

Day 5

晚上睡觉前没忍住搜了下fbdev,了解到了fvcon,看看能不能把显示设备上的console给弄出来。

https://www.kernel.org/doc/Documentation/fb/fbcon.txt

这回编译选择带上ccache,看看能不能稍微改善点编译速度。

time make -C linux O=$(pwd)/build/linux ARCH=riscv CROSS_COMPILE="ccache riscv64-linux-gnu-" -j12

real	5m51.382s
user	57m55.862s
sys	6m24.756s

看起来是没有fbdev支持,但是有drm,倒是成功把kmscon跑起来了,但是这个用户态console需要启动完系统之后才出现。研究一下有没有drm模拟fb的轮子。哦是这个:CONFIG_DRM_FBDEV_EMULATION,试试。啊,有了。

看到了CONFIG_RT_GROUP_SCHED,mark一下,先启用,之后估计能用上这个cgroup。

先拿menuconfig对着树莓派的配置迁移了一些,到了NET附近,通用配置突然就多了起来,决定生成defconfig直接改defconfig再让构建系统去清理合并。用meld辅助,遇到不确定的config就直接在menuconfig里搜,然后再加进defconfig。

把network stack弄过来了,剩下的杂项比如usb驱动啥的一大把…先不搞了…也导致编译时间直线上升。还是先revert了吧。

一时兴起企图尝试jtag看看rv核心。拿出之前买的tigard,还真给用起来了。

adapter driver ftdi
adapter speed 2000
ftdi_vid_pid 0x0403 0x6010
ftdi_channel 1
ftdi_layout_init 0x0038 0x003b
ftdi_layout_signal nTRST -data 0x0010
ftdi_layout_signal nSRST -data 0x0020
transport select jtag

set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu0 -irlen 5
jtag newtap $_CHIPNAME cpu1 -irlen 5
set _TARGETNAME_1 $_CHIPNAME.cpu1
set _TARGETNAME_2 $_CHIPNAME.cpu2
set _TARGETNAME_3 $_CHIPNAME.cpu3
set _TARGETNAME_4 $_CHIPNAME.cpu4

target create $_TARGETNAME_1 riscv -chain-position $_CHIPNAME.cpu1 -coreid 1
target create $_TARGETNAME_2 riscv -chain-position $_CHIPNAME.cpu1 -coreid 2
target create $_TARGETNAME_3 riscv -chain-position $_CHIPNAME.cpu1 -coreid 3
target create $_TARGETNAME_4 riscv -chain-position $_CHIPNAME.cpu1 -coreid 4

target smp $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4

init
halt

就是暂时只能在uboot用,linux可能需要改pinmux。纠结接下来先做什么。

Day 6

阅读了: Boot Loader Specification | UAPI Group Specifications

根据parted文档: Parted User’s Manual

重新认识了efi和boot分区。将之前的双分区(EFI+rootfs)改为经典PC三分区(EFI+boot+rootfs)。我直接在gparted里把rootfs挪后了512MB,在空出来的地方建了个ext4区,标记为bls_boot。希望当前这个uboot支持ext4。

然后把extlinux和kernel都挪去这个新分区,老efi区只留efi相关东西,目前就什么都不剩(除了uboot新建的ubootefi.var)。看看uboot认不认。

没认。确认了下是有ext4,再看看具体为什么。根据: Generic Distro Configuration Concept — Das U-Boot unknown version documentation

来看uboot找的是legacy_boot。那先标成legacy试试,不知道进了linux之后systemd自动挂载会不会创建autofs条目。期望是自动把efi区挂到/efi,而boot挂在/boot

认了…这应该算是uboot没有遵从Boot Loader Specification吧。但是systemd给我把efi挂去了boot,真正的boot没管。那就同时启用两个flag试试。

/dev/mmcblk1p3 on /boot type ext4 (rw,nosuid,nodev,noexec,relatime,nosymfollow)
/dev/mmcblk1p1 on /efi type vfat (rw,nosuid,nodev,noexec,relatime,nosymfollow,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)

这回对了。做这个主要是看内核make deb-pkg生成的包该怎么以最好的方式去利用。那么现在构建个内核deb看看。暂且只做二进制包。

time make -C linux O=$(pwd)/build/linux ARCH=riscv CROSS_COMPILE="ccache riscv64-linux-gnu-" bindeb-pkg

它给我生成在build目录里了,而不是build/linux。我寻思我没传过裸build目录啊,这里肯定有问题,里面一定是以不合适的手段用了相对路径。

直接看看生成的image包:

  • data里,内核三件套扔进了/boot,因此要求正确挂载boot
  • /etc/kernel/xxx.d被建立以执行pre/post的内核安装脚本。脚本本身不由kernel提供
  • ko被标准的扔进了/lib/modules
  • dtb被扔进了/usr/lib/linux-image-xxx/starfive

还多生成了个linux-libc-dev包,搜了一圈认为忽略这个包就行:[PATCH] deb-pkg: Make deb-pkg generate a seperate linux-libc-dev deb - maximilian attems

又去看了看来自u-boot-menu包的u-boot-update,了解了下它的流程。小结论,依靠这个包和内核包就能完成内核部署。

先在目标上安装u-boot-menu,再rsync把内核包传上去安装。之后再整理自动化流程。

装内核包的时候调用了u-boot-update,自动更新了extlinux.conf,但是没同步dtb。修改/etc/default/u-boot启动dtb同步:sudo sed -i 's/#U_BOOT_SYNC_DTBS="false"/U_BOOT_SYNC_DTBS="true"/' /etc/default/u-boot

手动执行u-boot-update后,没变。追了一下源码,似乎dtb是在安装kernel包的时候才会触发更新。那重新装一下内核包。同步了,但是dtb目录多了一层vendor,不确定是哪个组件的锅。以及还有个问题,内核如何选择dtb。

去看了眼uboot的板极支持,board/starfive/visionfive2/starfive_visionfive2.c里已经有了选择dtb的逻辑,那理论来说是work的。万事俱备,直接reboot。

启动报错了,Bad Linux RISCV Image magic!。看一下make deb-pkg的实现,这个vmlinuz不太对劲。它怎么用的是efi的二进制…先把vmlinuz换了去启动系统,再看看怎么修复。啊,它还默认rootfs只读了…也得改,也不必quiet。

关了CONFIG_EFI后就选择Image.gz了。感觉也合理,没必要在内核直接做efistub。那就这样吧。

顺带试一下sudo apt-get autoremove linux-image-*的cleanup,干净的。装了新内核,重启也没有问题了。

关于为什么cmdline里没有经典console=,因为在dts里面绑了stdout-path。但是有几个flag还是有必要加的比如rootwait

debian rootfs和内核基本就摸清楚了,那么剩下的问题是怎么打包更新uboot。Linux里面倒是能看到mtd设备。先研究下mtd分区列表是哪里来的。哦也在dts里。那就很方便了,只要能进系统就能更新引导(x

目前来看还是需要个简单的手段去用UART模式上传固件,才是最理想的。这帖大概结了。

offtopic

工具链

在编译内核这些东西的时候使用发行版携带的rv64工具链没有问题可以正常用,但是在给板子交叉编译用户态程序时就遇到了些问题:

  • 使用发行版提供的工具链交叉编译某个软件时,发现libatomic相关的编译不过,查了确认是个gcc bug,且在gcc 13.2修复了
  • 发行版提供gcc13.2打包的也是最新的glibc,比debian sid的glibc还新,导致版本mismatch

所以只能自己编译一个gcc工具链,用gcc 13.2搭配一个老版本的glibc比如2.31,解决libc的版本依赖问题。GitHub - riscv-collab/riscv-gnu-toolchain: GNU toolchain for RISC-V, including GCC

发行版内核

前几天偶然瞅见debian软件源里已经发布了starfive-6.5的内核,具体没瞅支持的是哪个目标,但是值得探索看看。