From c9f2231b55c5173ea11c658870bb21be47f58752 Mon Sep 17 00:00:00 2001 From: Kroese Date: Fri, 2 Feb 2024 17:07:44 +0100 Subject: [PATCH] fix: UEFI booting (#1) --- .github/workflows/check.yml | 2 +- Dockerfile | 3 +- readme.md | 40 +++------- src/boot.sh | 154 ++++++++++++++++++------------------ src/config.sh | 4 +- src/disk.sh | 30 ++----- src/display.sh | 13 ++- src/proc.sh | 4 +- 8 files changed, 108 insertions(+), 142 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a8f2161..5a1ae98 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -20,5 +20,5 @@ jobs: uses: hadolint/hadolint-action@v3.1.0 with: dockerfile: Dockerfile - ignore: DL3008,DL3003 + ignore: DL3008,DL3003,DL3035,DL3059 failure-threshold: warning diff --git a/Dockerfile b/Dockerfile index 04e8f78..35093c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,10 +8,10 @@ RUN apt-get update \ && apt-get --no-install-recommends -y install \ tini \ wget \ - ovmf \ nginx \ swtpm \ procps \ + seabios \ iptables \ iproute2 \ apt-utils \ @@ -21,6 +21,7 @@ RUN apt-get update \ ca-certificates \ netcat-openbsd \ qemu-system-arm \ + qemu-efi-aarch64 \ && apt-get clean \ && novnc="1.4.0" \ && mkdir -p /usr/share/novnc \ diff --git a/readme.md b/readme.md index f13d6a5..a0e5538 100644 --- a/readme.md +++ b/readme.md @@ -97,27 +97,13 @@ docker run -it --rm -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device Replace the example path `/var/qemu` with the desired storage folder. -* ### How do I boot Windows? +* ### How do I boot a x86 image? - To enable Windows booting, add the following line to your compose file: + You can use [qemu-docker](https://github.com/qemus/qemu-docker/) to run x86 and x64 images on ARM. - ```yaml - environment: - BOOT_MODE: "windows" - ``` +* ### How do I boot a local image? - But you might want to give [dockur/windows](https://github.com/dockur/windows) a try instead, as it includes all the drivers required during installation and many other features. - -* ### How do I verify if my system supports KVM? - - To verify if your system supports KVM, run the following commands: - - ```bash - sudo apt install cpu-checker - sudo kvm-ok - ``` - - If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS. + To skip the download, rename your image to `boot.iso` and place it in an empty `/storage` folder. * ### How do I assign an individual IP address to the container? @@ -196,18 +182,16 @@ docker run -it --rm -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device - /dev/bus/usb ``` -* ### How do I boot with UEFI? +* ### How do I verify if my system supports KVM? - To enable UEFI booting, add the following line to your compose file: + To verify if your system supports KVM, run the following commands: - ```yaml - environment: - BOOT_MODE: "uefi" + ```bash + sudo apt install cpu-checker + sudo kvm-ok ``` -* ### How do I boot a local image? - - To skip the download, rename your image to `boot.iso` and place it in an empty `/storage` folder. + If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS. * ### How do I provide custom arguments to QEMU? @@ -218,10 +202,6 @@ docker run -it --rm -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device ARGUMENTS: "-device usb-tablet" ``` -* ### How do I run a x86 or x64 machine? - - You can use [qemu-docker](https://github.com/qemus/qemu-docker/) to run x86 and x64 machines on ARM. - [build_url]: https://github.com/qemus/qemu-arm/ [hub_url]: https://hub.docker.com/r/qemux/qemu-arm/ [tag_url]: https://hub.docker.com/r/qemux/qemu-arm/tags diff --git a/src/boot.sh b/src/boot.sh index f4e2f9e..5beaec8 100644 --- a/src/boot.sh +++ b/src/boot.sh @@ -2,99 +2,99 @@ set -Eeuo pipefail # Docker environment variables -: "${TPM:="Y"}" # Enable TPM -: "${BOOT_MODE:="legacy"}" # Boot mode +: "${TPM:="Y"}" # Enable TPM +: "${BIOS:=""}" # Bios file +: "${BOOT_MODE:="uefi"}" # Boot mode SECURE="" -BOOT_OPTS="" +DIR="/usr/share/qemu" +BOOT_OPTS="-device ramfb" case "${BOOT_MODE,,}" in uefi) - ROM="OVMF_CODE_4M.fd" - VARS="OVMF_VARS_4M.fd" + ROM="AAVMF_CODE.fd" + VARS="AAVMF_VARS.fd" ;; secure) - ROM="OVMF_CODE_4M.secboot.fd" - VARS="OVMF_VARS_4M.secboot.fd" + ROM="AAVMF_CODE.fd" + VARS="AAVMF_VARS.fd" ;; windows) - ROM="OVMF_CODE_4M.ms.fd" - VARS="OVMF_VARS_4M.ms.fd" - ;; - windows_legacy) - USB="usb-ehci,id=ehci" - BOOT_OPTS="" - ;; - legacy) - BOOT_OPTS="" + ROM="AAVMF_CODE.ms.fd" + VARS="AAVMF_VARS.ms.fd" ;; *) - info "Unknown boot mode '${BOOT_MODE}', defaulting to 'legacy'" - BOOT_MODE="legacy" + info "Unknown boot mode '${BOOT_MODE}', defaulting to 'uefi'" + BOOT_MODE="uefi" + ROM="AAVMF_CODE.fd" + VARS="AAVMF_VARS.fd" ;; esac -if [[ "${BOOT_MODE,,}" != "legacy" ]] && [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then +if [ -n "$BIOS" ]; then - OVMF="/usr/share/OVMF" - DEST="$STORAGE/${BOOT_MODE,,}" - - if [ ! -f "$DEST.rom" ]; then - [ ! -f "$OVMF/$ROM" ] && error "UEFI boot file ($OVMF/$ROM) not found!" && exit 44 - cp "$OVMF/$ROM" "$DEST.rom" - fi - - if [ ! -f "$DEST.vars" ]; then - [ ! -f "$OVMF/$VARS" ] && error "UEFI vars file ($OVMF/$VARS) not found!" && exit 45 - cp "$OVMF/$VARS" "$DEST.vars" - fi - - if [[ "${BOOT_MODE,,}" != "uefi" ]]; then - SECURE=",smm=on" - BOOT_OPTS="$BOOT_OPTS -global driver=cfi.pflash01,property=secure,value=on" - fi - - BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on" - BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.vars,if=pflash,unit=1,format=raw" - - if [[ "${BOOT_MODE,,}" == "windows" ]]; then - - BOOT_OPTS="$BOOT_OPTS -global kvm-pit.lost_tick_policy=discard -global ICH9-LPC.disable_s3=1" - - if [[ "$TPM" == [Yy1]* ]]; then - - rm -rf /run/shm/tpm - rm -f /var/run/tpm.pid - mkdir -p /run/shm/tpm - chmod 755 /run/shm/tpm - - if ! swtpm socket -t -d --tpmstate dir=/run/shm/tpm --ctrl type=unixio,path=/run/swtpm-sock --pid file=/var/run/tpm.pid --tpm2; then - error "Failed to start TPM emulator, reason: $?" && exit 19 - fi - - for (( i = 1; i < 20; i++ )); do - - [ -S "/run/swtpm-sock" ] && break - - if (( i % 10 == 0 )); then - echo "Waiting for TPM socket to become available..." - fi - - sleep 0.1 - - done - - if [ ! -S "/run/swtpm-sock" ]; then - TPM="N" - error "TPM socket not found? Disabling TPM support..." - else - BOOT_OPTS="$BOOT_OPTS -chardev socket,id=chrtpm,path=/run/swtpm-sock" - BOOT_OPTS="$BOOT_OPTS -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0" - fi - - fi - fi + BOOT_OPTS="$BOOT_OPTS -bios $DIR/$BIOS" + return 0 fi +AAVMF="/usr/share/AAVMF/" +DEST="$STORAGE/${BOOT_MODE,,}" + +if [ ! -f "$DEST.rom" ]; then + [ ! -f "$AAVMF/$ROM" ] && error "UEFI boot file ($AAVMF/$ROM) not found!" && exit 44 + cp "$AAVMF/$ROM" "$DEST.rom" +fi + +if [ ! -f "$DEST.vars" ]; then + [ ! -f "$AAVMF/$VARS" ] && error "UEFI vars file ($AAVMF/$VARS) not found!" && exit 45 + cp "$AAVMF/$VARS" "$DEST.vars" +fi + +if [[ "${BOOT_MODE,,}" != "uefi" ]]; then + SECURE=",smm=on" + BOOT_OPTS="$BOOT_OPTS -global driver=cfi.pflash01,property=secure,value=on" +fi + +BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on" +BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.vars,if=pflash,unit=1,format=raw" + +if [[ "${BOOT_MODE,,}" == "windows" ]]; then + + BOOT_OPTS="$BOOT_OPTS -global kvm-pit.lost_tick_policy=discard -global ICH9-LPC.disable_s3=1" + + if [[ "$TPM" == [Yy1]* ]]; then + + rm -rf /run/shm/tpm + rm -f /var/run/tpm.pid + mkdir -p /run/shm/tpm + chmod 755 /run/shm/tpm + + if ! swtpm socket -t -d --tpmstate dir=/run/shm/tpm --ctrl type=unixio,path=/run/swtpm-sock --pid file=/var/run/tpm.pid --tpm2; then + error "Failed to start TPM emulator, reason: $?" && exit 19 + fi + + for (( i = 1; i < 20; i++ )); do + + [ -S "/run/swtpm-sock" ] && break + + if (( i % 10 == 0 )); then + echo "Waiting for TPM socket to become available..." + fi + + sleep 0.1 + + done + + if [ ! -S "/run/swtpm-sock" ]; then + TPM="N" + error "TPM socket not found? Disabling TPM support..." + else + BOOT_OPTS="$BOOT_OPTS -chardev socket,id=chrtpm,path=/run/swtpm-sock" + BOOT_OPTS="$BOOT_OPTS -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0" + fi + + fi +fi + return 0 diff --git a/src/config.sh b/src/config.sh index 8083552..9caebeb 100644 --- a/src/config.sh +++ b/src/config.sh @@ -8,10 +8,10 @@ set -Eeuo pipefail DEF_OPTS="-nodefaults" SERIAL_OPTS="-serial $SERIAL" MON_OPTS="-monitor $MONITOR" -USB_OPTS="-device $USB -device usb-tablet" +USB_OPTS="-device $USB -device usb-kbd -device usb-tablet" RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g') CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1" -MAC_OPTS="-machine type=${MACHINE}${SECURE},graphics=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}" +MAC_OPTS="-machine type=${MACHINE}${SECURE},graphics=off,dump-guest-core=off,${KVM_OPTS}" DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4" DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom" DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c" diff --git a/src/disk.sh b/src/disk.sh index 8d36239..32b4760 100644 --- a/src/disk.sh +++ b/src/disk.sh @@ -4,7 +4,7 @@ set -Eeuo pipefail # Docker environment variables : "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_turing' -: "${DISK_FMT:=""}" # Disk file format, can be set to "raw" (default) or "qcow2" +: "${DISK_FMT:=""}" # Disk file format, can be set to "raw" (default) or "qcow2" : "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format : "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance : "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host. @@ -15,20 +15,14 @@ BOOT="$STORAGE/$BASE" DISK_OPTS="-object iothread,id=io2" DISK_OPTS="$DISK_OPTS -drive id=cdrom0,media=cdrom,if=none,format=raw,readonly=on,file=$BOOT" - -if [[ "${MACHINE,,}" != "pc-q35-2"* ]]; then - DISK_OPTS="$DISK_OPTS -device virtio-scsi-pci,id=scsi0,iothread=io2,addr=0x5" - DISK_OPTS="$DISK_OPTS -device scsi-cd,bus=scsi0.0,drive=cdrom0,bootindex=$BOOT_INDEX" -else - DISK_OPTS="$DISK_OPTS -device ide-cd,drive=cdrom0,bootindex=$BOOT_INDEX" -fi +DISK_OPTS="$DISK_OPTS -device virtio-scsi-pci,id=scsi0,iothread=io2,addr=0x5" +DISK_OPTS="$DISK_OPTS -device scsi-cd,bus=scsi0.0,drive=cdrom0,bootindex=$BOOT_INDEX" DRIVERS="$STORAGE/drivers.iso" [ ! -f "$DRIVERS" ] && DRIVERS="/run/drivers.iso" -if [ -f "$DRIVERS" ] && [[ "${MACHINE,,}" != "pc-q35-2"* ]]; then - DISK_OPTS="$DISK_OPTS -drive id=cdrom1,media=cdrom,if=none,format=raw,readonly=on,file=$DRIVERS" - DISK_OPTS="$DISK_OPTS -device ide-cd,drive=cdrom1" +if [ -f "$DRIVERS" ]; then + DISK_OPTS="$DISK_OPTS -drive id=cdrom1,media=cdrom,if=none,format=raw,readonly=on,file=$DRIVERS -device usb-storage,drive=cdrom1" fi fmt2ext() { @@ -357,17 +351,9 @@ createDevice () { local result="-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on" - if [[ "${MACHINE,,}" == "pc-q35-2"* ]]; then - - result="$result -device virtio-blk-pci,scsi=off,bus=pcie.0,addr=$DISK_ADDRESS,drive=drive-$DISK_ID,id=$DISK_ID,iothread=io2,bootindex=$DISK_INDEX" - - else - - result="$result \ - -device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \ - -device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX" - - fi + result="$result \ + -device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \ + -device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX" echo "$result" return 0 diff --git a/src/display.sh b/src/display.sh index a21fc8e..febaaff 100644 --- a/src/display.sh +++ b/src/display.sh @@ -3,22 +3,21 @@ set -Eeuo pipefail # Docker environment variables -: "${GPU:="N"}" # GPU passthrough -: "${VGA:="virtio"}" # VGA adaptor -: "${DISPLAY:="web"}" # Display type +: "${DISPLAY:="web"}" # Display +: "${VGA:="virtio-gpu"}" # GPU model case "${DISPLAY,,}" in vnc) - DISPLAY_OPTS="-display vnc=:0 -vga $VGA" + DISPLAY_OPTS="-display vnc=:0 -device $VGA" ;; web) - DISPLAY_OPTS="-display vnc=:0,websocket=5700 -vga $VGA" + DISPLAY_OPTS="-display vnc=:0,websocket=5700 -device $VGA" ;; none) - DISPLAY_OPTS="-display none -vga none" + DISPLAY_OPTS="-display none" ;; *) - DISPLAY_OPTS="-display $DISPLAY -vga $VGA" + DISPLAY_OPTS="-display $DISPLAY -device $VGA" ;; esac diff --git a/src/proc.sh b/src/proc.sh index 93b2907..87d4653 100644 --- a/src/proc.sh +++ b/src/proc.sh @@ -33,9 +33,9 @@ fi if [[ "$KVM" != [Nn]* ]]; then CPU_FEATURES="kvm=on" - KVM_OPTS=",accel=kvm -enable-kvm" + KVM_OPTS=",accel=kvm,virtualization=true -enable-kvm" - if [[ "${BOOT_MODE,,}" == "windows" ]] || [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then + if [[ "${BOOT_MODE,,}" == "windows" ]]; then CPU_FEATURES="kvm=on,+hypervisor,+invtsc,l3-cache=on,migratable=no,hv_passthrough"