我最近买了一块相当不错的中国 ARM 电脑板,Firefly(又名 T-Chip)的 ITX-3588J,其核心处理器由 RockChip 制造。该主板本身是一台集成的单板计算机 (SBC),因此不需要额外的扩展卡或驱动器即可工作,但它支持添加最多 4 个 SATA 驱动器和 1 个 PCIe x8 卡。它本身从主板内置的闪存 MMC 芯片读取操作系统和固件,供应商提供 MMC 闪存包,用于预制的 Android 12 和 Ubuntu 20.04 安装。
但考虑到 MMC 上的存储空间有限,我添加了一个容量为 250 GB 的 SSD 驱动器,并希望能够安装较新版本的 Ubuntu,即 22.04,我想知道是否可以这样做。问题是,几乎没有关于如何做到这一点的真正好的信息,因为这个主板太新了 - 它实际上是今年首次亮相,之前的所有 Firefly/Rockchip 产品都更小,功能也小得多。尽管如此,自从我得到它以来,我一直在破解它,但还没有完全成功。
MMC 附带的闪存包包含一个“U-Boot”基本引导加载程序/固件类型包,然后启动 extlinux,最后启动主内核。我想知道是否有某种方法(特别是使用第一个引导加载程序或其他)来启动 Ubuntu 22.04 USB 棒映像,特别是“jammy-desktop-arm64.iso”
https://cdimage.ubuntu.com/jammy/daily-live/current/
网站旨在安装到硬盘上。直到现在我才知道有这样一种叫做“U-Boot”的东西,这确实是我第一次使用它,而且我发现的关于它的其他一切似乎都是针对已经完全了解它的高级用户,以及除了我之外的其他用例——我找不到任何信息涵盖“如何通过 U-Boot 为 ARM 启动 Ubuntu USB .iso”!而且文档似乎是从主板制造商或供应商的角度编写的,而不是从用户的角度编写的。
那么,这可能吗?如果可以,您该怎么做?您是否需要升级 U-Boot - 该软件包附带的版本是 2017.04,并且它似乎缺少 2022 版本中的一些功能,例如“bootefi”,我注意到 USB 棒上有一些 .efi 文件。安装新的 U-Boot 看起来很棘手,因为主线 U-Boot 软件包中可供下载的最新 Rockchip 主板专用位是 RK3568 - 这并不奇怪,因为这款主板实际上是在四月的今年但是,仍然表明添加了供应商的自定义代码来生成 Ubuntu 闪存包,尽管供应商确实显然提供了“可根据要求”提供的板级 SDK。
但理想情况下,如果不是绝对必要的话,我不希望处理所有这些问题,并且有某种方法可以连接到链中,从而以另一种方式启动该 USB 棒。有吗?
添加:
U-Boot“帮助”的输出是
=> help
? - alias for 'help'
android_print_hdr- print android image header
atags - Dump all atags
base - print or set address offset
bdinfo - print Board Info structure
bidram_dump- Dump bidram layout
blk - Block device sub-system
boot - boot default, i.e., run 'bootcmd'
boot_android- Execute the Android Bootloader flow.
boot_fit- Boot FIT Image from memory or boot/recovery partition
bootavb - Execute the Android avb a/b boot flow.
bootd - boot default, i.e., run 'bootcmd'
booti - boot arm64 Linux Image image from memory
bootm - boot application image from memory
bootp - boot image via network using BOOTP/TFTP protocol
bootz - boot Linux zImage image from memory
charge - Charge display
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
crypto_sum- crypto checksum engine
dhcp - boot image via network using DHCP/TFTP protocol
dm - Driver model low level access
download- enter rockusb/bootrom download mode
dtimg - manipulate dtb/dtbo Android image
dump_irqs- Dump IRQs
dump_resource- dump resource list
echo - echo args to console
editenv - edit environment variable
env - environment handling commands
exit - exit script
ext2load- load binary file from a Ext2 filesystem
ext2ls - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls - list files in a directory (default /)
ext4size- determine a file's size
false - do nothing, unsuccessfully
fastboot- use USB or UDP Fastboot protocol
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls - list files in a directory (default /)
fatsize - determine a file's size
fatwrite- write file into a dos filesystem
fdt - flattened device tree utility commands
fstype - Look up a filesystem type
go - start application at address 'addr'
gpt - GUID Partition Table
help - print command description/usage
iomem - Show iomem data by device compatible(high priority) or node name
lcdputs - print string on video framebuffer
load - load binary file from a filesystem
loop - infinite loop on address range
ls - list files in a directory (default /)
md - memory display
mdio - MDIO utility commands
mii - MII utility commands
mm - memory modify (auto-incrementing address)
mmc - MMC sub system
mmcinfo - display MMC info
mtd_blk - MTD Block device sub-system
mw - memory write (fill)
nfs - boot image via network using NFS protocol
nm - memory modify (constant address)
part - disk partition related commands
ping - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
pxe - commands to get and boot from pxe files
rbrom - Perform RESET of the CPU
reboot - Perform RESET of the CPU, alias of 'reset'
reset - Perform RESET of the CPU
rkimgtest- Test if storage media have rockchip image
rockchip_show_bmp- load and display bmp from resource partition
rockchip_show_logo- load and display log from resource partition
rockusb - Use the rockusb Protocol
run - run commands in an environment variable
save - save file to a filesystem
saveenv - save environment variables to persistent storage
setcurs - set cursor position within screen
setenv - set environment variables
sf - SPI flash sub-system
showvar - print local hushshell variables
size - determine a file's size
source - run script from memory
sspi - SPI utility command
sysboot - command to get and boot from syslinux files
sysmem_dump- Dump sysmem layout
sysmem_search- Search a available sysmem region
test - minimal test like /bin/sh
tftp - download image via network using TFTP protocol
tftpbootm- tftpbootm aosp/uImage/FIT image via network using TFTP protocol
tftpflash- flash image via network using TFTP protocol
tftpput - TFTP put command, for uploading files to a server
true - do nothing, successfully
ums - Use the UMS [USB Mass Storage]
usb - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version
U-Boot“printenv”的输出是
=> printenv
arch=arm
autoload=no
baudrate=1500000
board=evb_rk3588
board_name=evb_rk3588
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf
boot_net_usb_start=usb start
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_targets=mmc1 mmc0 usb0 pxe dhcp
bootargs=storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal storagenode=/mmc@fe2e0000
bootcmd=boot_android ${devtype} ${devnum};boot_fit;bootrkp;run distro_bootcmd;
bootcmd_dhcp=run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_mmc1=setenv devnum 1; run mmc_boot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcmd_usb0=setenv devnum 0; run usb_boot
bootdelay=0
cpu=armv8
devnum=0
devplist=3
devtype=mmc
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
eth1addr=ce:20:d9:ee:5d:8d
ethaddr=ca:20:d9:ee:5d:8d
fdt_addr_r=0x0a100000
fileaddr=0xedf00000
filesize=0x1f34a
kernel_addr_c=0x05480000
kernel_addr_r=0x00400000
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi
partitions=uuid_disk=${uuid_gpt_disk};name=uboot,start=8MB,size=4MB,uuid=${uuid_gpt_loader2};name=trust,size=4M,uuid=${uuid_gpt_atf};name=misc,size=4MB,uuid=${uuid_gpt_misc};name=resource,size=16MB,uuid=${uuid_gpt_resource};name=kernel,size=32M,uuid=${uuid_gpt_kernel};name=boot,size=32M,bootable,uuid=${uuid_gpt_boot};name=recovery,size=32M,uuid=${uuid_gpt_recovery};name=backup,size=112M,uuid=${uuid_gpt_backup};name=cache,size=512M,uuid=${uuid_gpt_cache};name=system,size=2048M,uuid=${uuid_gpt_system};name=metadata,size=16M,uuid=${uuid_gpt_metadata};name=vendor,size=32M,uuid=${uuid_gpt_vendor};name=oem,size=32M,uuid=${uuid_gpt_oem};name=frp,size=512K,uuid=${uuid_gpt_frp};name=security,size=2M,uuid=${uuid_gpt_security};name=userdata,size=-,uuid=${uuid_gpt_userdata};
pxefile_addr_r=0x00600000
ramdisk_addr_r=0x0a200000
rkimg_bootdev=if mmc dev 1 && rkimgtest mmc 1; then setenv devtype mmc; setenv devnum 1; echo Boot from SDcard;elif mmc dev 0; then setenv devtype mmc; setenv devnum 0;elif mtd_blk dev 0; then setenv devtype mtd; setenv devnum 0;elif mtd_blk dev 1; then setenv devtype mtd; setenv devnum 1;elif mtd_blk dev 2; then setenv devtype mtd; setenv devnum 2;elif rknand dev 0; then setenv devtype rknand; setenv devnum 0;elif rksfc dev 0; then setenv devtype spinand; setenv devnum 0;elif rksfc dev 1; then setenv devtype spinor; setenv devnum 1;elsesetenv devtype ramdisk; setenv devnum 0;fi;
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then echo Found ${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x00500000
serial#=1bc8feb9d8c82bd2
soc=rockchip
stderr=serial,vidconsole
stdout=serial,vidconsole
usb_boot=usb start; if usb dev ${devnum}; then setenv devtype usb; run scan_dev_for_boot_part; fi
vendor=rockchip
Environment size: 3949/32764 bytes
添加:啊!不幸的是,上面的一些行被 minicom 粗鲁地截断了
添加:现在我有了上面没有截断的完整输出。无法使换行功能正常工作,因此我改用 minicom 的“捕获”功能将所有内容捕获到文件中
添加:我现在也尝试了更多实验。在检查了下载的 22.04 Ubuntu 映像 USB 棒的内容后,我发现它包含一个要启动的内核/casper/vmlinuz
,带有一个 ramdisk /casper/initrd
。我从位于的库存 Ubuntu 20.04 MMC 映像中抓取了主板 FDT 文件,将其放在/boot/rk3588-firefly-itx-3588j.dtb
USB 棒的同一位置,然后尝试了以下 U-Boot 命令:
usb start
setenv bootargs 'root=/dev/sda1'
load usb 0:1 $kernel_addr_r /casper/vmlinuz
load usb 0:1 $ramdisk_addr_r /casper/initrd
load usb 0:1 $fdt_addr_r /boot/rk3588-firefly-itx-3588j.dtb
bootz $kernel_addr_r $ramdisk_addr_r $fdt_addr_r
这是我通过阅读“如何启动内核”所得到的。所有命令都通过了,但最后一条命令最多只说“Fdt Ramdisk 跳过重定位”,然后直接返回 U-Boot 提示符。重新发出命令根本不起作用。这是什么意思?
答案1
我想知道是否有某种方法(特别是使用第一个引导加载程序或其他)来启动它......
U-Boot 是一种广泛使用的第二阶段甚至第三阶段引导程序,尤其是在 ARM SBC 上。
第一阶段引导程序通常位于集成到 SoC 中的 ROM 中。U-Boot 旨在在 RAM 中执行(就像它加载/引导的映像一样),因此可能存在加载 U-Boot 的第二阶段引导程序,这(通常)使 U-Boot 成为第三阶段引导程序。U
-Boot 源代码包含这样一个前体程序,称为 SPL(辅助程序加载器),用于加载 U-Boot。
供应商确实明显提供了“可根据要求”提供的板级 SDK。
要重建和/或自定义 U-Boot,您必须获取该特定主板的源代码。U-Boot 的主线版本主要支持开发板,而不是消费级产品。理论上,根据 GPL,产品制造商应该向所有者提供开源代码,但小公司经常忽略/违反这一点。
由于供应商确实提供了 BSP,所以您应该提出请求。
如果您在网上搜索,您可以找到为流行的 ARM SBC(例如 RPi 和 Beaglebone)构建 U-Boot 的指南和教程。NXP/Freescale 和 Atmel/Microchip 的指南往往更注重技术/专业性。
... 有没有办法将启动 USB 盘的功能挂接到链上,以另一种方式启动。有吗?
可能,如果已安装的 U-Boot 版本中内置了 USB 功能。
您是否已连接到主板的串行控制台(115200 波特,8n1)?
在启动过程中,通过键入任意键来中断 U-Boot 以获取命令提示符。
使用该help
命令获取可用的命令和功能。您需要有usb
列出的命令集才能访问 USB 设备作为启动介质。
U-Boot 启动内核所执行的步骤可以在其命令行中更改,例如,将内核映像(和设备树)从设备/分区/文件系统 X 加载到内存中的位置 Y。这些步骤也可以保存为环境变量(启动命令)。
附录
看起来您有一个功能齐全且由主板制造商定制的 U-Boot 版本(用于高性能主板)。已将从 USB 设备启动所需的命令(即usb
、fat
和ext2
/ ext4
)配置到该安装版本中。还有许多非标准/自定义命令,例如boot_android
和usbboot
。这种定制是将明显“过时”的软件版本安装在消费级主板上的常见原因。
除了增强的 U-Boot 命令集之外,还定义了许多环境变量以促进替代启动方案,例如使用 eMMC 或 SD 卡(bootcmd_mmc0/bootcmd_mmc1)、USB 存储设备(bootcmd_usb0)和网络(bootcmd_pxe和bootcmd_dhcp)。
您可能不需要重建 U-Boot,但获取源代码的 SDK/BSP 仍然会有所帮助。它可能有一些关于添加的自定义命令的文档。一些新的启动命令和环境变量显然需要在启动设备上安装特定文件(例如启动项和/或启动文件)。
要么你需要进行大量的实验,要么你可以获取并研究“资源丰富“ 的 ”SDK、教程、技术文档和开发工具Firefly 声称已为该产品提供了此功能。
不要使用通用的 64 位 ARMv8 Ubuntu 桌面映像,建议您坚持使用Firefly 提供的 Ubuntu 镜像。一旦您脱离了 x86 风格 PC 架构的行业惯例,您将需要设备树等配置方案的知识/专业知识(例如 频度文件)以确保成功启动备用内核。
附录二
... load usb 0:1 $kernel_addr_r /casper/vmlinuz ... bootz $kernel_addr_r $ramdisk_addr_r $fdt_addr_r
用一个维姆林兹文件用于 U-Boot 启动是没有意义的。这是一个 ELF 可执行格式,但您需要使用可立即执行的映像文件,例如图像文件。
中描述了引导 arm64 的底层细节文档。
这bootz
命令适用于图像文件,一种自解压形式的图像文件。
使用booti
启动图像文件。
如果图像文件已被手动/永久压缩(例如图片.gz),然后使用 U-Boot 命令在启动之前明确解压缩该文件booti
。