mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-29 20:23:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea315bdb10 | ||
|
|
3f23aa92be | ||
|
|
4984d5ac7f | ||
|
|
d945bb703b | ||
|
|
b047bd2a52 | ||
|
|
efc97f6566 | ||
|
|
39f9c1e166 | ||
|
|
f81de1d3ec | ||
|
|
e7fabfc37d | ||
|
|
956e604dcb | ||
|
|
9d3669b647 | ||
|
|
17a3ca58a0 | ||
|
|
7e2d0cf2f8 |
@@ -1,11 +1,21 @@
|
|||||||
|
|
||||||
menu "Images"
|
menu "Images"
|
||||||
|
|
||||||
|
comment "DDI Based"
|
||||||
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-ddi/Config.in"
|
||||||
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-ddi-disk/Config.in"
|
||||||
|
|
||||||
|
comment "ITB Based"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-rootfs/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-rootfs/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-aux/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-aux/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-qcow/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-qcow/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-gns3a/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-gns3a/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-rauc/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-rauc/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-dl-release/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-dl-release/Config.in"
|
||||||
|
|
||||||
|
comment "General"
|
||||||
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-barebox-esp/Config.in"
|
||||||
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-lvm-stub/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-readme/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-readme/Config.in"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#Simple dracut config for a system without systemd
|
||||||
|
|
||||||
|
#Dracut configuration
|
||||||
|
|
||||||
|
show_modules=yes
|
||||||
|
i18n_install_all=no
|
||||||
|
lvmconf=no
|
||||||
|
mdadmconf=no
|
||||||
|
early_microcode=no
|
||||||
|
hostonly=no
|
||||||
|
hostonly_cmdline=no
|
||||||
|
use_fstab=no
|
||||||
|
kernel_cmdline="rd.break=initqueue"
|
||||||
|
do_strip=no
|
||||||
|
|
||||||
|
# Dracut modules needed
|
||||||
|
add_dracutmodules+=" \
|
||||||
|
busybox \
|
||||||
|
"
|
||||||
|
|
||||||
|
# Modules to ignore
|
||||||
|
omit_dracutmodules+=" \
|
||||||
|
base \
|
||||||
|
bash \
|
||||||
|
biosdevname \
|
||||||
|
btrfs \
|
||||||
|
bluetooth \
|
||||||
|
caps \
|
||||||
|
cifs \
|
||||||
|
connman \
|
||||||
|
crypt \
|
||||||
|
crypt-gpg \
|
||||||
|
dash \
|
||||||
|
dbus-broker \
|
||||||
|
dbus-daemon \
|
||||||
|
dm \
|
||||||
|
dmraid \
|
||||||
|
dmsquash-live-ntfs \
|
||||||
|
dracut-systemd \
|
||||||
|
fcoe \
|
||||||
|
fcoe-uefi \
|
||||||
|
fs-lib \
|
||||||
|
iscsi \
|
||||||
|
i18n \
|
||||||
|
kernel-modules \
|
||||||
|
kernel-modules-extra \
|
||||||
|
lvmmerge \
|
||||||
|
lvm \
|
||||||
|
lunmask \
|
||||||
|
mdraid \
|
||||||
|
memstrack \
|
||||||
|
mksh \
|
||||||
|
modsign \
|
||||||
|
mount-root \
|
||||||
|
multipath \
|
||||||
|
nbd \
|
||||||
|
network-legacy \
|
||||||
|
network-wicked \
|
||||||
|
nfs \
|
||||||
|
nvdimm \
|
||||||
|
nvmf \
|
||||||
|
parse-lunmask \
|
||||||
|
pcsc \
|
||||||
|
qemu \
|
||||||
|
qemu-net \
|
||||||
|
resume \
|
||||||
|
rootfs-block \
|
||||||
|
rngd \
|
||||||
|
shutdown \
|
||||||
|
systemd \
|
||||||
|
systemd-udevd \
|
||||||
|
systemd-coredump \
|
||||||
|
systemd-ask-password \
|
||||||
|
systemd-timedated \
|
||||||
|
systemd-rfkill \
|
||||||
|
systemd-resolved \
|
||||||
|
systemd-hostnamed \
|
||||||
|
systemd-initrd \
|
||||||
|
systemd-integritysetup \
|
||||||
|
systemd-journald \
|
||||||
|
systemd-ldconfig \
|
||||||
|
systemd-networkd \
|
||||||
|
systemd-timesyncd \
|
||||||
|
systemd-veritysetup \
|
||||||
|
systemd-modules-load \
|
||||||
|
systemd-pcrphase \
|
||||||
|
systemd-portabled \
|
||||||
|
systemd-pstore \
|
||||||
|
systemd-sysctl \
|
||||||
|
systemd-repart \
|
||||||
|
systemd-sysext \
|
||||||
|
systemd-sysusers \
|
||||||
|
systemd-tmpfiles \
|
||||||
|
squash \
|
||||||
|
ssh-client \
|
||||||
|
stratis \
|
||||||
|
tpm2-tss \
|
||||||
|
udev-rules \
|
||||||
|
url-lib \
|
||||||
|
usrmount \
|
||||||
|
virtiofs \
|
||||||
|
"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
config IMAGE_BAREBOX_ESP
|
||||||
|
bool "Barebox EFI System Partition"
|
||||||
|
depends on BR2_TARGET_BAREBOX
|
||||||
|
default y if IMAGE_DDI
|
||||||
|
help
|
||||||
|
An EFI System Partition (ESP) with Barebox installed.
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$BR2_ARCH" in
|
||||||
|
x86_64)
|
||||||
|
BOOT_EFI=BOOTX64.EFI
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown EFI boot path for $BR2_ARCH" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "${WORKDIR}"/root
|
||||||
|
rm -rf "${WORKDIR}"/tmp
|
||||||
|
mkdir -p "${WORKDIR}"/tmp
|
||||||
|
|
||||||
|
cat <<EOF >"${WORKDIR}"/genimage.cfg
|
||||||
|
image barebox-esp.vfat {
|
||||||
|
size = "16M"
|
||||||
|
vfat {
|
||||||
|
file EFI/BOOT/$BOOT_EFI {
|
||||||
|
image = $BINARIES_DIR/barebox.efi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Silence genimage warnings
|
||||||
|
config {}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
genimage \
|
||||||
|
--tmppath "${WORKDIR}"/tmp \
|
||||||
|
--rootpath "${WORKDIR}"/root \
|
||||||
|
--inputpath "${WORKDIR}" \
|
||||||
|
--outputpath "${BINARIES_DIR}" \
|
||||||
|
--config "${WORKDIR}"/genimage.cfg
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# image-barebox-esp
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
$(eval $(ix-image))
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
menuconfig IMAGE_DDI_DISK
|
||||||
|
bool "LVM2 based provisioning disk (DDI)"
|
||||||
|
depends on IMAGE_BAREBOX_ESP
|
||||||
|
depends on IMAGE_DDI
|
||||||
|
help
|
||||||
|
Compose a full disk image consisting of an EFI System
|
||||||
|
Partition (ESP) containing Barebox, and an LVM PV in which
|
||||||
|
Infix is installed as an LV.
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p "${WORKDIR}"/root
|
||||||
|
rm -rf "${WORKDIR}"/tmp
|
||||||
|
mkdir -p "${WORKDIR}"/tmp
|
||||||
|
|
||||||
|
"${BR2_EXTERNAL_INFIX_PATH}"/utils/lvm-mkinternal \
|
||||||
|
"${BINARIES_DIR}"/"${ARTIFACT}".raw >"${WORKDIR}"/internal.lvm
|
||||||
|
|
||||||
|
cat <<EOF >"${WORKDIR}"/genimage.cfg
|
||||||
|
|
||||||
|
image ${ARTIFACT}.disk {
|
||||||
|
hdimage {
|
||||||
|
partition-table-type = "gpt"
|
||||||
|
}
|
||||||
|
|
||||||
|
partition esp {
|
||||||
|
partition-type-uuid = "esp"
|
||||||
|
image = "$BINARIES_DIR/barebox-esp.vfat"
|
||||||
|
}
|
||||||
|
|
||||||
|
partition esp-backup {
|
||||||
|
partition-type-uuid = "esp"
|
||||||
|
image = "$BINARIES_DIR/barebox-esp.vfat"
|
||||||
|
}
|
||||||
|
|
||||||
|
partition internal {
|
||||||
|
growfs = "true"
|
||||||
|
partition-type-uuid = "lvm"
|
||||||
|
image = "internal.lvm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Silence genimage warnings
|
||||||
|
config {}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
genimage \
|
||||||
|
--tmppath "${WORKDIR}"/tmp \
|
||||||
|
--rootpath "${WORKDIR}"/root \
|
||||||
|
--inputpath "${WORKDIR}" \
|
||||||
|
--outputpath "${BINARIES_DIR}" \
|
||||||
|
--config "${WORKDIR}"/genimage.cfg
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# image-ddi-disk
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
IMAGE_DDI_DISK_DEPENDENCIES := image-barebox-esp image-ddi
|
||||||
|
|
||||||
|
$(eval $(ix-image))
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
menuconfig IMAGE_DDI
|
||||||
|
bool "Discoverable Disk Image (DDI)"
|
||||||
|
select BR2_TARGET_ROOTFS_SQUASHFS
|
||||||
|
select BR2_PACKAGE_HOST_GENIMAGE
|
||||||
|
help
|
||||||
|
Create a Discoverable Disk Image containing:
|
||||||
|
- SquashFS of the root filesystem
|
||||||
|
- dm-verity hash tree of the root filesystem
|
||||||
|
- DDI compliant JSON signature object of the hash tree
|
||||||
|
|
||||||
|
https://uapi-group.org/specifications/specs/discoverable_disk_image/
|
||||||
|
|
||||||
|
config IMAGE_DDI_KEY
|
||||||
|
string "signing key"
|
||||||
|
depends on IMAGE_DDI
|
||||||
|
default "${BR2_EXTERNAL_INFIX_PATH}/board/common/signing-keys/development/infix.key"
|
||||||
|
help
|
||||||
|
Path to the private RSA key, in PKCS#8 format, used to sign
|
||||||
|
the dm-verity hash tree.
|
||||||
|
|
||||||
|
config IMAGE_DDI_CERT
|
||||||
|
string "signing cert"
|
||||||
|
depends on IMAGE_DDI
|
||||||
|
default "${BR2_EXTERNAL_INFIX_PATH}/board/common/signing-keys/development/infix.crt"
|
||||||
|
help
|
||||||
|
Path to the X509 certificate whose associated public key can
|
||||||
|
validate the authenticity of the generated signature.
|
||||||
|
|
||||||
|
The SHA256 fingerprint of this certificate is recorded
|
||||||
|
alongside the standard PKCS#7 signature in the JSON object,
|
||||||
|
which can be useful to locate corresponding key on systems
|
||||||
|
that lack full X509 parsing capabilities.
|
||||||
|
|
||||||
Executable
+81
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Generate the DDI in two phases. First we create the verity hash tree
|
||||||
|
# and signature, then we collect them together with the rootfs in the
|
||||||
|
# ddi. The reason for this is that genimage (at least up to v19) can
|
||||||
|
# not infer the size of a partition if the image to be placed in it is
|
||||||
|
# created by the same genimage instance. With the two-phase approach,
|
||||||
|
# we work around that problem and can create a DDI without any wasted
|
||||||
|
# space.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
rm -rf "${WORKDIR}"/tmp
|
||||||
|
mkdir -p "${WORKDIR}"/tmp "${WORKDIR}"/verity
|
||||||
|
|
||||||
|
cat <<EOF >"${WORKDIR}"/genimage-verity.cfg
|
||||||
|
image rootfs.verity {
|
||||||
|
verity {
|
||||||
|
image = "rootfs.squashfs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image rootfs.verity-sig {
|
||||||
|
verity-sig {
|
||||||
|
image = "rootfs.verity"
|
||||||
|
cert = "${CERT}"
|
||||||
|
key = "${KEY}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config {}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
genimage \
|
||||||
|
--loglevel 1 \
|
||||||
|
--tmppath "${WORKDIR}"/tmp \
|
||||||
|
--rootpath "${WORKDIR}" \
|
||||||
|
--inputpath "${BINARIES_DIR}" \
|
||||||
|
--outputpath "${WORKDIR}"/verity \
|
||||||
|
--config "${WORKDIR}"/genimage-verity.cfg
|
||||||
|
|
||||||
|
case "${BR2_ARCH}" in
|
||||||
|
"x86_64")
|
||||||
|
arch=x86-64
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: missing mapping from ${BR2_ARCH} to genimage arch" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cat <<EOF >"${WORKDIR}"/genimage-ddi.cfg
|
||||||
|
image ${ARTIFACT}.raw {
|
||||||
|
hdimage {
|
||||||
|
partition-table-type = "gpt"
|
||||||
|
}
|
||||||
|
|
||||||
|
partition root {
|
||||||
|
partition-type-uuid = "root-${arch}"
|
||||||
|
image = "rootfs.squashfs"
|
||||||
|
}
|
||||||
|
partition root-verity {
|
||||||
|
partition-type-uuid = "root-${arch}-verity"
|
||||||
|
image = "${WORKDIR}/verity/rootfs.verity"
|
||||||
|
}
|
||||||
|
partition root-verity-sig {
|
||||||
|
partition-type-uuid = "root-${arch}-verity-sig"
|
||||||
|
image = "${WORKDIR}/verity/rootfs.verity-sig"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config {}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
genimage \
|
||||||
|
--loglevel 1 \
|
||||||
|
--tmppath "${WORKDIR}"/tmp \
|
||||||
|
--rootpath "${WORKDIR}" \
|
||||||
|
--inputpath "${BINARIES_DIR}" \
|
||||||
|
--outputpath "${BINARIES_DIR}" \
|
||||||
|
--config "${WORKDIR}"/genimage-ddi.cfg
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
image rootfs.verity {
|
||||||
|
verity {
|
||||||
|
image = "rootfs.squashfs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image rootfs.verity-sig {
|
||||||
|
verity-sig {
|
||||||
|
image = "rootfs.verity"
|
||||||
|
cert = "@CERT@"
|
||||||
|
key = "@KEY@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image @ARTIFACT@.raw {
|
||||||
|
hdimage {
|
||||||
|
partition-table-type = "gpt"
|
||||||
|
}
|
||||||
|
|
||||||
|
partition root {
|
||||||
|
partition-type-uuid = "root-@ARCH@"
|
||||||
|
image = "rootfs.squashfs"
|
||||||
|
}
|
||||||
|
partition root-verity {
|
||||||
|
partition-type-uuid = "root-@ARCH@-verity"
|
||||||
|
image = "rootfs.verity"
|
||||||
|
}
|
||||||
|
partition root-verity-sig {
|
||||||
|
partition-type-uuid = "root-@ARCH@-verity-sig"
|
||||||
|
image = "rootfs.verity-sig"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# image-ddi
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
IMAGE_DDI_DEPENDENCIES := host-genimage rootfs-squashfs
|
||||||
|
IMAGE_DDI_CONFIG_VARS := KEY CERT
|
||||||
|
|
||||||
|
$(eval $(ix-image))
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
tmpfs /tmp tmpfs mode=0755,nosuid,nodev 0 0
|
||||||
|
tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0
|
||||||
|
tmpfs /media tmpfs mode=1755,nosuid,nodev 0 0
|
||||||
|
tmpfs /mnt/tmp tmpfs defaults 0 0
|
||||||
|
|
||||||
|
# Locate and mount /cfg, /home, /root and /var from the internal
|
||||||
|
# volume, wherever that is located - or, as a last resort, setup tmpfs
|
||||||
|
# mounts at these points. Setup an ephemeral writable overlay on /etc.
|
||||||
|
/usr/libexec/infix/mnt# /mnt/rw helper none 0 0
|
||||||
|
|
||||||
|
# Optional, nice-to-have mounts
|
||||||
|
debugfs /sys/kernel/debug debugfs nofail 0 0
|
||||||
|
tracefs /sys/kernel/tracing tracefs nofail 0 0
|
||||||
|
cfgfs /config configfs nofail,noauto 0 0
|
||||||
|
host /mnt/host 9p nofail,noauto,cache=none,msize=16384 0 0
|
||||||
+211
@@ -0,0 +1,211 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Called from /etc/fstab to ensure we have something writable mounted
|
||||||
|
# at /cfg, /home, /root, and /var.
|
||||||
|
#
|
||||||
|
# In the normal case, the "rw" LV from the "internal" LVM VG is used
|
||||||
|
# to back all persistant storage. In the event that "internal" is
|
||||||
|
# present, but the "rw" LV is missing, one will be provisioned, along
|
||||||
|
# with the required BTRFS subvolumes.
|
||||||
|
#
|
||||||
|
# In all other scenarios where the subvolumes are not available, the
|
||||||
|
# system will fall back to temporary storage for all mount points.
|
||||||
|
#
|
||||||
|
# For /etc, a writable, tmpfs backed, layer is always overlayed on top
|
||||||
|
# of the read-only contents from the OS image.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
nm=$(basename "$0")
|
||||||
|
need_restore=
|
||||||
|
code=0
|
||||||
|
|
||||||
|
logmsg()
|
||||||
|
{
|
||||||
|
logger -k -t "$nm" -p user.crit "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
status()
|
||||||
|
{
|
||||||
|
GREEN="$(printf '\033[1;32m')"
|
||||||
|
RED="$(printf '\033[1;31m')"
|
||||||
|
YELLOW="$(printf '\033[1;33m')"
|
||||||
|
BOLD="$(printf '\033[1m')"
|
||||||
|
RESET="$(printf '\033[0m')"
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
0) color=$GREEN; text=' OK ' ;;
|
||||||
|
1) color=$RED; text='FAIL' ;;
|
||||||
|
2) color=$YELLOW;text='WARN' ;;
|
||||||
|
*) color=$YELLOW;text=' ⋯ ' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '%s[%s%s%s%s]%s ' "$BOLD" "$color" "$text" "$RESET" "$BOLD" "$RESET"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_start()
|
||||||
|
{
|
||||||
|
printf '\r\033[K%s%s' "$(status 3)" "$*" > /dev/console
|
||||||
|
need_restore=YES
|
||||||
|
}
|
||||||
|
|
||||||
|
print_end()
|
||||||
|
{
|
||||||
|
rc=$1; shift
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
printf '\r\033[K%s%s\n' "$(status "$rc")" "$*" > /dev/console
|
||||||
|
else
|
||||||
|
printf '\r%s\n' "$(status "$rc")" > /dev/console
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restore Finit's original progress message so its [ OK ] appears correctly
|
||||||
|
print_restore()
|
||||||
|
{
|
||||||
|
[ "$need_restore" ] || return 0
|
||||||
|
print_start "Mounting filesystems from /etc/fstab"
|
||||||
|
}
|
||||||
|
|
||||||
|
# # External button or bootloader changed kernel command line
|
||||||
|
# check_factory()
|
||||||
|
# {
|
||||||
|
# if [ -f /mnt/cfg/infix/.reset ]; then
|
||||||
|
# return 0;
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# if grep -q 'finit.cond=factory-reset' /proc/cmdline; then
|
||||||
|
# return 0;
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# # Add to your br2-external to extend factory-reset check
|
||||||
|
# if [ ! -x /usr/libexec/infix/check-factory ]; then
|
||||||
|
# return 1;
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# /usr/libexec/infix/check-factory
|
||||||
|
# }
|
||||||
|
|
||||||
|
# factory_reset()
|
||||||
|
# {
|
||||||
|
# find /sys/class/leds/ -type l -exec sh -c 'echo 100 > $0/brightness' {} \;
|
||||||
|
# print_start "Resetting to factory defaults."
|
||||||
|
# logger $opt -p user.notice -t "$nm" "Resetting to factory defaults."
|
||||||
|
|
||||||
|
# rm -rf /mnt/cfg/* /mnt/var/*
|
||||||
|
# sync
|
||||||
|
|
||||||
|
# logger $opt -p user.notice -t "$nm" "Factory reset complete."
|
||||||
|
# print_end 0 "Factory reset complete."
|
||||||
|
# print_restore
|
||||||
|
# }
|
||||||
|
|
||||||
|
subvols="cfg var root home"
|
||||||
|
|
||||||
|
internal_rw_provision()
|
||||||
|
{
|
||||||
|
print_start "Provisioning persistent storage on internal volume"
|
||||||
|
|
||||||
|
lvm lvcreate --name rw --extents 50%FREE internal || {
|
||||||
|
logmsg "No rw LV available, nor could it be created"
|
||||||
|
print_end 1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mkfs.btrfs -L rw /dev/internal/rw || {
|
||||||
|
logmsg "Could not create BTRFS on rw LV"
|
||||||
|
print_end 1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mount -t btrfs /dev/internal/rw /mnt/rw || {
|
||||||
|
logmsg "Failed to mount rw"
|
||||||
|
print_end 1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for subvol in $subvols; do
|
||||||
|
btrfs subvolume create /mnt/rw/@"$subvol" || {
|
||||||
|
logmsg "Failed to create @$subvol on rw"
|
||||||
|
print_end 1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
umount /mnt/rw || {
|
||||||
|
logmsg "Failed to unmount rw"
|
||||||
|
print_end 1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
print_end 0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_rw_activate()
|
||||||
|
{
|
||||||
|
lvm vgs internal || {
|
||||||
|
logmsg "No internal volume available"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
lvm vgchange -ay internal || {
|
||||||
|
logmsg "Unable to bring internal volume online"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# The only condition under which we do BTRFS provisioning is when
|
||||||
|
# the LV is absent. In all other failure scenarios: fall back to
|
||||||
|
# tmpfs and let the user sort it out. This way we do not risk any
|
||||||
|
# loss of data.
|
||||||
|
[ -b /dev/internal/rw ] && return 0
|
||||||
|
|
||||||
|
internal_rw_provision
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_rw_mount()
|
||||||
|
{
|
||||||
|
internal_rw_activate || return 1
|
||||||
|
|
||||||
|
for subvol in $subvols; do
|
||||||
|
mount -t btrfs /dev/internal/rw /"$subvol" -o subvol=@"$subvol" || {
|
||||||
|
logmsg "Failed to mount /$subvol"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpfs_rw_mount()
|
||||||
|
{
|
||||||
|
for subvol in $subvols; do
|
||||||
|
mkdir -p -m 0755 /mnt/tmp/"$subvol"
|
||||||
|
mount /mnt/tmp/"$subvol" /"$subvol" -o bind || {
|
||||||
|
logmsg "Failed to mount temporary /$subvol"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpfs_etc_mount()
|
||||||
|
{
|
||||||
|
mkdir -p -m 0755 /mnt/tmp/etc/
|
||||||
|
tar c -C /etc . | tar x -C /mnt/tmp/etc
|
||||||
|
mount /mnt/tmp/etc /etc -o bind
|
||||||
|
}
|
||||||
|
|
||||||
|
exec >/mnt/tmp/mnt.log 2>&1
|
||||||
|
|
||||||
|
tmpfs_etc_mount || {
|
||||||
|
code=1
|
||||||
|
logmsg "Failed to make /etc writable"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! internal_rw_mount; then
|
||||||
|
code=1
|
||||||
|
print_end 1 "Mounting persistent storage from internal volume"
|
||||||
|
logmsg "Internal volume not found, falling back to tmpfs"
|
||||||
|
|
||||||
|
print_start "Falling back to ephemeral tmpfs storage!"
|
||||||
|
tmpfs_rw_mount
|
||||||
|
print_end $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_restore
|
||||||
|
exit $code
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
config IMAGE_LVM_STUB
|
||||||
|
bool "LVM2 stub image"
|
||||||
|
default y if IMAGE_DDI
|
||||||
|
help
|
||||||
|
An empty LVM2 physical volume attached to the internal
|
||||||
|
volume group. This is useful as a base image for persistent
|
||||||
|
storage in QEMU emulation scenarios where the OS is supplied
|
||||||
|
in a separate image.
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p "${WORKDIR}"/root
|
||||||
|
rm -rf "${WORKDIR}"/tmp
|
||||||
|
mkdir -p "${WORKDIR}"/tmp
|
||||||
|
|
||||||
|
"${BR2_EXTERNAL_INFIX_PATH}"/utils/lvm-mkinternal >"${WORKDIR}"/stub.lvm
|
||||||
|
|
||||||
|
cat <<EOF >"${WORKDIR}"/genimage.cfg
|
||||||
|
image lvm-stub.disk {
|
||||||
|
hdimage {
|
||||||
|
partition-table-type = "gpt"
|
||||||
|
}
|
||||||
|
|
||||||
|
partition internal {
|
||||||
|
growfs = "true"
|
||||||
|
image = "stub.lvm"
|
||||||
|
partition-type-uuid = "lvm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Silence genimage warnings
|
||||||
|
config {}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
genimage \
|
||||||
|
--tmppath "${WORKDIR}"/tmp \
|
||||||
|
--rootpath "${WORKDIR}"/root \
|
||||||
|
--inputpath "${WORKDIR}" \
|
||||||
|
--outputpath "${BINARIES_DIR}" \
|
||||||
|
--config "${WORKDIR}"/genimage.cfg
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# image-lvm-stub
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
$(eval $(ix-image))
|
||||||
@@ -10,6 +10,7 @@ $(1): $$($(2)_DEPENDENCIES)
|
|||||||
PKGDIR=$$($(2)_DIR) \
|
PKGDIR=$$($(2)_DIR) \
|
||||||
WORKDIR=$$(BUILD_DIR)/$(1) \
|
WORKDIR=$$(BUILD_DIR)/$(1) \
|
||||||
BINARIES_DIR=$$(BINARIES_DIR) \
|
BINARIES_DIR=$$(BINARIES_DIR) \
|
||||||
|
BR2_ARCH=$$(BR2_ARCH) \
|
||||||
BR2_EXTERNAL_INFIX_PATH=$$(BR2_EXTERNAL_INFIX_PATH) \
|
BR2_EXTERNAL_INFIX_PATH=$$(BR2_EXTERNAL_INFIX_PATH) \
|
||||||
ARTIFACT=$$(INFIX_ARTIFACT) \
|
ARTIFACT=$$(INFIX_ARTIFACT) \
|
||||||
COMPATIBLE=$$(INFIX_COMPATIBLE) \
|
COMPATIBLE=$$(INFIX_COMPATIBLE) \
|
||||||
@@ -19,6 +20,7 @@ $(1): $$($(2)_DEPENDENCIES)
|
|||||||
|
|
||||||
ifeq ($$($(2)),y)
|
ifeq ($$($(2)),y)
|
||||||
TARGETS_ROOTFS += $(1)
|
TARGETS_ROOTFS += $(1)
|
||||||
|
BR2_ROOTFS_OVERLAY := "$$(realpath $$(pkgdir)/rootfs) $$(call qstrip,$$(BR2_ROOTFS_OVERLAY))"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
check() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
depends() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
# Not sure if this should be handled by buildroot's merged-usr
|
||||||
|
# module. Fix it here for now.
|
||||||
|
ln -s "lib" "${initdir?}/lib64"
|
||||||
|
}
|
||||||
Executable
+279
@@ -0,0 +1,279 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo -ne "\e[31m●\e[0m \e[33m●\e[0m \e[32m●\e[0m Infix Initramfs — " >/dev/console
|
||||||
|
source /etc/os-release >/dev/console
|
||||||
|
echo "$VERSION"
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
getkopt()
|
||||||
|
{
|
||||||
|
grep -q -E "(^| )$1( |$)" /proc/cmdline
|
||||||
|
}
|
||||||
|
|
||||||
|
getkparam()
|
||||||
|
{
|
||||||
|
sed -n "s/.*\<$1=\([^ ]*\).*/\1/p" /proc/cmdline
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_shell()
|
||||||
|
{
|
||||||
|
[ "$(getkparam rd.shell)" = "$1" ] || return 0
|
||||||
|
|
||||||
|
exec </dev/console &>/dev/console
|
||||||
|
echo "Starting debug shell at $1"
|
||||||
|
exec sh -i
|
||||||
|
}
|
||||||
|
|
||||||
|
die()
|
||||||
|
{
|
||||||
|
step="${*:-$step}"
|
||||||
|
|
||||||
|
echo -e "\r\e[0K[\e[31mFAIL\e[0m] $step" >/dev/console
|
||||||
|
echo "<0>ix-initramfs: ERROR: $step" >/dev/kmsg
|
||||||
|
debug_shell error
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
warn()
|
||||||
|
{
|
||||||
|
step="${*:-$step}"
|
||||||
|
|
||||||
|
echo -e "\r\e[0K[\e[33mWARN\e[0m] $step" >/dev/console
|
||||||
|
echo "<5>ix-initramfs: WARNING: $step" >/dev/kmsg
|
||||||
|
debug_shell warning
|
||||||
|
}
|
||||||
|
|
||||||
|
ok()
|
||||||
|
{
|
||||||
|
step="${*:-$step}"
|
||||||
|
|
||||||
|
echo -e "\r\e[0K[\e[32m OK \e[0m] $step" >/dev/console
|
||||||
|
echo "<5>ix-initramfs: $step" >/dev/kmsg
|
||||||
|
}
|
||||||
|
|
||||||
|
begin()
|
||||||
|
{
|
||||||
|
step="$*"
|
||||||
|
echo -ne "[\e[33m ⋯ \e[0m] $step" >/dev/console
|
||||||
|
}
|
||||||
|
|
||||||
|
debug()
|
||||||
|
{
|
||||||
|
echo "<7>ix-initramfs: $*" >/dev/kmsg
|
||||||
|
}
|
||||||
|
|
||||||
|
mountcore()
|
||||||
|
{
|
||||||
|
mount -t proc proc /proc
|
||||||
|
mount -t sysfs sys /sys
|
||||||
|
mount -t devtmpfs dev /dev
|
||||||
|
}
|
||||||
|
|
||||||
|
mountroot()
|
||||||
|
{
|
||||||
|
mkdir /newroot
|
||||||
|
mount "$1" /newroot || \
|
||||||
|
die "Unable to mount rootfs on $1"
|
||||||
|
|
||||||
|
ok "Mounting root filesystem on $(basename $1)"
|
||||||
|
}
|
||||||
|
|
||||||
|
switchroot()
|
||||||
|
{
|
||||||
|
local innerinit=$(getkparam init)
|
||||||
|
|
||||||
|
ok "Switching to root filesystem"
|
||||||
|
exec switch_root /newroot ${innerinit:-/sbin/init}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_get_part()
|
||||||
|
{
|
||||||
|
local _i _pv
|
||||||
|
|
||||||
|
for _i in $(seq 50); do
|
||||||
|
_pv=$(lvm pvs --reportformat json \
|
||||||
|
| jq -r '.report[].pv[] | select(.vg_name == "internal") | .pv_name')
|
||||||
|
if [ "$_pv" ]; then
|
||||||
|
[ $_i -gt 5 ] && ok
|
||||||
|
echo "$_pv"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ $_i -eq 5 ] && begin "Waiting for the internal volume to come online"
|
||||||
|
sleep .2
|
||||||
|
done
|
||||||
|
|
||||||
|
warn "Proceeding without the internal volume"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_inflate()
|
||||||
|
{
|
||||||
|
local _dev _growfs _index _part
|
||||||
|
|
||||||
|
getkopt rd.nointernal && return 0
|
||||||
|
|
||||||
|
GPT_PART_GROWFS_BIT=59
|
||||||
|
|
||||||
|
_part=$(internal_get_part)
|
||||||
|
[ "$_part" ] || return 0
|
||||||
|
|
||||||
|
_index=$(cat /sys/class/block/$(basename "$_part")/partition)
|
||||||
|
[ "$_index" ] || return 1
|
||||||
|
|
||||||
|
_dev=/dev/$(basename $(realpath /sys/class/block/$(basename "$_part")/../))
|
||||||
|
[ -b "$_dev" ] || return 1
|
||||||
|
|
||||||
|
sgdisk "$_dev" -A "$_index":get:$GPT_PART_GROWFS_BIT \
|
||||||
|
| grep -q "$_index:$GPT_PART_GROWFS_BIT:1" \
|
||||||
|
|| return 0
|
||||||
|
|
||||||
|
begin "Inflating internal VG in $_part"
|
||||||
|
|
||||||
|
# First, expand the GPT to cover the entire disk and expand the
|
||||||
|
# LVM partition as much as possible.
|
||||||
|
if ! sgdisk "$_dev" \
|
||||||
|
--disk-guid=random \
|
||||||
|
--set-alignment=1 \
|
||||||
|
--move-second-header \
|
||||||
|
--delete="$_index" \
|
||||||
|
--largest-new="$_index" --typecode="$_index":8e00 \
|
||||||
|
>/tmp/internal-inflate.log 2>&1; then
|
||||||
|
warn "Failed to inflate GPT on $_dev"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! lvm pvresize "$_part" >>/tmp/internal-inflate.log 2>&1; then
|
||||||
|
warn "Failed to resize PV $_part"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok "Inflated internal VG in $_part"
|
||||||
|
}
|
||||||
|
|
||||||
|
addparts()
|
||||||
|
{
|
||||||
|
local _disk="$1"
|
||||||
|
local _partscan="/sys/class/block/"$(basename "$_disk")/partscan
|
||||||
|
|
||||||
|
[ -f "$_partscan" ] && [ $(cat "$_partscan") -eq 1 ] && return
|
||||||
|
|
||||||
|
kpartx -a "$_disk" 2>/dev/null || die "addparts: Unable to add partitions from $_disk"
|
||||||
|
}
|
||||||
|
|
||||||
|
gptuuid_probe()
|
||||||
|
{
|
||||||
|
local _uuid=$(echo "$1" | sed -e 's/^GPTUUID=//' | tr ABCDEF abcdef)
|
||||||
|
local _cand _disk _initrd
|
||||||
|
|
||||||
|
[ -f /initrd.image ] && _initrd=/initrd.image
|
||||||
|
|
||||||
|
for _disk in $_initrd $(find /dev/ -type b); do
|
||||||
|
_cand=$(ddi "$_disk" inspect uuid | tr ABCDEF abcdef)
|
||||||
|
[ $? -eq 0 ] || continue
|
||||||
|
|
||||||
|
if [ "$_cand" = "$_uuid" ]; then
|
||||||
|
ok "Located $_uuid in $_disk"
|
||||||
|
echo "$_disk"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
die "gptuuid_probe: Unable to find disk $_uuid"
|
||||||
|
}
|
||||||
|
|
||||||
|
ddi_probe()
|
||||||
|
{
|
||||||
|
local _disk="$1"
|
||||||
|
local _dm="$(basename $_disk).root"
|
||||||
|
local _hash=$(getkparam rd.ddi.roothash)
|
||||||
|
local _v _trust
|
||||||
|
|
||||||
|
if [ -n "$_hash" ]; then
|
||||||
|
ok "Trusting pre-authenticated root hash"
|
||||||
|
_v="-V $_hash"
|
||||||
|
else
|
||||||
|
_v="-v"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_trust=$(ddi "$_disk" part root open $_v "$_dm" 2>&1 \
|
||||||
|
|| die "ddi_probe: veritysetup of $_disk failed")
|
||||||
|
|
||||||
|
ok "$_trust"
|
||||||
|
ok "Opened verity protected root from $(basename $_disk)"
|
||||||
|
echo /dev/mapper/"$_dm"
|
||||||
|
}
|
||||||
|
|
||||||
|
lvm_probe()
|
||||||
|
{
|
||||||
|
local _vg=$(dirname "$1") _lv=$(basename "$1")
|
||||||
|
|
||||||
|
lvm vgchange -ay "$_vg" &>/dev/null || \
|
||||||
|
die "lvm_probe: Failed to activate the $_vg VG"
|
||||||
|
|
||||||
|
[ -b /dev/"$1" ] || die "lvm_probe: Unable to locate the $_lv LV in $_vg"
|
||||||
|
|
||||||
|
echo /dev/"$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
lo_probe()
|
||||||
|
{
|
||||||
|
local _lo=$(losetup -f || die "probe_lo: found no free loop device for $1")
|
||||||
|
losetup -P "$_lo" "$1" || die "probe_lo: losetup of $1 to $_lo failed"
|
||||||
|
|
||||||
|
debug "lo_probe: setup $_lo backed by $1"
|
||||||
|
echo "$_lo"
|
||||||
|
}
|
||||||
|
|
||||||
|
probe()
|
||||||
|
{
|
||||||
|
local _real _kind
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
/*)
|
||||||
|
_real=$(realpath "$1")
|
||||||
|
_kind=$(stat -c %F "$_real" 2>/dev/null || true)
|
||||||
|
case "$_kind" in
|
||||||
|
"block special file")
|
||||||
|
addparts "$_real"
|
||||||
|
echo "$_real"
|
||||||
|
;;
|
||||||
|
"regular file")
|
||||||
|
lo_probe "$_real"
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
die "Unknown root \"$1\""
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unsupported root \"$1\": $_kind"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
lvm)
|
||||||
|
shift
|
||||||
|
probe $(lvm_probe "$@")
|
||||||
|
;;
|
||||||
|
ddi)
|
||||||
|
shift
|
||||||
|
ddi_probe $(probe "$@")
|
||||||
|
;;
|
||||||
|
GPTUUID=*)
|
||||||
|
gptuuid_probe "$@"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
mountcore
|
||||||
|
|
||||||
|
debug_shell internal
|
||||||
|
internal_inflate
|
||||||
|
|
||||||
|
debug_shell probe
|
||||||
|
rootdev=$(probe $(getkparam root | sed -e 's/:/ /g'))
|
||||||
|
|
||||||
|
debug_shell mount
|
||||||
|
mountroot "$rootdev"
|
||||||
|
|
||||||
|
debug_shell switchroot
|
||||||
|
switchroot
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
progs="blkid ddi dmsetup kpartx jq lvm openssl sgdisk veritysetup"
|
||||||
|
|
||||||
|
check() {
|
||||||
|
require_binaries $progs || return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
depends() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
inst_multiple $progs
|
||||||
|
inst '/etc/os-release'
|
||||||
|
inst '/etc/rauc/keys/*'
|
||||||
|
|
||||||
|
cp "$moddir/init" "${initdir?}/init"
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
mainmenu "QEMU @ARCH@ Virtualization"
|
||||||
|
|
||||||
|
config QEMU_@ARCH@
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
|
config QEMU_ARCH
|
||||||
|
string
|
||||||
|
default "@ARCH@"
|
||||||
|
|
||||||
|
config QEMU_VIRTIO_BUS
|
||||||
|
string
|
||||||
|
default "device" if QEMU_arm
|
||||||
|
default "pci"
|
||||||
|
|
||||||
|
config QEMU_BIN_DDI
|
||||||
|
string
|
||||||
|
default "@IMAGE@"
|
||||||
|
|
||||||
|
config QEMU_BIN_DISK
|
||||||
|
string
|
||||||
|
default "@DISK@"
|
||||||
|
|
||||||
|
config QEMU_BIN_ESP
|
||||||
|
string
|
||||||
|
default "@ESP@"
|
||||||
|
|
||||||
|
config QEMU_BIN_KERNEL
|
||||||
|
string
|
||||||
|
depends on QEMU_LOADER_QEMU
|
||||||
|
default "../zImage" if QEMU_arm
|
||||||
|
default "../Image" if QEMU_aarch64
|
||||||
|
default "../bzImage" if QEMU_x86_64
|
||||||
|
|
||||||
|
config QEMU_BIN_LVM_STUB
|
||||||
|
string
|
||||||
|
default "../lvm-stub.disk"
|
||||||
|
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Loader"
|
||||||
|
default QEMU_LOADER_QEMU
|
||||||
|
|
||||||
|
config QEMU_LOADER_QEMU
|
||||||
|
bool "QEMU"
|
||||||
|
|
||||||
|
config QEMU_LOADER_OVMF
|
||||||
|
bool "OVMF (UEFI)"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config QEMU_BIN_BIOS
|
||||||
|
string
|
||||||
|
depends on !QEMU_LOADER_KERNEL
|
||||||
|
default "OVMF.fd" if QEMU_LOADER_OVMF
|
||||||
|
|
||||||
|
menu "Machine"
|
||||||
|
|
||||||
|
config QEMU_MACHINE
|
||||||
|
string "Machine"
|
||||||
|
default "pc" if QEMU_x86_64
|
||||||
|
default "virt"
|
||||||
|
|
||||||
|
config QEMU_CPU
|
||||||
|
string "CPU"
|
||||||
|
default "host" if QEMU_x86_64
|
||||||
|
default "cortex-a53" if QEMU_aarch64
|
||||||
|
default "max"
|
||||||
|
|
||||||
|
config QEMU_RAM
|
||||||
|
string "RAM size (k/M/G)"
|
||||||
|
default "384M"
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Console"
|
||||||
|
default QEMU_CONSOLE_VIRTIO
|
||||||
|
|
||||||
|
config QEMU_CONSOLE_VIRTIO
|
||||||
|
bool "Virtio (hvc0)"
|
||||||
|
|
||||||
|
config QEMU_CONSOLE_SERIAL
|
||||||
|
bool "Serial (ttyS0/ttyAMA0)"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config QEMU_CONSOLE
|
||||||
|
string
|
||||||
|
default "hvc0" if QEMU_CONSOLE_VIRTIO
|
||||||
|
default "ttyAMA0" if QEMU_arm
|
||||||
|
default "ttyAMA0" if QEMU_aarch64
|
||||||
|
default "ttyS0"
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Disks & Filesystems"
|
||||||
|
|
||||||
|
config QEMU_DISK_INITRD
|
||||||
|
bool "Use the DDI as initrd"
|
||||||
|
depends on QEMU_LOADER_QEMU
|
||||||
|
help
|
||||||
|
Pass, and boot from, the DDI as the initial RAM disk.
|
||||||
|
|
||||||
|
This is useful to test netbooting scenarios, e.g., in
|
||||||
|
combination with an empty system disk to simulate an initial
|
||||||
|
deployment.
|
||||||
|
|
||||||
|
comment "System disk"
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Interface"
|
||||||
|
default QEMU_DISK_SYS_IF_VIRTIO
|
||||||
|
|
||||||
|
config QEMU_DISK_SYS_IF_VIRTIO
|
||||||
|
bool "virtio"
|
||||||
|
help
|
||||||
|
Attach system disks using virtio block devices.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Contents"
|
||||||
|
default QEMU_DISK_SYS_SPLIT
|
||||||
|
|
||||||
|
config QEMU_DISK_SYS_EMPTY
|
||||||
|
bool "Empty disk"
|
||||||
|
help
|
||||||
|
Attach an empty disk.
|
||||||
|
|
||||||
|
This is useful for testing things like installing Infix from a
|
||||||
|
USB mass storage device (see "USB Mass Storage" below).
|
||||||
|
|
||||||
|
config QEMU_DISK_SYS_FULL
|
||||||
|
bool "Full system disk"
|
||||||
|
help
|
||||||
|
Use the full system disk containing:
|
||||||
|
- EFI partition (and backup) with Barebox
|
||||||
|
- LVM PV with Infix installed
|
||||||
|
|
||||||
|
This is useful when testing system upgrades, fallback
|
||||||
|
mechanisms related to corrupt disks etc.
|
||||||
|
|
||||||
|
WARNING: Usage of this option is fraught with peril as
|
||||||
|
incremental builds of Infix are likely to cause corruption in
|
||||||
|
the QCoW2 layer. If you do not understand the meaning of this
|
||||||
|
you most likely to NOT want to make use of this feature.
|
||||||
|
|
||||||
|
config QEMU_DISK_SYS_NONE
|
||||||
|
bool "None"
|
||||||
|
help
|
||||||
|
Do not attach any system disk.
|
||||||
|
|
||||||
|
This is useful for testing how Infix behaves when no persistent
|
||||||
|
storage is available - a common scenario during bringup of a
|
||||||
|
new board.
|
||||||
|
|
||||||
|
config QEMU_DISK_SYS_SPLIT
|
||||||
|
bool "Split ESP/DDI/LVM"
|
||||||
|
help
|
||||||
|
Attach the EFI System partition, containing Barebox; the raw
|
||||||
|
DDI image; and an (initially empty) LVM stub for persistent
|
||||||
|
storage - each as a separate disk.
|
||||||
|
|
||||||
|
This is the simplest way of testing out incremental builds of
|
||||||
|
Infix. Since the DDI is attached as a raw read-only disk, there
|
||||||
|
is no risk of CoW corruption like with a full system disk.
|
||||||
|
|
||||||
|
NOTE: In this setup, the size below refers to the size of the
|
||||||
|
LVM stub.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config QEMU_DISK_SYS_SIZE
|
||||||
|
string "Size (k/M/G)"
|
||||||
|
default "8G"
|
||||||
|
|
||||||
|
comment "USB mass storage"
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Contents"
|
||||||
|
default QEMU_DISK_USB_NONE
|
||||||
|
|
||||||
|
config QEMU_DISK_USB_DISK
|
||||||
|
bool "Full system disk"
|
||||||
|
help
|
||||||
|
Attach the full system disk containing:
|
||||||
|
- EFI partition (and backup) with Barebox
|
||||||
|
- LVM PV with Infix installed
|
||||||
|
|
||||||
|
config QEMU_DISK_USB_NONE
|
||||||
|
bool "None"
|
||||||
|
help
|
||||||
|
Do not attach any disk over USB.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config QEMU_DISK_USB_SIZE
|
||||||
|
string "Size (k/M/G)"
|
||||||
|
depends on !QEMU_DISK_USB_NONE
|
||||||
|
default "4G"
|
||||||
|
|
||||||
|
comment "Host filesystem passthrough (9P)"
|
||||||
|
|
||||||
|
config QEMU_DISK_HOST
|
||||||
|
string "Path"
|
||||||
|
default "/tmp"
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
menu "Networking"
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Mode"
|
||||||
|
default QEMU_NET_USER
|
||||||
|
|
||||||
|
config QEMU_NET_BRIDGE
|
||||||
|
bool "Bridged"
|
||||||
|
|
||||||
|
config QEMU_NET_NONE
|
||||||
|
bool "None"
|
||||||
|
|
||||||
|
config QEMU_NET_ROCKER
|
||||||
|
bool "Rocker"
|
||||||
|
|
||||||
|
config QEMU_NET_TAP
|
||||||
|
bool "TAP"
|
||||||
|
|
||||||
|
config QEMU_NET_USER
|
||||||
|
bool "User"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config QEMU_NET_MODE
|
||||||
|
string
|
||||||
|
default "bridge" if QEMU_NET_BRIDGE
|
||||||
|
default "none" if QEMU_NET_NONE
|
||||||
|
default "rocker" if QEMU_NET_ROCKER
|
||||||
|
default "tap" if QEMU_NET_TAP
|
||||||
|
default "user" if QEMU_NET_USER
|
||||||
|
|
||||||
|
config QEMU_NET_MODEL
|
||||||
|
string "Interface model"
|
||||||
|
default "virtio-net-device" if QEMU_arm
|
||||||
|
default "virtio-net-pci"
|
||||||
|
help
|
||||||
|
The default virtio NIC works for most use-cases, but if you
|
||||||
|
want to play with low-level stuff like ethtool, you might
|
||||||
|
want to test the Intel 82545EM driver, e1000.
|
||||||
|
|
||||||
|
Note: ARM 32-bit uses virtio-net-device (MMIO) by default.
|
||||||
|
|
||||||
|
config QEMU_NET_BRIDGE_DEV
|
||||||
|
string "Bridge device"
|
||||||
|
depends on QEMU_NET_BRIDGE
|
||||||
|
default "virbr0"
|
||||||
|
|
||||||
|
config QEMU_NET_USER_OPTS
|
||||||
|
string "User mode options"
|
||||||
|
depends on QEMU_NET_USER
|
||||||
|
help
|
||||||
|
Extra -nic user,<OPTIONS>
|
||||||
|
|
||||||
|
config QEMU_NET_TAP_N
|
||||||
|
int "Number of TAPs"
|
||||||
|
depends on QEMU_NET_TAP
|
||||||
|
default 1
|
||||||
|
|
||||||
|
config QEMU_NET_PORTS
|
||||||
|
int "Number of Rocker switch ports"
|
||||||
|
depends on QEMU_NET_ROCKER
|
||||||
|
default 10
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
config QEMU_EXTRA
|
||||||
|
string "Extra QEMU options"
|
||||||
|
|
||||||
|
config QEMU_APPEND
|
||||||
|
string "Extra kernel options"
|
||||||
|
depends on QEMU_LOADER_QEMU
|
||||||
Executable
+480
@@ -0,0 +1,480 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# This script can be used to start an Infix OS image in Qemu. It reads
|
||||||
|
# either a .config, generated from Config.in, or qemu.cfg from a release
|
||||||
|
# tarball, for the required configuration data.
|
||||||
|
#
|
||||||
|
# Debian/Ubuntu users can change the configuration post-release, install
|
||||||
|
# the kconfig-frontends package:
|
||||||
|
#
|
||||||
|
# sudo apt install kconfig-frontends
|
||||||
|
#
|
||||||
|
# and then call this script with:
|
||||||
|
#
|
||||||
|
# ./run.sh -c
|
||||||
|
#
|
||||||
|
# To bring up a menuconfig dialog. Select `Exit` and save the changes.
|
||||||
|
# For more help, see:_
|
||||||
|
#
|
||||||
|
# ./run.sh -h
|
||||||
|
#
|
||||||
|
# shellcheck disable=SC3037
|
||||||
|
|
||||||
|
# Add /sbin to PATH for mkfs.ext4 and such (not default in debian)
|
||||||
|
export PATH="/sbin:/usr/sbin:$PATH"
|
||||||
|
|
||||||
|
qdir=$(dirname "$(readlink -f "$0")")
|
||||||
|
imgdir=$(readlink -f "${qdir}/..")
|
||||||
|
prognm=$(basename "$0")
|
||||||
|
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
cat <<EOF
|
||||||
|
usage: $prognm [OPTIONS] [-- KERNEL-ARGS]
|
||||||
|
|
||||||
|
Start Infix in a VM.
|
||||||
|
|
||||||
|
Any arguments after -- are passed to the kernel, provided that QEMU's
|
||||||
|
native loader is being used (i.e., not UEFI, for example). This
|
||||||
|
includes a second --, which the kernel uses to delimit between kernel
|
||||||
|
arguments and those passed to the init process.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-0
|
||||||
|
Clear any copy-on-write layers, resetting all disks to their
|
||||||
|
initial states, and exit.
|
||||||
|
|
||||||
|
-c
|
||||||
|
Run menuconfig to change Qemu settings. This requires the
|
||||||
|
'kconfig-frontends' package (Debian/Ubuntu).
|
||||||
|
|
||||||
|
-G
|
||||||
|
Skip config generation. This is useful if you are testing out new
|
||||||
|
QEMU features by manually modifying qemu.cfg.
|
||||||
|
|
||||||
|
-h
|
||||||
|
Show this help message
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
$prognm -- loglevel=4 -- finit.debug
|
||||||
|
|
||||||
|
Will set the kernel's loglevel to 4, and pass finit.debug as an
|
||||||
|
argument to PID 1.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
die()
|
||||||
|
{
|
||||||
|
echo "$prognm: $*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
binpath()
|
||||||
|
{
|
||||||
|
case "$1" in
|
||||||
|
./*|../*)
|
||||||
|
# Relative paths are relative to the location of .config
|
||||||
|
printf "$qdir/$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
q()
|
||||||
|
{
|
||||||
|
local _cmd="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
case "$_cmd" in
|
||||||
|
sect)
|
||||||
|
printf ' \\\n\t' >>"$qdir"/qemu.sh
|
||||||
|
|
||||||
|
case $# in
|
||||||
|
1)
|
||||||
|
printf -- "-$1" >>"$qdir"/qemu.sh
|
||||||
|
_delim=" "
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
printf -- "-$1 $2" >>"$qdir"/qemu.sh
|
||||||
|
_delim=","
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "q sect: Invalid arguments"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
param)
|
||||||
|
[ $# -eq 2 ] || die "q param: Takes exactly two arguments"
|
||||||
|
printf -- "$_delim$1=$2" >>"$qdir"/qemu.sh
|
||||||
|
_delim=","
|
||||||
|
;;
|
||||||
|
option)
|
||||||
|
[ $# -eq 1 ] || die "q option: Takes exactly one argument"
|
||||||
|
printf -- "$_delim$1" >>"$qdir"/qemu.sh
|
||||||
|
_delim=","
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "q: Unknown command: $_cmd"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
q_sect_device_virtio()
|
||||||
|
{
|
||||||
|
q sect device virtio-$1-$QEMU_VIRTIO_BUS
|
||||||
|
}
|
||||||
|
|
||||||
|
q_add_disk()
|
||||||
|
{
|
||||||
|
if [ "$QEMU_DISK_SYS_IF_VIRTIO" ]; then
|
||||||
|
q_sect_device_virtio blk
|
||||||
|
q param drive "$1"
|
||||||
|
else
|
||||||
|
die "Unknown system disk interface"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
q_sect_device_usb()
|
||||||
|
{
|
||||||
|
if [ -z "$usb_bus_added" ]; then
|
||||||
|
q sect usb
|
||||||
|
q sect device usb-ehci
|
||||||
|
q param id ehci
|
||||||
|
usb_bus_added=YES
|
||||||
|
fi
|
||||||
|
|
||||||
|
q sect device "$1"
|
||||||
|
q param bus ehci.0
|
||||||
|
}
|
||||||
|
|
||||||
|
qcowed()
|
||||||
|
{
|
||||||
|
local _qcow="$qdir"/"$1".qcow2
|
||||||
|
local _base _size
|
||||||
|
|
||||||
|
if [ -f "$_qcow" ] && qemu-img check -q "$_qcow"; then
|
||||||
|
echo "$_qcow"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$_qcow"
|
||||||
|
|
||||||
|
case $# in
|
||||||
|
2)
|
||||||
|
_size="$2"
|
||||||
|
|
||||||
|
qemu-img create -q -f qcow2 "$_qcow" "$_size" \
|
||||||
|
|| die "Unable to create $1"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
|
||||||
|
_base="$2"
|
||||||
|
_size="$3"
|
||||||
|
|
||||||
|
[ "$_size" = "auto" ] && _size=
|
||||||
|
|
||||||
|
qemu-img create -q -f qcow2 -F raw \
|
||||||
|
-o backing_file="$_base" "$_qcow" $_size \
|
||||||
|
|| die "Unable to create CoW layer for $_base"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "qcowed: usage: qcowed <name> [<backing-file>] <size>"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "$_qcow"
|
||||||
|
}
|
||||||
|
|
||||||
|
append()
|
||||||
|
{
|
||||||
|
echo -n " $*" >>"$qdir"/append
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_machine()
|
||||||
|
{
|
||||||
|
q sect machine
|
||||||
|
q param type "$QEMU_MACHINE"
|
||||||
|
q param accel kvm:tcg
|
||||||
|
|
||||||
|
q sect cpu "$QEMU_CPU"
|
||||||
|
|
||||||
|
q sect m
|
||||||
|
q param size "$QEMU_RAM"
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_loader()
|
||||||
|
{
|
||||||
|
if [ "$QEMU_LOADER_QEMU" ]; then
|
||||||
|
q sect kernel $(binpath "$QEMU_BIN_KERNEL")
|
||||||
|
elif [ "$QEMU_LOADER_OVMF" ]; then
|
||||||
|
q sect bios $(binpath "$QEMU_BIN_BIOS")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_serial()
|
||||||
|
{
|
||||||
|
q sect display none
|
||||||
|
|
||||||
|
q_sect_device_virtio serial
|
||||||
|
|
||||||
|
q sect chardev stdio
|
||||||
|
q param id console0
|
||||||
|
q param mux on
|
||||||
|
|
||||||
|
q sect mon
|
||||||
|
q param chardev console0
|
||||||
|
|
||||||
|
case "$QEMU_CONSOLE" in
|
||||||
|
hvc0)
|
||||||
|
q sect device virtconsole
|
||||||
|
q param nr 0
|
||||||
|
q param name console
|
||||||
|
q param chardev console0
|
||||||
|
;;
|
||||||
|
ttyS0|ttyAMA0)
|
||||||
|
q sect serial chardev:console0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unsupported console: $QEMU_CONSOLE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
append console="$QEMU_CONSOLE"
|
||||||
|
|
||||||
|
[ "$V" ] && append debug || append loglevel=4
|
||||||
|
}
|
||||||
|
|
||||||
|
gpt_uuid()
|
||||||
|
{
|
||||||
|
sgdisk "$1" -p | awk '
|
||||||
|
BEGIN { err = 1; } END { exit(err); }
|
||||||
|
/^Creating new GPT/ { exit; }
|
||||||
|
|
||||||
|
/^Disk identifier \(GUID\): / {
|
||||||
|
print($4); err = 0; exit;
|
||||||
|
}' || die "Unable to determine GPT UUID of $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disk_sys_empty()
|
||||||
|
{
|
||||||
|
q sect drive
|
||||||
|
q param id disk-sys
|
||||||
|
q param format qcow2
|
||||||
|
q param if none
|
||||||
|
q param file $(qcowed disk-sys "$QEMU_DISK_SYS_SIZE")
|
||||||
|
|
||||||
|
q_add_disk disk-sys
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disk_sys_full()
|
||||||
|
{
|
||||||
|
q sect drive
|
||||||
|
q param id disk-sys
|
||||||
|
q param format qcow2
|
||||||
|
q param if none
|
||||||
|
q param file $(qcowed disk-sys $(binpath "$QEMU_BIN_DISK") \
|
||||||
|
"$QEMU_DISK_SYS_SIZE")
|
||||||
|
|
||||||
|
q_add_disk disk-sys
|
||||||
|
|
||||||
|
append root=ddi:lvm:internal/$(basename "$QEMU_BIN_DDI")
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disk_sys_split()
|
||||||
|
{
|
||||||
|
# EFI System Partition
|
||||||
|
q sect drive
|
||||||
|
q param id disk-esp
|
||||||
|
q param format qcow2
|
||||||
|
q param if none
|
||||||
|
q param file $(qcowed disk-esp $(binpath "$QEMU_BIN_ESP") auto)
|
||||||
|
|
||||||
|
q_add_disk disk-esp
|
||||||
|
|
||||||
|
# LVM stub
|
||||||
|
q sect drive
|
||||||
|
q param id disk-sys
|
||||||
|
q param format qcow2
|
||||||
|
q param if none
|
||||||
|
q param file $(qcowed disk-sys $(binpath "$QEMU_BIN_LVM_STUB") \
|
||||||
|
"$QEMU_DISK_SYS_SIZE")
|
||||||
|
|
||||||
|
q_add_disk disk-sys
|
||||||
|
|
||||||
|
# DDI (ro)
|
||||||
|
q sect drive
|
||||||
|
q param id disk-ddi
|
||||||
|
q param format raw
|
||||||
|
q param file $(binpath "$QEMU_BIN_DDI")
|
||||||
|
q param if none
|
||||||
|
q param read-only on
|
||||||
|
|
||||||
|
q_add_disk disk-ddi
|
||||||
|
|
||||||
|
append root=ddi:GPTUUID=$(gpt_uuid $(binpath "$QEMU_BIN_DDI"))
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disk_sys()
|
||||||
|
{
|
||||||
|
[ "$QEMU_DISK_SYS_NONE" ] && return
|
||||||
|
|
||||||
|
if [ "$QEMU_DISK_SYS_EMPTY" ]; then
|
||||||
|
gen_disk_sys_empty
|
||||||
|
elif [ "$QEMU_DISK_SYS_FULL" ]; then
|
||||||
|
gen_disk_sys_full
|
||||||
|
elif [ "$QEMU_DISK_SYS_SPLIT" ]; then
|
||||||
|
gen_disk_sys_split
|
||||||
|
else
|
||||||
|
die "Unknown system disk mode"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disk_usb()
|
||||||
|
{
|
||||||
|
[ "$QEMU_DISK_USB_NONE" ] && return
|
||||||
|
|
||||||
|
if [ "$QEMU_DISK_USB_DISK" ]; then
|
||||||
|
q sect drive
|
||||||
|
q param id disk-usb
|
||||||
|
q param format qcow2
|
||||||
|
q param file $(qcowed disk-usb \
|
||||||
|
$(binpath "$QEMU_BIN_DISK") \
|
||||||
|
"$QEMU_DISK_USB_SIZE")
|
||||||
|
q param if none
|
||||||
|
|
||||||
|
q_sect_device_usb usb-storage
|
||||||
|
q param drive disk-usb
|
||||||
|
else
|
||||||
|
die "Unknown USB attachment"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disk_initrd()
|
||||||
|
{
|
||||||
|
[ "$QEMU_DISK_INITRD" ] || return
|
||||||
|
|
||||||
|
q sect initrd $(binpath "$QEMU_BIN_DDI")
|
||||||
|
append root=ddi:/initrd.image
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_is_available()
|
||||||
|
{
|
||||||
|
[ "$QEMU_DISK_SYS_FULL" ] || [ "$QEMU_DISK_SYS_SPLIT" ] \
|
||||||
|
|| [ "$QEMU_DISK_USB_DISK" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_disks()
|
||||||
|
{
|
||||||
|
gen_disk_sys
|
||||||
|
gen_disk_usb
|
||||||
|
|
||||||
|
gen_disk_initrd
|
||||||
|
|
||||||
|
internal_is_available || append rd.nointernal
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_gdb()
|
||||||
|
{
|
||||||
|
# Create a UNIX socket on the host that is connected to a virtio
|
||||||
|
# console in the guest, which gdbserver can attach to for
|
||||||
|
# userspace debugging.
|
||||||
|
q sect chardev socket
|
||||||
|
q param id gdbserver
|
||||||
|
q param path "$qdir"/gdbserver.sock
|
||||||
|
q param server on
|
||||||
|
q param wait off
|
||||||
|
|
||||||
|
q sect device virtconsole
|
||||||
|
q param nr 1
|
||||||
|
q param name gdbserver
|
||||||
|
q param chardev gdbserver
|
||||||
|
|
||||||
|
# Create a UNIX socket on the host that is connected to QEMU's GDB
|
||||||
|
# stub, for bootloader/kernel debugging.
|
||||||
|
q sect chardev socket
|
||||||
|
q param id gdbqemu
|
||||||
|
q param path "$qdir"/gdbqemu.sock
|
||||||
|
q param server on
|
||||||
|
q param wait off
|
||||||
|
|
||||||
|
q sect gdb chardev:gdbqemu
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_all()
|
||||||
|
{
|
||||||
|
local _append
|
||||||
|
|
||||||
|
: >"$qdir"/append
|
||||||
|
cat <<EOF >"$qdir"/qemu.sh
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Starting Qemu :: Ctrl-a x -- exit | Ctrl-a c -- toggle console/monitor"
|
||||||
|
|
||||||
|
line=\$(stty -g)
|
||||||
|
stty raw
|
||||||
|
trap 'stty "\$line"' EXIT INT TERM
|
||||||
|
|
||||||
|
qemu-system-$QEMU_ARCH -nodefaults \\
|
||||||
|
EOF
|
||||||
|
chmod +x "$qdir"/qemu.sh
|
||||||
|
|
||||||
|
gen_machine
|
||||||
|
gen_loader
|
||||||
|
gen_serial
|
||||||
|
gen_disks
|
||||||
|
gen_gdb
|
||||||
|
|
||||||
|
if [ "$QEMU_LOADER_QEMU" ]; then
|
||||||
|
_append=$(cat "$qdir"/append)
|
||||||
|
q sect append "\"$_append $QEMU_APPEND $*\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo >>"$qdir"/qemu.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
menuconfig()
|
||||||
|
{
|
||||||
|
command -v kconfig-mconf >/dev/null \
|
||||||
|
|| die "cannot find kconfig-mconf for menuconfig"
|
||||||
|
|
||||||
|
CONFIG_= KCONFIG_CONFIG="$qdir"/.config \
|
||||||
|
kconfig-mconf "$qdir"/Config.in
|
||||||
|
}
|
||||||
|
|
||||||
|
_generate=YES
|
||||||
|
|
||||||
|
while getopts "0cGh-" opt; do
|
||||||
|
case ${opt} in
|
||||||
|
0)
|
||||||
|
echo "Clearing all copy-on-write layers" >&2
|
||||||
|
rm -f "$qdir"/*.qcow2
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
c)
|
||||||
|
menuconfig
|
||||||
|
;;
|
||||||
|
G)
|
||||||
|
_generate=
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
usage && exit 0
|
||||||
|
;;
|
||||||
|
-)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage && exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$qdir"/.config
|
||||||
|
|
||||||
|
[ "$_generate" ] && gen_all "$*"
|
||||||
|
|
||||||
|
exec "$qdir"/qemu.sh
|
||||||
@@ -149,7 +149,7 @@ config QEMU_HOST
|
|||||||
|
|
||||||
config QEMU_APPEND
|
config QEMU_APPEND
|
||||||
string "Extra kernel options"
|
string "Extra kernel options"
|
||||||
depends on !QEMU_ROOTFS_MMC
|
depends on QEMU_LOADER_KERNEL
|
||||||
|
|
||||||
config QEMU_EXTRA
|
config QEMU_EXTRA
|
||||||
string "Extra QEMU options"
|
string "Extra QEMU options"
|
||||||
@@ -4,9 +4,15 @@
|
|||||||
#
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
QEMU_SCRIPTS_DIR := $(pkgdir)
|
qemu-scripts-dir := $(pkgdir)/$(if $(IMAGE_DDI),ddi,itb)
|
||||||
|
qemu-image := ../$(INFIX_ARTIFACT).$(if $(IMAGE_DDI),raw,qcow2)
|
||||||
|
qemu-disk := $(if $(IMAGE_DDI_DISK),../$(INFIX_ARTIFACT).disk)
|
||||||
|
qemu-esp := $(if $(IMAGE_BAREBOX_ESP),../barebox-esp.vfat)
|
||||||
|
|
||||||
|
qemu-kconfig-prefix := $(if $(IMAGE_DDI),,CONFIG_)
|
||||||
|
|
||||||
qemu-kconfig = \
|
qemu-kconfig = \
|
||||||
CONFIG_="CONFIG_" \
|
CONFIG_="$(qemu-kconfig-prefix)" \
|
||||||
BR2_CONFIG="$(BINARIES_DIR)/qemu/.config" \
|
BR2_CONFIG="$(BINARIES_DIR)/qemu/.config" \
|
||||||
$(BUILD_DIR)/buildroot-config/$(1) $(2) "$(BINARIES_DIR)/qemu/Config.in"
|
$(BUILD_DIR)/buildroot-config/$(1) $(2) "$(BINARIES_DIR)/qemu/Config.in"
|
||||||
|
|
||||||
@@ -25,17 +31,19 @@ qemu-scripts: \
|
|||||||
$(BINARIES_DIR)/qemu/Config.in \
|
$(BINARIES_DIR)/qemu/Config.in \
|
||||||
$(BINARIES_DIR)/qemu/.config
|
$(BINARIES_DIR)/qemu/.config
|
||||||
|
|
||||||
$(BINARIES_DIR)/qemu/run.sh: $(QEMU_SCRIPTS_DIR)/run.sh
|
$(BINARIES_DIR)/qemu/run.sh: $(qemu-scripts-dir)/run.sh
|
||||||
@$(call IXMSG,"Installing QEMU scripts")
|
@$(call IXMSG,"Installing QEMU scripts")
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@cp $< $@
|
@cp $< $@
|
||||||
|
|
||||||
$(BINARIES_DIR)/qemu/Config.in: $(QEMU_SCRIPTS_DIR)/Config.in.in
|
$(BINARIES_DIR)/qemu/Config.in: $(qemu-scripts-dir)/Config.in.in
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@sed \
|
@sed \
|
||||||
-e "s:@ARCH@:QEMU_$(BR2_ARCH):" \
|
-e "s:@ARCH@:$(BR2_ARCH):g" \
|
||||||
-e "s:@DISK_IMG@:../$(INFIX_ARTIFACT).qcow2:" \
|
-e "s:@IMAGE@:$(qemu-image):g" \
|
||||||
< $< >$@
|
-e "s:@DISK@:$(qemu-disk):g" \
|
||||||
|
-e "s:@ESP@:$(qemu-esp):g" \
|
||||||
|
<$< >$@
|
||||||
|
|
||||||
$(BINARIES_DIR)/qemu/.config: $(BINARIES_DIR)/qemu/Config.in
|
$(BINARIES_DIR)/qemu/.config: $(BINARIES_DIR)/qemu/Config.in
|
||||||
@$(call qemu-kconfig,conf,--olddefconfig)
|
@$(call qemu-kconfig,conf,--olddefconfig)
|
||||||
|
|||||||
Executable
+343
@@ -0,0 +1,343 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
capath=/etc/rauc/keys
|
||||||
|
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
local _ddi="$(basename $0)"
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
usage: $_ddi [<options>] <image> <command> [<args>]
|
||||||
|
|
||||||
|
Discoverable Disk Image manipulation
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-A <arch>
|
||||||
|
Override the system architecture.
|
||||||
|
|
||||||
|
-C <path>
|
||||||
|
Source trusted signing keys from the supplied directory.
|
||||||
|
Default: $capath
|
||||||
|
|
||||||
|
-h
|
||||||
|
Show this message and exit.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
|
||||||
|
inspect <property>
|
||||||
|
|
||||||
|
uuid
|
||||||
|
Print GPT disk identifier
|
||||||
|
|
||||||
|
part <partition> <command> [<args]
|
||||||
|
Where <partition> is one of:
|
||||||
|
root The first root partition
|
||||||
|
|
||||||
|
open [<options>] <name>
|
||||||
|
|
||||||
|
Create a device mapping for the specified partition, called
|
||||||
|
<name>.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-v
|
||||||
|
Use the associated dm-verity hash tree, whose root hash is
|
||||||
|
available in the associated signature partition.
|
||||||
|
|
||||||
|
-V <root-hash>
|
||||||
|
Use the associated dm-verity hash tree, along with an
|
||||||
|
externally validated root hash.
|
||||||
|
|
||||||
|
verify [<options>]
|
||||||
|
|
||||||
|
Verify that the specified partition exists and, optionally,
|
||||||
|
is accompanied by a trusted dm-verity hash tree.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-v
|
||||||
|
Require the presence of an associated dm-verity hash tree,
|
||||||
|
whose root hash is available in the associated signature
|
||||||
|
partition.
|
||||||
|
|
||||||
|
-V <root-hash>
|
||||||
|
Require the presence of an associated dm-verity hash tree
|
||||||
|
whose root hash matches the provided one.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
Map and mount the verity protected SquashFS root partition from an
|
||||||
|
image:
|
||||||
|
$_ddi infix-x86_64.raw part root open -v infix
|
||||||
|
mount -t squashfs /dev/mapper/infix /opt
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
X86_64_CODE_ROOT=0x8304
|
||||||
|
X86_64_CODE_ROOT_VERITY=0x830c
|
||||||
|
X86_64_CODE_ROOT_VERITY_SIG=0x8370
|
||||||
|
|
||||||
|
die()
|
||||||
|
{
|
||||||
|
echo "ERROR: $*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ok()
|
||||||
|
{
|
||||||
|
echo "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_arch()
|
||||||
|
{
|
||||||
|
case "$1" in
|
||||||
|
x86_64)
|
||||||
|
CODE_ROOT=$X86_64_CODE_ROOT
|
||||||
|
CODE_ROOT_VERITY=$X86_64_CODE_ROOT_VERITY
|
||||||
|
CODE_ROOT_VERITY_SIG=$X86_64_CODE_ROOT_VERITY_SIG
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unsupported architecture"
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_work()
|
||||||
|
{
|
||||||
|
local _umask
|
||||||
|
|
||||||
|
_umask=$(umask)
|
||||||
|
umask 077
|
||||||
|
workdir=$(mktemp -d)
|
||||||
|
umask $_umask
|
||||||
|
|
||||||
|
trap 'rm -rf "$workdir"' EXIT INT TERM
|
||||||
|
}
|
||||||
|
|
||||||
|
ddi_to_block()
|
||||||
|
{
|
||||||
|
local _kind _lo
|
||||||
|
|
||||||
|
_kind=$(stat -Lc %F "$1")
|
||||||
|
case "$_kind" in
|
||||||
|
"block special file")
|
||||||
|
echo "$1"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
"regular file")
|
||||||
|
_lo=$(losetup -f || die "Found no free loop device for $1")
|
||||||
|
losetup -P "$_lo" "$1" || die "Failed to setup loop device of $1"
|
||||||
|
echo "$_lo"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
die "$1 is a $_kind, only regular and block devices are supported"
|
||||||
|
}
|
||||||
|
|
||||||
|
ddi_get_part_info()
|
||||||
|
{
|
||||||
|
local _code _item
|
||||||
|
|
||||||
|
case "$2" in
|
||||||
|
root) _code="$CODE_ROOT";;
|
||||||
|
root-verity) _code="$CODE_ROOT_VERITY";;
|
||||||
|
root-verity-sig) _code="$CODE_ROOT_VERITY_SIG";;
|
||||||
|
*) die "Unknown partition type \"$1\"" ;;
|
||||||
|
esac
|
||||||
|
_code=$(printf "%04X" "$_code")
|
||||||
|
_item=${3:-exists}
|
||||||
|
|
||||||
|
sgdisk "$1" -p | awk -v code="$_code" -v item="$_item" '
|
||||||
|
/^[ ]*[0-9]+/ {
|
||||||
|
if ($6 != code)
|
||||||
|
next;
|
||||||
|
|
||||||
|
if (item == "exists") exit(0);
|
||||||
|
if (item == "index") { print($1); exit(0); }
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
ddi_get_part_dev()
|
||||||
|
{
|
||||||
|
local _dev _index _lvuuid _subsys
|
||||||
|
|
||||||
|
_index=$(ddi_get_part_info "$1" "$2" index \
|
||||||
|
|| die "No $2 partition found on $1")
|
||||||
|
|
||||||
|
_subsys=$(dmsetup info -c --noheadings -o subsystem "$1" 2>/dev/null || true)
|
||||||
|
if [ "$_subsys" = "LVM" ]; then
|
||||||
|
_lvuuid=$(dmsetup info -c --noheadings -o uuid "$1")
|
||||||
|
_dev=/dev/mapper/$(dmsetup info -c --noheadings -o name -u "part${_index}-$_lvuuid")
|
||||||
|
else
|
||||||
|
_dev=$(basename "$1")
|
||||||
|
_dev=$(find /sys/block/"$_dev"/ -mindepth 1 -maxdepth 1 -type d \
|
||||||
|
-name "${_dev}$_index" -o -name "${_dev}p$_index")
|
||||||
|
_dev=/dev/$(basename "$_dev")
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -b "$_dev" ] || die "Failed to locate $2 partition in $1"
|
||||||
|
|
||||||
|
echo "$_dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
ddi_get_root_hash()
|
||||||
|
{
|
||||||
|
local _subj
|
||||||
|
|
||||||
|
command -v openssl >/dev/null || die "Missing dependency: openssl"
|
||||||
|
command -v jq >/dev/null || die "Missing dependency: jq"
|
||||||
|
|
||||||
|
jq -r .rootHash "$1" | tr -d '\n' >"$workdir"/hash \
|
||||||
|
|| die "Invalid signature: rootHash is missing"
|
||||||
|
|
||||||
|
jq -r .signature "$1" | base64 -d >"$workdir"/sig \
|
||||||
|
|| die "Invalid signature: signature data is missing"
|
||||||
|
|
||||||
|
openssl cms -verify -verify_retcode -CApath "$capath" \
|
||||||
|
-content "$workdir"/hash \
|
||||||
|
-in "$workdir"/sig -inform DER \
|
||||||
|
-certsout "$workdir"/certs >/dev/null 2>&1 \
|
||||||
|
|| die "Signature verification failed"
|
||||||
|
|
||||||
|
_subj=$(openssl x509 -noout -subject <"$workdir"/certs | sed -e 's/^subject=//')
|
||||||
|
ok "Trusting root hash signature from $_subj"
|
||||||
|
|
||||||
|
cat "$workdir"/hash
|
||||||
|
}
|
||||||
|
|
||||||
|
ddipart_get_verity()
|
||||||
|
{
|
||||||
|
local _hash
|
||||||
|
|
||||||
|
while getopts "vV:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
V)
|
||||||
|
vkind="${kind}-verity"
|
||||||
|
vhash="$OPTARG"
|
||||||
|
;;
|
||||||
|
v)
|
||||||
|
vkind="${kind}-verity"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[ "$vkind" ] || return
|
||||||
|
|
||||||
|
vpart=$(ddi_get_part_dev "$img" "$vkind")
|
||||||
|
|
||||||
|
[ "$vhash" ] && return
|
||||||
|
|
||||||
|
vskind="${vkind}-sig"
|
||||||
|
vspart=$(ddi_get_part_dev "$img" "$vskind")
|
||||||
|
vhash=$(ddi_get_root_hash "$vspart")
|
||||||
|
}
|
||||||
|
|
||||||
|
ddipart_open()
|
||||||
|
{
|
||||||
|
[ "$vpart" ] || die "$kind partition is already accessible at $part"
|
||||||
|
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
veritysetup open "$part" "$1" "$vpart" "$vhash"
|
||||||
|
}
|
||||||
|
|
||||||
|
ddipart_verify()
|
||||||
|
{
|
||||||
|
[ "$vpart" ] || return
|
||||||
|
|
||||||
|
veritysetup verify "$part" "$vpart" "$vhash"
|
||||||
|
ok "Image in $img has $kind partition with valid dm-verity hash tree"
|
||||||
|
}
|
||||||
|
|
||||||
|
ddipart()
|
||||||
|
{
|
||||||
|
local _cmd
|
||||||
|
|
||||||
|
kind="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
ddi_get_part_info "$img" "$kind" \
|
||||||
|
|| die "No $kind partition found on $img"
|
||||||
|
|
||||||
|
_cmd="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
case "$_cmd" in
|
||||||
|
open|verify)
|
||||||
|
img=$(ddi_to_block $img)
|
||||||
|
part=$(ddi_get_part_dev "$img" "$kind")
|
||||||
|
ddipart_get_verity "$@"
|
||||||
|
|
||||||
|
ddipart_$_cmd "$@"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unknown partition command \"$_cmd\""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
ddiinspect()
|
||||||
|
{
|
||||||
|
case "$1" in
|
||||||
|
uuid)
|
||||||
|
sgdisk "$img" -p | awk '
|
||||||
|
BEGIN { err = 1; } END { exit(err); }
|
||||||
|
/^Creating new GPT/ { exit; }
|
||||||
|
|
||||||
|
/^Disk identifier \(GUID\): / {
|
||||||
|
print($4); err = 0; exit;
|
||||||
|
}'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unknown property: $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_arch=$(uname -m)
|
||||||
|
|
||||||
|
while getopts "A:C:h" opt; do
|
||||||
|
case ${opt} in
|
||||||
|
A)
|
||||||
|
_arch="$OPTARG"
|
||||||
|
;;
|
||||||
|
C)
|
||||||
|
capath="$OPTARG"
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
usage && exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
usage && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
img="$1"
|
||||||
|
cmd="$2"
|
||||||
|
shift 2
|
||||||
|
|
||||||
|
setup_arch "$_arch"
|
||||||
|
setup_work
|
||||||
|
|
||||||
|
case "$cmd" in
|
||||||
|
inspect)
|
||||||
|
ddiinspect "$@"
|
||||||
|
;;
|
||||||
|
part)
|
||||||
|
ddipart "$@"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command \"$cmd\"" >2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
CODE_ROOT=0x8304
|
||||||
|
CODE_ROOT_VERITY=0x830c
|
||||||
|
CODE_ROOT_VERITY_SIG=0x8370
|
||||||
+1
-1
Submodule buildroot updated: 66450a898a...cde6f777f9
@@ -37,6 +37,7 @@ BR2_PACKAGE_STRESS_NG=y
|
|||||||
BR2_PACKAGE_JQ=y
|
BR2_PACKAGE_JQ=y
|
||||||
BR2_PACKAGE_E2FSPROGS=y
|
BR2_PACKAGE_E2FSPROGS=y
|
||||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||||
|
BR2_PACKAGE_CRYPTSETUP=y
|
||||||
BR2_PACKAGE_DBUS_CXX=y
|
BR2_PACKAGE_DBUS_CXX=y
|
||||||
BR2_PACKAGE_DBUS_GLIB=y
|
BR2_PACKAGE_DBUS_GLIB=y
|
||||||
BR2_PACKAGE_EUDEV_RULES_GEN=y
|
BR2_PACKAGE_EUDEV_RULES_GEN=y
|
||||||
@@ -87,6 +88,7 @@ BR2_PACKAGE_BASH_COMPLETION=y
|
|||||||
BR2_PACKAGE_SUDO=y
|
BR2_PACKAGE_SUDO=y
|
||||||
BR2_PACKAGE_GETENT=y
|
BR2_PACKAGE_GETENT=y
|
||||||
BR2_PACKAGE_KMOD_TOOLS=y
|
BR2_PACKAGE_KMOD_TOOLS=y
|
||||||
|
BR2_PACKAGE_MULTIPATH_TOOLS=y
|
||||||
BR2_PACKAGE_PWGEN=y
|
BR2_PACKAGE_PWGEN=y
|
||||||
BR2_PACKAGE_RAUC=y
|
BR2_PACKAGE_RAUC=y
|
||||||
BR2_PACKAGE_RAUC_DBUS=y
|
BR2_PACKAGE_RAUC_DBUS=y
|
||||||
@@ -95,6 +97,7 @@ BR2_PACKAGE_RAUC_NETWORK=y
|
|||||||
BR2_PACKAGE_RAUC_JSON=y
|
BR2_PACKAGE_RAUC_JSON=y
|
||||||
BR2_PACKAGE_SYSKLOGD=y
|
BR2_PACKAGE_SYSKLOGD=y
|
||||||
BR2_PACKAGE_SYSKLOGD_LOGGER=y
|
BR2_PACKAGE_SYSKLOGD_LOGGER=y
|
||||||
|
BR2_PACKAGE_UTIL_LINUX_PARTX=y
|
||||||
BR2_PACKAGE_WATCHDOGD=y
|
BR2_PACKAGE_WATCHDOGD=y
|
||||||
BR2_PACKAGE_WATCHDOGD_GENERIC=y
|
BR2_PACKAGE_WATCHDOGD_GENERIC=y
|
||||||
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
|
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
|
||||||
@@ -105,13 +108,16 @@ BR2_PACKAGE_WATCHDOGD_TEMPMON=y
|
|||||||
BR2_PACKAGE_LESS=y
|
BR2_PACKAGE_LESS=y
|
||||||
BR2_PACKAGE_MG=y
|
BR2_PACKAGE_MG=y
|
||||||
BR2_PACKAGE_NANO=y
|
BR2_PACKAGE_NANO=y
|
||||||
|
BR2_TARGET_ROOTFS_CPIO_DRACUT=y
|
||||||
|
BR2_TARGET_ROOTFS_CPIO_DRACUT_MODULES="${BR2_EXTERNAL_INFIX_PATH}/board/common/initramfs"
|
||||||
|
BR2_TARGET_ROOTFS_CPIO_DRACUT_CONF_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/dracut.conf"
|
||||||
|
BR2_TARGET_ROOTFS_INITRAMFS=y
|
||||||
# BR2_TARGET_ROOTFS_TAR is not set
|
# BR2_TARGET_ROOTFS_TAR is not set
|
||||||
BR2_TARGET_EDK2=y
|
BR2_TARGET_BAREBOX=y
|
||||||
BR2_TARGET_GRUB2=y
|
BR2_TARGET_BAREBOX_CUSTOM_VERSION=y
|
||||||
BR2_TARGET_GRUB2_X86_64_EFI=y
|
BR2_TARGET_BAREBOX_CUSTOM_VERSION_VALUE="2025.11.0"
|
||||||
BR2_TARGET_GRUB2_BUILTIN_MODULES_EFI="boot linux ext2 squash4 part_gpt normal efi_gop configfile loadenv test echo reboot net efinet tftp loopback cat search"
|
BR2_TARGET_BAREBOX_BOARD_DEFCONFIG="efi"
|
||||||
BR2_TARGET_GRUB2_BUILTIN_CONFIG_EFI="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/grub-embed.cfg"
|
BR2_TARGET_BAREBOX_IMAGE_FILE="barebox.efi"
|
||||||
BR2_TARGET_GRUB2_INSTALL_TOOLS=y
|
|
||||||
BR2_PACKAGE_HOST_DOSFSTOOLS=y
|
BR2_PACKAGE_HOST_DOSFSTOOLS=y
|
||||||
BR2_PACKAGE_HOST_E2FSPROGS=y
|
BR2_PACKAGE_HOST_E2FSPROGS=y
|
||||||
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
|
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
|
||||||
@@ -150,9 +156,6 @@ BR2_PACKAGE_MDNS_ALIAS=y
|
|||||||
BR2_PACKAGE_ONIEPROM=y
|
BR2_PACKAGE_ONIEPROM=y
|
||||||
BR2_PACKAGE_ROUSETTE=y
|
BR2_PACKAGE_ROUSETTE=y
|
||||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||||
IMAGE_ITB_AUX=y
|
IMAGE_DDI=y
|
||||||
IMAGE_ITB_QCOW=y
|
|
||||||
IMAGE_ITB_RAUC=y
|
|
||||||
IMAGE_README=y
|
|
||||||
TRUSTED_KEYS=y
|
TRUSTED_KEYS=y
|
||||||
TRUSTED_KEYS_DEVELOPMENT=y
|
TRUSTED_KEYS_DEVELOPMENT=y
|
||||||
|
|||||||
Executable
+209
@@ -0,0 +1,209 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import struct
|
||||||
|
|
||||||
|
class ID:
|
||||||
|
def __init__(self):
|
||||||
|
charset = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
charset += "0123456789"
|
||||||
|
|
||||||
|
b = random.choices(charset, k=32)
|
||||||
|
self.bytes = "".join(b).encode()
|
||||||
|
|
||||||
|
def dashed(self):
|
||||||
|
return self.bytes[0:6].decode() + \
|
||||||
|
"-" + self.bytes[6:10].decode() + \
|
||||||
|
"-" + self.bytes[10:14].decode() + \
|
||||||
|
"-" + self.bytes[14:18].decode() + \
|
||||||
|
"-" + self.bytes[18:22].decode() + \
|
||||||
|
"-" + self.bytes[22:26].decode() + \
|
||||||
|
"-" + self.bytes[26:32].decode()
|
||||||
|
|
||||||
|
def crc32(data: bytes) -> int:
|
||||||
|
crc = 0xf597a6cf
|
||||||
|
|
||||||
|
for byte in data:
|
||||||
|
crc ^= byte
|
||||||
|
for _ in range(8):
|
||||||
|
if crc & 1:
|
||||||
|
crc = (crc >> 1) ^ 0xedb88320
|
||||||
|
else:
|
||||||
|
crc >>= 1
|
||||||
|
|
||||||
|
return crc & 0xffffffff
|
||||||
|
|
||||||
|
def sendfile(dst, src, count):
|
||||||
|
while count > 0:
|
||||||
|
chunk = os.sendfile(dst, src, None, count)
|
||||||
|
if chunk < 0:
|
||||||
|
raise OSError("sendfile")
|
||||||
|
|
||||||
|
count -= chunk
|
||||||
|
|
||||||
|
class Linear:
|
||||||
|
def __init__(self, start, align, path, name=None):
|
||||||
|
self.id = ID()
|
||||||
|
self.name = name if name else os.path.basename(path)
|
||||||
|
self.path = path
|
||||||
|
self.start = start
|
||||||
|
self.align = align
|
||||||
|
self.size = os.path.getsize(path)
|
||||||
|
self.asize = (self.size + align - 1) & ~(align - 1)
|
||||||
|
|
||||||
|
def sendfile(self, fd):
|
||||||
|
pad = self.asize - self.size
|
||||||
|
|
||||||
|
with open(self.path, "rb") as f:
|
||||||
|
sendfile(fd, f.fileno(), self.size)
|
||||||
|
|
||||||
|
if pad:
|
||||||
|
os.write(fd, b"\0" * pad)
|
||||||
|
|
||||||
|
def meta(self):
|
||||||
|
return f""" {self.name} {{
|
||||||
|
id = "{self.id.dashed()}"
|
||||||
|
status = ["READ", "WRITE", "VISIBLE"]
|
||||||
|
segment_count = 1
|
||||||
|
|
||||||
|
segment1 {{
|
||||||
|
start_extent = 0
|
||||||
|
extent_count = {self.asize // self.align }
|
||||||
|
type = "striped"
|
||||||
|
stripe_count = 1
|
||||||
|
stripes = [
|
||||||
|
"pv0", {self.start // self.align }
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
}}"""
|
||||||
|
|
||||||
|
class InternalPV:
|
||||||
|
def __init__(self, images=[], align=(1 << 20), creation_time=0):
|
||||||
|
self.pvid = ID()
|
||||||
|
self.vgid = ID()
|
||||||
|
self.align = align
|
||||||
|
self.creation_time = creation_time
|
||||||
|
|
||||||
|
self.lvs = []
|
||||||
|
self.dsize = 0
|
||||||
|
for img in images:
|
||||||
|
lv = Linear(self.dsize, align, img)
|
||||||
|
self.lvs.append(lv)
|
||||||
|
self.dsize += lv.asize
|
||||||
|
|
||||||
|
# Reserve `align` bytes for primary metadata area, the size
|
||||||
|
# used by all LVs, and another `aligned` bytes for the backup
|
||||||
|
# metadata area
|
||||||
|
self.size = align + self.dsize + align
|
||||||
|
|
||||||
|
def write(self, dst):
|
||||||
|
for i in range(4):
|
||||||
|
dst.write(self._label(i))
|
||||||
|
|
||||||
|
dst.write(b"\0" * 0x800)
|
||||||
|
|
||||||
|
dst.write(self._metadata(True))
|
||||||
|
|
||||||
|
for lv in self.lvs:
|
||||||
|
lv.sendfile(dst.fileno())
|
||||||
|
|
||||||
|
dst.write(self._metadata(False))
|
||||||
|
|
||||||
|
def _label(self, sector: int):
|
||||||
|
headfmt, tailfmt = "<8s Q I", "<I8s 32sQ QQ QQ QQ QQ QQ II"
|
||||||
|
padsize = 512 - struct.calcsize(headfmt) - struct.calcsize(tailfmt)
|
||||||
|
|
||||||
|
tail = struct.pack(tailfmt,
|
||||||
|
32, b"LVM2 001",
|
||||||
|
self.pvid.bytes, self.size,
|
||||||
|
# Data area (size=0 ~= all available space (?))
|
||||||
|
self.align, 0,
|
||||||
|
0, 0,
|
||||||
|
# Primary metadata area
|
||||||
|
0x1000, self.align - 0x1000,
|
||||||
|
# Backup metadata area
|
||||||
|
self.align + self.dsize, self.align,
|
||||||
|
0, 0,
|
||||||
|
# Supported extensions (Unsure which
|
||||||
|
# extensions this maps to, but it makes the
|
||||||
|
# LVM tooling happy :))
|
||||||
|
2, 1) + b"\0" * padsize
|
||||||
|
|
||||||
|
head = struct.pack(headfmt, b"LABELONE", sector, crc32(tail))
|
||||||
|
|
||||||
|
return head + tail
|
||||||
|
|
||||||
|
def _metadata(self, primary):
|
||||||
|
headfmt, tailfmt = "<I", "<16sI QQ QQII QQII"
|
||||||
|
padsize = 512 - struct.calcsize(headfmt) - struct.calcsize(tailfmt)
|
||||||
|
|
||||||
|
offs = 0x1000 if primary else (self.align + self.dsize)
|
||||||
|
size = self.align - 0x1000 if primary else self.align
|
||||||
|
|
||||||
|
txt = self._meta_txt()
|
||||||
|
txtpadsize = size - 512 - len(txt)
|
||||||
|
|
||||||
|
tail = struct.pack(tailfmt,
|
||||||
|
b" LVM2 x[5A%r0N*>", 1,
|
||||||
|
offs, size,
|
||||||
|
512, len(txt), crc32(txt), 0,
|
||||||
|
0, 0, 0, 0) + b"\0" * padsize
|
||||||
|
|
||||||
|
head = struct.pack(headfmt, crc32(tail))
|
||||||
|
|
||||||
|
return head + tail + txt + bytes([0] * txtpadsize)
|
||||||
|
|
||||||
|
def _meta_txt(self):
|
||||||
|
return f"""internal {{
|
||||||
|
id = "{self.vgid.dashed()}"
|
||||||
|
seqno = 1
|
||||||
|
status = ["RESIZEABLE", "READ", "WRITE"]
|
||||||
|
extent_size = {self.align >> 9}
|
||||||
|
max_pv = 0
|
||||||
|
max_lv = 0
|
||||||
|
metadata_copies = 2
|
||||||
|
|
||||||
|
physical_volumes {{
|
||||||
|
pv0 {{
|
||||||
|
id = "{self.pvid.dashed()}"
|
||||||
|
dev = "/dev/internal"
|
||||||
|
status = ["ALLOCATABLE"]
|
||||||
|
dev_size = {self.size >> 9}
|
||||||
|
pe_start = {self.align >> 9}
|
||||||
|
pe_count = {self.dsize // self.align }
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
logical_volumes {{
|
||||||
|
{"\n".join([lv.meta() for lv in self.lvs])}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
contents = "Text Format Volume Group"
|
||||||
|
version = 1
|
||||||
|
description = "Internal image storage"
|
||||||
|
creation_host = "infix-build-system"
|
||||||
|
creation_time = {self.creation_time}
|
||||||
|
""".encode()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Create LVM PV containing a set of images")
|
||||||
|
parser.add_argument("-T", "--creation-time", metavar="TIMESTAMP",
|
||||||
|
default=int(datetime.datetime.now().timestamp()))
|
||||||
|
parser.add_argument("images", metavar="IMAGE", nargs="*")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
random.seed(args.creation_time)
|
||||||
|
|
||||||
|
pv = InternalPV(args.images, creation_time=args.creation_time)
|
||||||
|
pv.write(sys.stdout.buffer)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user