@@ -66,6 +66,42 @@ require_commands() {
6666 done
6767}
6868
69+ cmdline_set_arg () {
70+ local cmdline=" $1 "
71+ local key=" $2 "
72+ local value=" $3 "
73+ local arg found
74+ local -a args output
75+ read -r -a args <<< " $cmdline"
76+ found=0
77+ output=()
78+ for arg in " ${args[@]} " ; do
79+ if [[ " $arg " == " $key =" * ]]; then
80+ output+=(" $key =$value " )
81+ found=1
82+ else
83+ output+=(" $arg " )
84+ fi
85+ done
86+ if [[ " $found " == " 0" ]]; then
87+ output+=(" $key =$value " )
88+ fi
89+ printf ' %s\n' " ${output[*]} "
90+ }
91+
92+ cmdline_add_flag () {
93+ local cmdline=" $1 "
94+ local flag=" $2 "
95+ local arg
96+ for arg in $cmdline ; do
97+ if [[ " $arg " == " $flag " ]]; then
98+ printf ' %s\n' " $cmdline "
99+ return 0
100+ fi
101+ done
102+ printf ' %s %s\n' " $cmdline " " $flag "
103+ }
104+
69105github_api () {
70106 local url=" $1 "
71107 local -a headers
@@ -170,6 +206,21 @@ partition_values() {
170206 | awk -F: -v part=" $part " ' $1 == part { gsub(/B/, "", $2); gsub(/B/, "", $4); print $2, $4 }'
171207}
172208
209+ partition_uuid () {
210+ local part=" $1 "
211+ local disk_id uuid
212+ if uuid=" $( sfdisk --part-uuid " $IMAGE_FILE " " $part " 2> /dev/null) " && [[ -n " $uuid " ]]; then
213+ printf ' %s\n' " $uuid "
214+ return 0
215+ fi
216+ if disk_id=" $( sfdisk --disk-id " $IMAGE_FILE " 2> /dev/null) " && [[ " $disk_id " == 0x* ]]; then
217+ disk_id=" ${disk_id# 0x} "
218+ printf ' %s-%02x\n' " ${disk_id,,} " " $part "
219+ return 0
220+ fi
221+ return 1
222+ }
223+
173224mount_partitions () {
174225 local boot_start boot_size root_start root_size
175226 mkdir -p " $ROOT_MNT " " $BOOT_MNT "
@@ -221,34 +272,139 @@ copy_boot_file() {
221272 cp " $BOOT_MNT /$name " " $BOOT_FILES /$name "
222273}
223274
275+ copy_optional_boot_file () {
276+ local name=" $1 "
277+ if [[ -f " $BOOT_MNT /$name " ]]; then
278+ cp " $BOOT_MNT /$name " " $BOOT_FILES /$name "
279+ return 0
280+ fi
281+ return 1
282+ }
283+
284+ select_initrd () {
285+ local kernel=" $1 "
286+ local config=" $BOOT_MNT /config.txt"
287+ local explicit candidate
288+ if [[ -f " $config " ]]; then
289+ explicit=" $( awk '
290+ /^[[:space:]]*#/ { next }
291+ /^[[:space:]]*initramfs[[:space:]]+/ { print $2; exit }
292+ ' " $config " ) "
293+ if [[ -n " $explicit " && -f " $BOOT_MNT /$explicit " ]]; then
294+ printf ' %s\n' " $explicit "
295+ return 0
296+ fi
297+ fi
298+
299+ case " $kernel " in
300+ kernel8.img)
301+ for candidate in initramfs8 initramfs_2710 initrd.img; do
302+ [[ -f " $BOOT_MNT /$candidate " ]] && printf ' %s\n' " $candidate " && return 0
303+ done
304+ ;;
305+ kernel7l.img)
306+ for candidate in initramfs7l initramfs_2711 initrd.img; do
307+ [[ -f " $BOOT_MNT /$candidate " ]] && printf ' %s\n' " $candidate " && return 0
308+ done
309+ ;;
310+ kernel7.img)
311+ for candidate in initramfs7 initramfs_2709 initrd.img; do
312+ [[ -f " $BOOT_MNT /$candidate " ]] && printf ' %s\n' " $candidate " && return 0
313+ done
314+ ;;
315+ kernel.img)
316+ for candidate in initramfs initrd.img; do
317+ [[ -f " $BOOT_MNT /$candidate " ]] && printf ' %s\n' " $candidate " && return 0
318+ done
319+ ;;
320+ esac
321+ return 1
322+ }
323+
324+ try_dtmerge () {
325+ local source_dtb=" $1 "
326+ local output_dtb=" $2 "
327+ local dtmerge=" $ROOT_MNT /usr/bin/dtmerge"
328+ local emulator
329+ [[ -x " $dtmerge " ]] || return 1
330+
331+ case " $( file -b " $dtmerge " ) " in
332+ * aarch64* )
333+ emulator=" qemu-aarch64-static"
334+ ;;
335+ * ARM* )
336+ emulator=" qemu-arm-static"
337+ ;;
338+ * )
339+ return 1
340+ ;;
341+ esac
342+ command -v " $emulator " > /dev/null 2>&1 || return 1
343+
344+ " $emulator " -L " $ROOT_MNT " " $dtmerge " " $source_dtb " " $output_dtb " - uart0=on > /dev/null 2>&1 \
345+ || return 1
346+ if [[ -f " $BOOT_MNT /overlays/disable-bt.dtbo" ]]; then
347+ " $emulator " -L " $ROOT_MNT " " $dtmerge " " $output_dtb " " $output_dtb .tmp" \
348+ " $BOOT_MNT /overlays/disable-bt.dtbo" > /dev/null 2>&1 \
349+ || return 1
350+ mv " $output_dtb .tmp" " $output_dtb "
351+ fi
352+ }
353+
354+ prepare_qemu_dtb () {
355+ local dtb=" $1 "
356+ local merged=" qemu-$dtb "
357+ if try_dtmerge " $BOOT_FILES /$dtb " " $BOOT_FILES /$merged " ; then
358+ echo " Prepared QEMU DTB with uart0=on and disable-bt overlay when available: $merged " >&2
359+ printf ' %s\n' " $merged "
360+ return 0
361+ fi
362+ echo " Using unmodified DTB: $dtb " >&2
363+ printf ' %s\n' " $dtb "
364+ }
365+
224366prepare_boot_files () {
225- local kernel dtb cmdline
367+ local kernel dtb qemu_dtb cmdline initrd root_partuuid
226368 mkdir -p " $BOOT_FILES "
227369
228- if [[ -f " $BOOT_MNT /kernel7.img" ]]; then
370+ if [[ -f " $BOOT_MNT /kernel8.img" ]]; then
371+ kernel=" kernel8.img"
372+ dtb=" bcm2710-rpi-3-b.dtb"
373+ elif [[ -f " $BOOT_MNT /kernel7.img" ]]; then
229374 kernel=" kernel7.img"
230375 dtb=" bcm2709-rpi-2-b.dtb"
231376 elif [[ -f " $BOOT_MNT /kernel7l.img" ]]; then
232377 kernel=" kernel7l.img"
233378 dtb=" bcm2711-rpi-4-b.dtb"
234- elif [[ -f " $BOOT_MNT /kernel8.img" ]]; then
235- kernel=" kernel8.img"
236- dtb=" bcm2710-rpi-3-b.dtb"
237379 else
238380 fail " no supported Raspberry Pi kernel found in boot partition"
239381 fi
240382
241383 copy_boot_file " $kernel "
242384 copy_boot_file " $dtb "
385+ qemu_dtb=" $( prepare_qemu_dtb " $dtb " ) "
386+ if initrd=" $( select_initrd " $kernel " ) " ; then
387+ copy_optional_boot_file " $initrd "
388+ printf ' %s\n' " $initrd " > " $BOOT_FILES /initrd-name"
389+ echo " Using initramfs for direct QEMU boot: $initrd "
390+ else
391+ rm -f " $BOOT_FILES /initrd-name"
392+ echo " No initramfs selected for direct QEMU boot"
393+ fi
243394
244395 cmdline=" $( tr -d ' \n' < " $BOOT_MNT /cmdline.txt" ) "
245396 cmdline=" ${cmdline// console=serial0,115200/ console=ttyAMA0,115200} "
246397 cmdline=" ${cmdline// console=serial0/ console=ttyAMA0,115200} "
247398 cmdline=" $( printf ' %s\n' " $cmdline " \
248399 | sed -E ' s/(^| )init=[^ ]+//g; s/(^| )quiet( |$)/ /g; s/[[:space:]]+/ /g; s/^ //; s/ $//' ) "
400+ if root_partuuid=" $( partition_uuid 2) " ; then
401+ cmdline=" $( cmdline_set_arg " $cmdline " root " PARTUUID=$root_partuuid " ) "
402+ fi
403+ cmdline=" $( cmdline_add_flag " $cmdline " rootwait) "
404+ cmdline=" $( cmdline_set_arg " $cmdline " rootfstype ext4) "
249405 printf ' %s systemd.unit=multi-user.target systemd.show_status=1 nr_cpus=1 maxcpus=1\n' " $cmdline " > " $BOOT_FILES /cmdline.txt"
250406 printf ' %s\n' " $kernel " > " $BOOT_FILES /kernel-name"
251- printf ' %s\n' " $dtb " > " $BOOT_FILES /dtb-name"
407+ printf ' %s\n' " $qemu_dtb " > " $BOOT_FILES /dtb-name"
252408}
253409
254410write_guest_probe () {
@@ -399,34 +555,47 @@ UNIT
399555}
400556
401557qemu_command () {
402- local kernel dtb cmdline qemu_bin machine
558+ local kernel dtb cmdline qemu_bin machine cpu initrd
559+ local -a args
403560 kernel=" $( cat " $BOOT_FILES /kernel-name" ) "
404561 dtb=" $( cat " $BOOT_FILES /dtb-name" ) "
405562 cmdline=" $( cat " $BOOT_FILES /cmdline.txt" ) "
406563
407564 if [[ " $kernel " == " kernel8.img" ]]; then
408565 qemu_bin=" qemu-system-aarch64"
409566 machine=" raspi3b"
567+ cpu=" cortex-a53"
410568 else
411569 qemu_bin=" qemu-system-arm"
412570 machine=" raspi2b"
571+ cpu=" "
413572 fi
414573
415574 require_command " $qemu_bin "
416- printf ' %q ' \
417- " $qemu_bin " \
418- -M " $machine " \
419- -smp 1 \
420- -m 1G \
421- -kernel " $BOOT_FILES /$kernel " \
422- -dtb " $BOOT_FILES /$dtb " \
423- -append " $cmdline " \
424- -drive " file=$IMAGE_FILE ,format=raw,if=sd" \
425- -netdev user,id=net0 \
426- -device usb-net,netdev=net0 \
427- -serial mon:stdio \
428- -display none \
575+ args=(" $qemu_bin " -M " $machine " )
576+ if [[ -n " $cpu " ]]; then
577+ args+=(-cpu " $cpu " )
578+ fi
579+ args+=(
580+ -smp 1
581+ -m 1G
582+ -kernel " $BOOT_FILES /$kernel "
583+ -dtb " $BOOT_FILES /$dtb "
584+ )
585+ if [[ -f " $BOOT_FILES /initrd-name" ]]; then
586+ initrd=" $( cat " $BOOT_FILES /initrd-name" ) "
587+ args+=(-initrd " $BOOT_FILES /$initrd " )
588+ fi
589+ args+=(
590+ -append " $cmdline "
591+ -drive " file=$IMAGE_FILE ,format=raw,if=sd"
592+ -netdev " user,id=net0"
593+ -device " usb-net,netdev=net0"
594+ -serial mon:stdio
595+ -display none
429596 -no-reboot
597+ )
598+ printf ' %q ' " ${args[@]} "
430599}
431600
432601run_one_boot () {
@@ -491,7 +660,7 @@ run_boot_smoke() {
491660
492661main () {
493662 local image_archive
494- require_commands curl jq git rsync parted awk mount umount find cp tee timeout
663+ require_commands curl jq git rsync parted sfdisk awk mount umount find cp tee timeout file
495664 require_commands unzip xz gzip
496665 if [[ -n " ${AIRPLANES_IMAGE_PATH:- } " ]]; then
497666 image_archive=" $AIRPLANES_IMAGE_PATH "
0 commit comments