Compare commits

...

7 Commits

Author SHA1 Message Date
Daniel Barlow 32c13c46bb support aarch64 in tftpboot test 2023-12-19 12:12:12 +00:00
Daniel Barlow e5db2691e5 add CI job to test tftpboot 2023-12-18 22:42:29 +00:00
Daniel Barlow 9ca9723c9d make rootfs work with tftpbootlz 2023-12-17 19:39:26 +00:00
Daniel Barlow d1e2d525a4 tftpboot omnia using bootz not bootm
because kernel size is now beyond the u-boot size
limit for bootm
2023-12-16 23:40:55 +00:00
Daniel Barlow f4f4387861 well, we're back to where we can boot again
so that's good
2023-12-16 23:40:55 +00:00
Daniel Barlow 55fa9992d4 WIP 2023-12-13 21:54:15 +00:00
Daniel Barlow 95d9e014fb omnia: fix paths 2023-12-13 21:52:28 +00:00
14 changed files with 411 additions and 26 deletions

View File

@ -3442,16 +3442,147 @@ diskimage {
partitionType = "mtd" ; # or "mbr" or maybe "gpt"
partitions = [ o.uimage o.rootfs ];
}
for the turris we need to check but proceeding on the assumption
it wants a tarball with extlinux enabled
it wants a tarball with extlinux enabled
https://docs.turris.cz/geek/schnapps/schnapps/#export-and-import
https://wiki.turris.cz/en/howto/omnia_booting_from_external_storage
if we adopt this as our installation format then we are not
reformatting the flash and will keep the btrfs that the device
was shipped with.
was shipped with.
https://forum.turris.cz/t/update-to-5-1-x-by-medkit/13986/12
suggests that we could install a custom medkit from the
vendor OS
=> btrsubvol mmc 0:1
ID 257 parent 5 name /@
ID 259 parent 5 name /@factory
there don't seem to be any other btr commands in u-boot
Tue Dec 12 14:38:53 GMT 2023
from the source code, to get to the various omnia revovery modes
uboot> setenv omnia_reset 3 # or 1..n
uboot> setenv boot_targets rescue
uboot> boot
// reset boot_targets to default value.
Tue Dec 12 22:44:34 GMT 2023
The hold-down-reset-until-n-leds-flash support depends quite heavily
on the post-boot Linux environment, in that it appears to be passing
omniarescue=3 rescue_mode=3 to the kernel command line -> pid 1
cmdline
On the other hand, it is described as being able to boot from usb
stick if there's a boot.scr on the usb stick, so maybe we just do
that. The installation process could then be "boot usb, dd the
disk image to mmc, reboot, remove usb, realise we got the wrong root=".
Hmm.
* Could we edit extlinux.conf for first boot? But bear in mind it's a
link to a store file.
* Could we have extlinux.conf point at mmc0 and somehow override it for the
usb stick boot?
* Could preinit try multiple root mounts until it gets one that works?
* maybe we could detect omniarescue on kernel command line and switch to
usb root?
* maybe outputs.usbstick could generate a customised rootfs image?
it might be unworkable to
(narrator: it boots from mmc0 first and usb stick second, so that's not
particularly useful)
Device 0: Vendor: SanDisk Rev: 1.00 Prod: Cruzer Blade
Type: Removable Hard Disk
Capacity: 7632.0 MB = 7.4 GB (15630336 x 512)
... is now current device
Scanning usb 0:1...
No EFI system partition
fdt_find_or_add_subnode: chosen: FDT_ERR_BADSTRUCTURE
ERROR: /chosen node create failed
- must RESET the board to recover.
Thu Dec 14 15:32:39 GMT 2023
from the omnia rescue image, we have
## Loading kernel from FIT Image at 01700000 ...
Load Address: 0x00800000
Entry Point: 0x00800000
int lzmaBuffToBuffDecompress(unsigned char *outStream, SizeT *uncompressedSize,
const unsigned char *inStream, SizeT length)
err = image_decomp(os.comp, load, os.image_start, os.type,
load_buf, image_buf, image_len,
CONFIG_SYS_BOOTM_LEN, &load_end);
configs/mvebu_db_armada8k_defconfig:CONFIG_SYS_BOOTM_LEN=0x800000
default 0x4000000 if PPC || ARM64
default 0x1000000 if X86 || ARCH_MX6 || ARCH_MX7
default 0x800000
Fri Dec 15 19:21:53 GMT 2023
Let's put some English words on the page to explain the above
gibberish. Since I upgraded the U-Boot on my Turris Omnia, it has
stopped being able to tftpboot.
Uncompressing Kernel Image
lzma compressed: uncompress error 7
Must RESET board to recover
"uncompress error 7" means there is not enough space in the output
buffer, and the output buffer is set by CONFIG_SYS_BOOTM_LEN which is
8192k, smaller than the uncompressed 12104200 of our kernel.
So how can we fix?
* one possibility is to do what the turris rescue mode does: build an
uncompressed uimage and then lzma the result. u-boot can uncompress
the received file using lzmadec command. we'd want to do this without
breaking tftpboot on every other device that might not have an lzmadec
command
* is there bloat in the kernel we could trim? probably not 4MB of it
* we could build a custom u-boot with a bigger buffer. this _might_
not be a completely stupid idea as it's only the people prepared to
open the box that would be doing tftp workflows anyway, so provided
it's possible to replace u-boot without bricking it
* we could try building zimage instead of uimage and use bootz to
start it
Sat Dec 16 11:15:56 GMT 2023
there is another use case for weird tftpboot derivation, which is the
device Raito has ported to where you need to wave a magic chicken at
u-boot on each command line
Sat Dec 16 23:32:11 GMT 2023
Turns out that even when using an uncompressed uimage, u-boot runs the
code to check the decompressed size, so that doesn't help at all. But
booting a zImage works fine. I am committing a first pass of
modules/outputs/tftpbootlz.nix which does this using a lot of
copy-paste and (ironically) no lzma stuff at all.

View File

@ -43,5 +43,9 @@
boot.commandLine = [
"console=ttyAMA0,38400"
];
hardware = let addr = lim.parseInt "0x40010000"; in {
loadAddress = addr;
entryPoint = addr;
};
};
}

View File

@ -45,9 +45,9 @@
boot.commandLine = [
"console=ttyAMA0"
];
hardware = {
loadAddress = lim.parseInt "0x00010000";
entryPoint = lim.parseInt "0x00010000";
hardware = let addr = lim.parseInt "0x40008000"; in {
loadAddress = addr;
entryPoint = addr;
};
};
}

View File

@ -14,10 +14,10 @@
let openwrt = pkgs.openwrt; in {
imports = [
../../modules/arch/arm.nix
../modules/outputs/tftpboot.nix
../modules/outputs/mbrimage.nix
../modules/outputs/extlinux.nix
../modules/outputs/ext4fs.nix
../../modules/outputs/tftpbootlz.nix
../../modules/outputs/ext4fs.nix
../../modules/outputs/mbrimage.nix
../../modules/outputs/extlinux.nix
];
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
@ -52,12 +52,6 @@
# WARNING: unmet direct dependencies detected for ARCH_WANT_LIBATA_LEDS
ATA = "y";
# CONFIG_REGMAP=y
# CONFIG_REGMAP_I2C=y
# CONFIG_REGMAP_SPI=y
# CONFIG_REGMAP_MMIO=y
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
@ -95,7 +89,7 @@
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
};
};
rootfsType = "ext4";
boot = {
commandLine = [
"console=ttyS0,115200"
@ -122,6 +116,8 @@
};
};
boot.tftp.loadAddress = lim.parseInt "0x1000000";
hardware = let
mac80211 = pkgs.mac80211.override {
drivers = ["ath9k_pci" "ath10k_pci"];
@ -129,8 +125,9 @@
};
in {
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x00008000";
entryPoint = lim.parseInt "0x00008000";
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
rootDevice = "/dev/mtdblock0";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/armada-385-turris-omnia.dts";
@ -172,6 +169,11 @@
devpath = "/devices/platform/soc/soc:internal-regs/f1034000.ethernet";
ifname = "wan";
};
lan = link.build {
ifname = "lan1";
};
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];

View File

@ -44,7 +44,6 @@ in rec {
../modules/ntp
../modules/ssh
];
rootfsType = "jffs2";
hostname = "rotuer";
services.hostap = svc.hostapd.build {
@ -182,4 +181,8 @@ in rec {
defaultProfile.packages = with pkgs; [
min-collect-garbage
];
programs.busybox.applets = [
"fdisk" "sfdisk"
];
}

View File

@ -70,26 +70,30 @@ in {
in
pkgs.buildPackages.runCommand "boot-scr" { nativeBuildInputs = [ pkgs.pkgsBuildBuild.dtc ]; } ''
uimageSize=$(($(stat -L -c %s ${o.uimage}) + 0x1000 &(~0xfff)))
rootfsStart=0x$(printf %x $((${toString cfg.loadAddress} + 0x100000 + $uimageSize &(~0xfffff) )))
rootfsStart=$(printf %x $((${toString cfg.loadAddress} + 0x100000 + $uimageSize &(~0xfffff) )))
rootfsBytes=$(($(stat -L -c %s ${o.rootfs}) + 0x100000 &(~0xfffff)))
rootfsBytes=$(($rootfsBytes + ${toString cfg.freeSpaceBytes} ))
rootfsMb=$(($rootfsBytes >> 20))
cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsBytes},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
cmd="mtdparts=phram0:''${rootfsMb}M(rootfs) phram.phram=phram0,0x''${rootfsStart},''${rootfsBytes},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
dtbStart=$(printf %x $((${toString cfg.loadAddress} + $rootfsBytes + 0x100000 + $uimageSize )))
mkdir $out
cat ${o.dtb} > $out/dtb
fdtput -p -t s $out/dtb /reserved-memory/phram-rootfs compatible phram
fdtput -p -t lx $out/dtb /reserved-memory/phram-rootfs reg 0 $rootfsStart 0 $(printf %x $rootfsBytes)
fdtput -p $out/dtb /reserved-memory '#address-cells' 2
fdtput -p $out/dtb /reserved-memory '#size-cells' 2
fdtput -p $out/dtb /reserved-memory ranges
fdtput -p -t s $out/dtb /reserved-memory/phram-rootfs@$rootfsStart compatible phram
fdtput -p -t lx $out/dtb /reserved-memory/phram-rootfs@$rootfsStart reg 0 0x$rootfsStart 0 $(printf %x $rootfsBytes)
# dtc -I dtb -O dts -o /dev/stdout $out/dtb; exit 1
dtbBytes=$(($(stat -L -c %s $out/dtb) + 0x1000 &(~0xfff)))
cat > $out/script << EOF
setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr}
setenv bootargs 'liminix ${cmdline} $cmd'
tftpboot 0x${lib.toHexString cfg.loadAddress} result/uimage ; tftpboot 0x$(printf %x $rootfsStart) result/rootfs ; tftpboot 0x$dtbStart result/dtb
tftpboot 0x${lib.toHexString cfg.loadAddress} result/uimage ; tftpboot 0x$rootfsStart result/rootfs ; tftpboot 0x$dtbStart result/dtb
bootm 0x${lib.toHexString cfg.loadAddress} - 0x$dtbStart
EOF
'';

View File

@ -0,0 +1,90 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
inherit (pkgs.lib.trivial) toHexString;
o = config.system.outputs;
cmdline = concatStringsSep " " config.boot.commandLine;
cfg = config.boot.tftp;
tftpbootlz =
pkgs.buildPackages.runCommand "tftpbootlz" {
nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc ];
} ''
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); }
hex() { printf "0x%x" $1; }
kernelStart=${toString cfg.loadAddress}
kernelSize=$(binsize ${o.zimage})
mkdir -p $out
cat ${o.dtb} > $out/dtb
fdtput -p -t lx $out/dtb /reserved-memory '#address-cells' 1
fdtput -t lx $out/dtb /reserved-memory '#size-cells' 1
fdtput $out/dtb /reserved-memory ranges
fdtput -p -t s $out/dtb /reserved-memory/phram-rootfs compatible phram
# can't calculate the actual address here until we know how
# big the dtb will be
fdtput -t lx $out/dtb /reserved-memory/phram-rootfs reg 0xdead 0xcafe
dtbStart=$(($kernelStart + $kernelSize))
dtbSize=$(binsize $out/dtb)
rootfsOrigSize=$(binsize64k ${o.rootfs})
lzma -z9cv ${o.rootfs} > $out/rootfs.lz
rootfsLzSize=$(binsize $out/rootfs.lz)
rootfsLzStart=$(($dtbStart + $dtbSize))
rootfsOrigStart=$(($rootfsLzStart + $rootfsLzSize))
fdtput -t lx $out/dtb /reserved-memory/phram-rootfs reg $(printf "%x" $rootfsOrigStart) $(printf "%x" $rootfsOrigSize)
# dtc -I dtb -O dts -o /dev/stdout $out/dtb ; exit 1
cmd="mtdparts=phram0:''${rootfsOrigSize}(rootfs) phram.phram=phram0,''${rootfsOrigStart},''${rootfsOrigSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
(cd $out;
ln -s ${o.zimage} zImage
ln -s ${o.manifest} manifest
ln -s ${o.kernel.headers} build)
cat > $out/boot.scr << EOF
setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr}
setenv bootargs "liminix ${cmdline} $cmd"
tftpboot $(hex $kernelStart) result/zImage; tftpboot $(hex $dtbStart) result/dtb ; tftpboot $(hex $rootfsLzStart) result/rootfs.lz
lzmadec $(hex $rootfsLzStart) $(hex $rootfsOrigStart)
bootz $(hex $kernelStart) - $(hex $dtbStart)
EOF
'';
in {
imports = [ ../ramdisk.nix ];
options.boot.tftp.freeSpaceBytes = mkOption {
type = types.int;
default = 0;
};
options.system.outputs = {
tftpbootlz = mkOption {
type = types.package;
description = ''
tftpbootlz
**********
This is a variant of the tftpboot output intended for the
Turris Omnia. It uses a zImage instead of a uimage, as a
workaround for an awkwardly low CONFIG_SYS_BOOTM_LEN setting
in the U-Boot build for the device which means it won't boot
uimages unless they're teeny tiny.
As a bonus, it also uses lzma compression on the rootfs,
which reduces a 20MB ext4 image to around 4MB
'';
};
};
config = {
boot.ramdisk.enable = true;
system.outputs = {
inherit tftpbootlz;
};
};
}

View File

@ -200,6 +200,12 @@ extraPkgs // {
strace = prev.strace.override { libunwind = null; };
ubootQemuAarch64 = final.buildUBoot {
defconfig = "qemu_arm64_defconfig";
extraMeta.platforms = ["aarch64-linux"];
filesToInstall = ["u-boot.bin"];
};
ubootQemuArm = final.buildUBoot {
defconfig = "qemu_arm_defconfig";
extraMeta.platforms = ["armv7l-linux"];
@ -212,6 +218,23 @@ extraPkgs // {
CONFIG_CMD_UBIFS=y
CONFIG_BOOTSTD=y
CONFIG_BOOTMETH_DISTRO=y
CONFIG_LZMA=y
CONFIG_CMD_LZMADEC=y
CONFIG_SYS_BOOTM_LEN=0x1000000
'';
};
# gnufdisk = prev.gnufdisk.override {
# guile = null;
# };
# util-linux = prev.util-linux.override {
# ncursesSupport = false;
# pamSupport = false;
# systemdSupport = false;
# nlsSupport = false;
# translateManpages = false;
# capabilitiesSupport = false;
# };
}

View File

@ -87,7 +87,7 @@
(local bin {
:mips ["qemu-system-mips" "-M" "malta"]
:aarch64 ["qemu-system-aarch64" "-M" "virt"
"-semihosting" "-cpu" "cortex-a72"]
"-cpu" "cortex-a72"]
:arm ["qemu-system-arm" "-M" "virt,highmem=off"
"-cpu" "cortex-a15"]
})

View File

@ -7,4 +7,5 @@
ext4 = import ./ext4/test.nix;
min-copy-closure = import ./min-copy-closure/test.nix;
fennel = import ./fennel/test.nix;
tftpboot = import ./tftpboot/test.nix;
}

31
tests/tftpboot/a.sh Normal file
View File

@ -0,0 +1,31 @@
"qemu-system-arm" \
"-M" \
"virt,highmem=off" \
"-cpu" \
"cortex-a15" \
"-m" \
"272" \
"-echr" \
"16" \
"-device" \
"loader,file=run-vm-FwJ0aL,addr=0x3c00000" \
"-serial" \
"mon:stdio" \
"-drive" \
"if=pflash,format=raw,file=run-vm-duvYIP" \
"-drive" \
"if=none,format=raw,id=hd0,file=run-vm-FwJ0aL" \
"-device" \
"virtio-blk-pci,drive=hd0" \
"-netdev" \
"socket,id=access,mcast=230.0.0.1:1234,localaddr=127.0.0.1" \
"-device" \
"virtio-net,disable-legacy=on,disable-modern=off,netdev=access,mac=ba:ad:1d: \
ea:21:02" \
"-netdev" \
"user,tftp=/build,id=lan" \
"-device" \
"virtio-net,disable-legacy=on,disable-modern=off,netdev=lan,mac=ba:ad:1d:ea: \
21:01" \
"-display" \
"none"

View File

@ -0,0 +1,38 @@
{ config, pkgs, lib, lim, ... } :
let
inherit (pkgs.pseudofile) dir symlink;
dts = pkgs.runCommand "qemu.dts" {
nativeBuildInputs = with pkgs.pkgsBuildBuild; [ dtc qemu ];
} ''
qemu-system-${pkgs.stdenv.hostPlatform.qemuArch} \
-machine virt -machine dumpdtb=tmp.dtb
dtc -I dtb -O dts -o $out tmp.dtb
# https://stackoverflow.com/a/69890137,
# XXX try fdtput $out -p -t s /pl061@9030000 status disabled
# instead of using sed
sed -i $out -e 's/compatible = "arm,pl061.*/status = "disabled";/g'
'';
in {
imports = [
../../modules/outputs/ext4fs.nix
../../modules/outputs/tftpboot.nix
];
config = {
hardware.dts.src = lib.mkForce dts;
boot.tftp = {
loadAddress = lim.parseInt "0x44000000";
serverip = "10.0.2.2";
ipaddr = "10.0.2.15";
};
boot.imageFormat = "fit";
rootfsType = "ext4";
filesystem = dir {
hello = {
type = "f";
uid = 7;
gid = 24;
file = "hello world";
};
};
};
}

View File

@ -0,0 +1,21 @@
set timeout 30
spawn socat unix-connect:vm/console -
expect "stop autoboot"
send "\r"
expect "=>"
send "setenv ethact eth1\r"
set fh [open "result/boot.scr"]
while {[gets $fh line] >= 0} {
expect "=>"
send "$line\r"
}
close $fh
expect {
"s6-linux-init" { exit 0 }
timeout { exit 1 }
}

37
tests/tftpboot/test.nix Normal file
View File

@ -0,0 +1,37 @@
{
liminix
}:
let check = deviceName : ubootName :
let derivation = (import liminix {
device = import "${liminix}/devices/${deviceName}/";
liminix-config = ./configuration.nix;
});
img = derivation.outputs.tftpboot;
uboot = derivation.pkgs.${ubootName};
pkgsBuild = derivation.pkgs.pkgsBuildBuild;
phram = 240 * 1024 * 1024;
in pkgsBuild.runCommand "check" {
nativeBuildInputs = with pkgsBuild; [
expect
socat
run-liminix-vm
] ;
} ''
mkdir vm
ln -s ${img} result
run-liminix-vm \
--background ./vm \
--u-boot ${uboot}/u-boot.bin \
--arch ${derivation.pkgs.stdenv.hostPlatform.qemuArch} \
--phram-address $(printf "0x%x" ${toString phram} ) \
--lan "user,tftp=`pwd`" \
--disk-image result/rootfs \
result/uimage result/rootfs
expect ${./script.expect} 2>&1 |tee $out
'';
in {
arm = check "qemu-armv7l" "ubootQemuArm";
aarch64 = check "qemu-aarch64" "ubootQemuAarch64";
}