diff --git a/api/core/v1alpha2/vmcondition/condition.go b/api/core/v1alpha2/vmcondition/condition.go index 6abfecbe0c..0a7554ea0f 100644 --- a/api/core/v1alpha2/vmcondition/condition.go +++ b/api/core/v1alpha2/vmcondition/condition.go @@ -172,6 +172,7 @@ const ( ReasonPodTerminating RunningReason = "PodTerminating" ReasonPodNotFound RunningReason = "PodNotFound" ReasonPodConditionMissing RunningReason = "PodConditionMissing" + ReasonBootFailed RunningReason = "BootFailed" ReasonGuestNotRunning RunningReason = "GuestNotRunning" ) diff --git a/images/edk2/patches/001-debug-device-no-bootable-device-message.patch b/images/edk2/patches/001-debug-device-no-bootable-device-message.patch new file mode 100644 index 0000000000..ada524a888 --- /dev/null +++ b/images/edk2/patches/001-debug-device-no-bootable-device-message.patch @@ -0,0 +1,62 @@ +diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +index d9f61757cf..d2a0e5f6a1 100644 +--- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c ++++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +@@ -2020,6 +2020,14 @@ PlatformBootManagerUnableToBoot ( + EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu; + UINTN Index; + ++ { ++ STATIC CONST CHAR8 Msg[] = "No bootable device.\r\n"; ++ UINTN i; ++ for (i = 0; i < sizeof (Msg) - 1; i++) { ++ IoWrite8 (0x403, (UINT8)Msg[i]); ++ } ++ } ++ + if (FeaturePcdGet (PcdBootRestrictToFirmware)) { + AsciiPrint ( + "%a: No bootable option was found.\n", +diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c +index 9bacf9d8c7..ea78559516 100644 +--- a/ShellPkg/Application/Shell/Shell.c ++++ b/ShellPkg/Application/Shell/Shell.c +@@ -359,6 +359,14 @@ UefiMain ( + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn; + SPLIT_LIST *Split; + ++ { ++ STATIC CONST CHAR8 Msg[] = "No bootable device.\r\n"; ++ UINTN i; ++ for (i = 0; i < sizeof (Msg) - 1; i++) { ++ IoWrite8 (0x403, (UINT8)Msg[i]); ++ } ++ } ++ + if (PcdGet8 (PcdShellSupportLevel) > 3) { + return (EFI_UNSUPPORTED); + } +diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h +index 89b4ac6b02..cd82e6f608 100644 +--- a/ShellPkg/Application/Shell/Shell.h ++++ b/ShellPkg/Application/Shell/Shell.h +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #include "ShellParametersProtocol.h" + #include "ShellProtocol.h" +diff --git a/ShellPkg/Application/Shell/Shell.inf b/ShellPkg/Application/Shell/Shell.inf +index f1e41de133..88b033bc35 100644 +--- a/ShellPkg/Application/Shell/Shell.inf ++++ b/ShellPkg/Application/Shell/Shell.inf +@@ -66,6 +66,7 @@ + SortLib + HandleParsingLib + UefiHiiServicesLib ++ IoLib + + [Guids] + gShellVariableGuid ## SOMETIMES_CONSUMES ## GUID diff --git a/images/edk2/patches/README.md b/images/edk2/patches/README.md new file mode 100644 index 0000000000..8d1720d23a --- /dev/null +++ b/images/edk2/patches/README.md @@ -0,0 +1,2 @@ +# 001-isa-debug-port-no-bootable-device-message.patch +If an EFI “No bootable device” error occurs, or the system drops into the EFI shell, output “No bootable device.” to the debug device at address 0x403. \ No newline at end of file diff --git a/images/edk2/werf.inc.yaml b/images/edk2/werf.inc.yaml index 452ae9fe18..7793c69d27 100644 --- a/images/edk2/werf.inc.yaml +++ b/images/edk2/werf.inc.yaml @@ -53,6 +53,13 @@ git: stageDependencies: install: - '*.json' +- add: {{ .ModuleDir }}/images/{{ .ImageName }}/patches + to: /src/patches + includePaths: + - '*.patch' + stageDependencies: + install: + - '*.patch' - add: {{ .ModuleDir }}/images/{{ .ImageName }}/uefi-revocation-list to: /src/FIRMWARE includePaths: @@ -68,6 +75,8 @@ shell: - | cd /src + echo "kek231" + echo "Git clone Edk2 repository..." git clone \ --depth=1 $(cat /run/secrets/SOURCE_REPO)/{{ $gitRepoUrl }} \ @@ -90,6 +99,13 @@ shell: submodule update --init --recursive --depth=1 fi + echo "Applying patches..." + for p in /src/patches/*.patch; do + [ -f "$p" ] || continue + echo "Applying $p" + git apply "$p" + done + --- image: {{ .ModuleNamePrefix }}{{ .ImageName }} diff --git a/images/qemu/patches/002-no-bootable-qmp.patch b/images/qemu/patches/002-no-bootable-qmp.patch new file mode 100644 index 0000000000..96f96da8b5 --- /dev/null +++ b/images/qemu/patches/002-no-bootable-qmp.patch @@ -0,0 +1,132 @@ +diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c +index fdb04fe..0cf2325 100644 +--- a/hw/char/debugcon.c ++++ b/hw/char/debugcon.c +@@ -26,6 +26,7 @@ + + #include "qemu/osdep.h" + #include "qapi/error.h" ++#include "qapi/qapi-events-control.h" + #include "qemu/module.h" + #include "chardev/char-fe.h" + #include "hw/isa/isa.h" +@@ -34,6 +35,7 @@ + #include "qom/object.h" + + #define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" ++#define DEBUGCON_NO_BOOTABLE_DEVICE "No bootable device." + OBJECT_DECLARE_SIMPLE_TYPE(ISADebugconState, ISA_DEBUGCON_DEVICE) + + //#define DEBUG_DEBUGCON +@@ -42,6 +44,9 @@ typedef struct DebugconState { + MemoryRegion io; + CharBackend chr; + uint32_t readback; ++ bool watch_no_bootable_device; ++ char match_buf[sizeof(DEBUGCON_NO_BOOTABLE_DEVICE) - 1]; ++ size_t match_len; + } DebugconState; + + struct ISADebugconState { +@@ -51,6 +56,27 @@ struct ISADebugconState { + DebugconState state; + }; + ++static void debugcon_maybe_emit_no_bootable_device(DebugconState *s, ++ unsigned char ch) ++{ ++ if (!s->watch_no_bootable_device) { ++ return; ++ } ++ ++ if (s->match_len < sizeof(s->match_buf)) { ++ s->match_buf[s->match_len++] = ch; ++ } else { ++ memmove(s->match_buf, s->match_buf + 1, sizeof(s->match_buf) - 1); ++ s->match_buf[sizeof(s->match_buf) - 1] = ch; ++ } ++ ++ if (s->match_len == sizeof(s->match_buf) && ++ memcmp(s->match_buf, DEBUGCON_NO_BOOTABLE_DEVICE, ++ sizeof(s->match_buf)) == 0) { ++ qapi_event_send_no_bootable_device(); ++ } ++} ++ + static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) + { +@@ -64,6 +90,7 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, + /* XXX this blocks entire thread. Rewrite to use + * qemu_chr_fe_write and background I/O callbacks */ + qemu_chr_fe_write_all(&s->chr, &ch, 1); ++ debugcon_maybe_emit_no_bootable_device(s, ch); + } + + +@@ -118,6 +145,8 @@ static Property debugcon_isa_properties[] = { + DEFINE_PROP_UINT32("iobase", ISADebugconState, iobase, 0xe9), + DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr), + DEFINE_PROP_UINT32("readback", ISADebugconState, state.readback, 0xe9), ++ DEFINE_PROP_BOOL("watch-no-bootable", ISADebugconState, ++ state.watch_no_bootable_device, false), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/qapi/control.json b/qapi/control.json +index 336386f..e1e727e 100644 +--- a/qapi/control.json ++++ b/qapi/control.json +@@ -209,3 +209,13 @@ + '*pretty': 'bool', + 'chardev': 'str' + } } ++ ++## ++# @NO_BOOTABLE_DEVICE: ++# ++# Emitted when `isa-debugcon` with enabled no-bootable watching ++# receives the string "No bootable device.". ++# ++# Since: 0.14 ++## ++{ 'event': 'NO_BOOTABLE_DEVICE' } +diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c +index 22957fa..9b4840e 100644 +--- a/tests/qtest/qmp-test.c ++++ b/tests/qtest/qmp-test.c +@@ -337,6 +337,25 @@ static void test_qmp_missing_any_arg(void) + qtest_quit(qts); + } + ++static void test_qmp_no_bootable_device_event(void) ++{ ++ static const char trigger[] = "No bootable device."; ++ QTestState *qts; ++ size_t i; ++ ++ qts = qtest_initf("-nodefaults -machine q35 " ++ "-chardev null,id=debugcon " ++ "-device isa-debugcon,iobase=0x402,chardev=debugcon," ++ "watch-no-bootable=on"); ++ ++ for (i = 0; i < sizeof(trigger) - 1; i++) { ++ qtest_outb(qts, 0x402, trigger[i]); ++ } ++ ++ qtest_qmp_eventwait(qts, "NO_BOOTABLE_DEVICE"); ++ qtest_quit(qts); ++} ++ + int main(int argc, char *argv[]) + { + g_test_init(&argc, &argv, NULL); +@@ -348,6 +367,8 @@ int main(int argc, char *argv[]) + #endif + qtest_add_func("qmp/preconfig", test_qmp_preconfig); + qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg); ++ qtest_add_func("qmp/no-bootable-device-event", ++ test_qmp_no_bootable_device_event); + + return g_test_run(); + } diff --git a/images/qemu/patches/seabios/001-alt-skip-flags-when-parse-objdump-section.patch b/images/qemu/patches/seabios/001-alt-skip-flags-when-parse-objdump-section.patch new file mode 100644 index 0000000000..815c5fc7a1 --- /dev/null +++ b/images/qemu/patches/seabios/001-alt-skip-flags-when-parse-objdump-section.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/layoutrom.py b/scripts/layoutrom.py +index 6616721..4f655dc 100755 +--- a/scripts/layoutrom.py ++++ b/scripts/layoutrom.py +@@ -564,7 +564,7 @@ def parseObjDump(file, fileid): + + if state == 'section': + try: +- idx, name, size, vma, lma, fileoff, align = line.split() ++ idx, name, size, vma, lma, fileoff, align, *_flags = line.split() + if align[:3] != '2**': + continue + section = Section() diff --git a/images/qemu/patches/seabios/002-0x403-debug-port-no-bootable-device-message.patch b/images/qemu/patches/seabios/002-0x403-debug-port-no-bootable-device-message.patch new file mode 100644 index 0000000000..dac272bddf --- /dev/null +++ b/images/qemu/patches/seabios/002-0x403-debug-port-no-bootable-device-message.patch @@ -0,0 +1,38 @@ +diff --git a/src/boot.c b/src/boot.c +index 1effd80..ec5992f 100644 +--- a/src/boot.c ++++ b/src/boot.c +@@ -21,6 +21,7 @@ + #include "string.h" // memset + #include "util.h" // irqtimer_calc + #include "tcgbios.h" // tpm_* ++#include "x86.h" // outb + + /**************************************************************** + * Helper search functions +@@ -960,12 +961,23 @@ boot_rom(u32 vector) + } + + // Unable to find bootable device - warn user and eventually retry. ++static void ++write_port_403(const char *s) ++{ ++ if (!CONFIG_DEBUG_IO || !runningOnQEMU()) ++ return; ++ ++ for (; *s; s++) ++ outb(*s, 0x403); ++} ++ + static void + boot_fail(void) + { +- if (BootRetryTime == (u32)-1) ++ if (BootRetryTime == (u32)-1) { + printf("No bootable device.\n"); +- else ++ write_port_403("No bootable device.\n"); ++ } else + printf("No bootable device. Retrying in %d seconds.\n" + , BootRetryTime/1000); + // Wait for 'BootRetryTime' milliseconds and then reboot. diff --git a/images/qemu/patches/seabios/README.md b/images/qemu/patches/seabios/README.md new file mode 100644 index 0000000000..7829f2be27 --- /dev/null +++ b/images/qemu/patches/seabios/README.md @@ -0,0 +1,11 @@ +# Patches + +## 001-alt-skip-flags-when-parse-objdump-section.patch + +This patch makes `scripts/layoutrom.py` tolerate extra flags in `objdump` +section output. + +## 002-0x403-debug-port-no-bootable-device-message.patch + +If SeaBIOS cannot find a bootable device on QEMU, this patch also outputs +`No bootable device.` to the debug device at address `0x403`. diff --git a/images/qemu/werf.inc.yaml b/images/qemu/werf.inc.yaml index 019a5f5d58..d1a0a2e220 100644 --- a/images/qemu/werf.inc.yaml +++ b/images/qemu/werf.inc.yaml @@ -62,6 +62,14 @@ shell: fi + echo "Apply SeaBIOS patches" + for p in /patches/seabios/*.patch ; do + [ -f "$p" ] || continue + git -C roms/seabios apply --check --ignore-space-change --ignore-whitespace "$p" >/dev/null 2>&1 || (echo "FAIL" ; exit 1) + echo -n "Apply ${p} to roms/seabios ... " + git -C roms/seabios apply --ignore-space-change --ignore-whitespace "$p" && echo OK || (echo FAIL ; exit 1) + done + --- {{- $name := print $.ImageName "-dependencies" -}} {{- define "$name" -}} @@ -201,6 +209,9 @@ shell: cd /{{ $gitRepoName }}-{{ $version }} + echo "Building patched SeaBIOS..." + make -C roms bios V=1 PYTHON=python3 HOSTCC=gcc -j$(nproc) + for p in /patches/*.patch ; do echo -n "Apply ${p} ... " git apply --ignore-space-change --ignore-whitespace ${p} && echo OK || (echo FAIL ; exit 1) @@ -346,7 +357,6 @@ shell: {{- $_ := set $ "ProjectName" (list $.ImageName "qemu" | join "/") }} {{- include "image-build.build" (set $ "BuildCommand" `make -j$(nproc)`) | nindent 6 }} - setup: - | /install-qemu.sh --version-num "{{ $version }}" \ diff --git a/images/virt-artifact/werf.inc.yaml b/images/virt-artifact/werf.inc.yaml index f30560fba6..2fe6d1cae8 100644 --- a/images/virt-artifact/werf.inc.yaml +++ b/images/virt-artifact/werf.inc.yaml @@ -16,7 +16,8 @@ shell: install: - | echo "Git clone {{ $gitRepoName }} repository..." - git clone --depth=1 $(cat /run/secrets/SOURCE_REPO)/{{ $gitRepoUrl }} --branch {{ $tag }} /src/kubevirt + echo "kek231dddd" + git clone --depth=1 $(cat /run/secrets/SOURCE_REPO)/{{ $gitRepoUrl }} --branch v1.6.2-virtualization-no-bootable /src/kubevirt rm -rf /src/kubevirt/.git diff --git a/images/virtualization-artifact/pkg/controller/vm/internal/lifecycle.go b/images/virtualization-artifact/pkg/controller/vm/internal/lifecycle.go index 4f694654c0..714522bf34 100644 --- a/images/virtualization-artifact/pkg/controller/vm/internal/lifecycle.go +++ b/images/virtualization-artifact/pkg/controller/vm/internal/lifecycle.go @@ -206,6 +206,14 @@ func (h *LifeCycleHandler) syncRunning(ctx context.Context, vm *v1alpha2.Virtual if kvvmi != nil && vm.Status.Phase != v1alpha2.MachineStopped { vm.Status.Node = kvvmi.Status.NodeName + for _, c := range kvvmi.Status.Conditions { + if string(c.Type) == "BootFailed" { + cb.Reason(vmcondition.ReasonBootFailed).Status(metav1.ConditionFalse).Message(c.Reason) + conditions.SetCondition(cb, &vm.Status.Conditions) + return nil + } + } + if vm.Status.Phase == v1alpha2.MachineRunning { cb.Reason(vmcondition.ReasonVirtualMachineRunning).Status(metav1.ConditionTrue) conditions.SetCondition(cb, &vm.Status.Conditions)