diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2025-07-13 01:44:51 -0400 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2025-07-13 01:44:51 -0400 |
commit | 3adbf0bb8a78f17a1e9390b59e51eb1a47d8ac98 (patch) | |
tree | a5dbe172f85a5e3b9ec908729bde174a1275b6f9 | |
parent | 43ec52b4c875f23ab041dd3de906cfacbd0d1a9d (diff) | |
parent | 693b3039d77195953e70f008991c80bf9c5b9691 (diff) | |
download | qemu-3adbf0bb8a78f17a1e9390b59e51eb1a47d8ac98.zip qemu-3adbf0bb8a78f17a1e9390b59e51eb1a47d8ac98.tar.gz qemu-3adbf0bb8a78f17a1e9390b59e51eb1a47d8ac98.tar.bz2 |
Merge tag 'pull-request-2025-07-11' of https://gitlab.com/thuth/qemu into staging
* s390x: Allow to select different entries when booting via pxelinux.cfg
* Link s390-ccw.img statically
* Fix broken bamboo functional test
* s390x code cleanups and refactorings
# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCgAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmhw2i0RHHRodXRoQHJl
# ZGhhdC5jb20ACgkQLtnXdP5wLbUGtA//XVr5t2/iH+zFdaHHFglMtYkqwyYspa/O
# zGPgcIZptQrzlbR+GFJwd4ae1HWb60E1YDyC7M1iWGQXeMNrDgeJJjUQfhB7693Y
# CPT1FCWaqXdrTHQJhf5+EGJZopwY1K4EHs+bMxCpU3ManD+MKuXzCgOMzZATnPUZ
# EcvOrzDBfEFEzQn5COUi5FF5Ds4DpOqQY1g1tpG92hQwWeAgdPPXSYlakG64Hm8C
# Km6BzAcylrRiHdORk3GeMJ1cPQ3vCjMrjTd87ra/xuH+DvPeyZ31cRIWIP1dn44x
# eog5dWo7pNmwfU50c4w/6dTSqwHG/bD/2ZPJH2nnJDLK02WeguantPN43fdoPU0c
# NEMldVE5GAqEr7Sbd5YIw9lBqrROIDfeUAxje4VZa1gSY4N/GYMGEZaM5vqYJJTP
# 0ndWP83QdamWuE0eOYMA+4oZiPpW79+Igv/PV13lsm9JgvO0WQisPFxE0cZqMTQp
# +wgbQ69rpyMiQxpusiL/6LA3khDyC8Z8g7cmjBfpqgwmVAZp7ly+GLk+ctG0zsjE
# hB99hkujZVkBZQLnVs0C/pXn1NdJ0wEupiHOSsVlQtqzNHlbweRJoxuGSp4Rl0Et
# 0DnTr3YHB6bdvRazaKzlkBHLLAXKEw0/xaRWGbE4tftZIrkOEeE0LMLLaLWLNKhX
# rqRoxq00OPs=
# =SOH3
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 11 Jul 2025 05:32:29 EDT
# gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg: issuer "thuth@redhat.com"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full]
# gpg: aka "Thomas Huth <thuth@redhat.com>" [full]
# gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full]
# gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5
* tag 'pull-request-2025-07-11' of https://gitlab.com/thuth/qemu:
target/s390x: Have s390_cpu_halt() not return anything
target/s390x: Expose s390_count_running_cpus() method
target/s390x: Remove unused s390_cpu_[un]halt() user stubs
tests/functional/test_ppc_bamboo: Replace broken link with working assets
tests/functional: Add dependency to the keymap_targets
pc-bios: Update the s390 bios images with the pxelinux.cfg loadparm changes
pc-bios/s390-ccw: link statically
tests/functional: Add a test for s390x pxelinux.cfg network booting
pc-bios/s390-ccw: Add a boot menu for booting via pxelinux.cfg
pc-bios/s390-ccw: Make get_boot_index() from menu.c global
pc-bios/s390-ccw: Allow up to 31 entries for pxelinux.cfg
pc-bios/s390-ccw: Allow to select a different pxelinux.cfg entry via loadparm
hw/s390x/s390-pci-bus.c: Use g_assert_not_reached() in functions taking an ett
target/s390x/tcg: Use vaddr in s390_probe_access()
target/s390x/kvm: Use vaddr in find/insert_hw_breakpoint()
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | hw/s390x/s390-pci-bus.c | 26 | ||||
-rw-r--r-- | pc-bios/s390-ccw.img | bin | 96000 -> 87824 bytes | |||
-rw-r--r-- | pc-bios/s390-ccw/Makefile | 2 | ||||
-rw-r--r-- | pc-bios/s390-ccw/menu.c | 6 | ||||
-rw-r--r-- | pc-bios/s390-ccw/netmain.c | 66 | ||||
-rw-r--r-- | pc-bios/s390-ccw/s390-ccw.h | 1 | ||||
-rw-r--r-- | target/s390x/cpu-system.c | 6 | ||||
-rw-r--r-- | target/s390x/helper.c | 4 | ||||
-rw-r--r-- | target/s390x/kvm/kvm.c | 4 | ||||
-rw-r--r-- | target/s390x/s390x-internal.h | 13 | ||||
-rw-r--r-- | target/s390x/tcg/mem_helper.c | 10 | ||||
-rw-r--r-- | tests/functional/meson.build | 3 | ||||
-rwxr-xr-x | tests/functional/test_ppc_bamboo.py | 34 | ||||
-rwxr-xr-x | tests/functional/test_s390x_pxelinux.py | 119 |
15 files changed, 227 insertions, 68 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 1842c3d..e88ed2c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1805,6 +1805,7 @@ F: hw/s390x/ipl.* F: pc-bios/s390-ccw/ F: pc-bios/s390-ccw.img F: docs/devel/s390-dasd-ipl.rst +F: tests/functional/test_s390x_pxelinux.py T: git https://github.com/borntraeger/qemu.git s390-next L: qemu-s390x@nongnu.org diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index e6aa445..f87d274 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -384,9 +384,9 @@ static uint64_t get_table_index(uint64_t iova, int8_t ett) return calc_sx(iova); case ZPCI_ETT_RT: return calc_rtx(iova); + default: + g_assert_not_reached(); } - - return -1; } static bool entry_isvalid(uint64_t entry, int8_t ett) @@ -397,22 +397,24 @@ static bool entry_isvalid(uint64_t entry, int8_t ett) case ZPCI_ETT_ST: case ZPCI_ETT_RT: return rt_entry_isvalid(entry); + default: + g_assert_not_reached(); } - - return false; } /* Return true if address translation is done */ static bool translate_iscomplete(uint64_t entry, int8_t ett) { switch (ett) { - case 0: + case ZPCI_ETT_ST: return (entry & ZPCI_TABLE_FC) ? true : false; - case 1: + case ZPCI_ETT_RT: return false; + case ZPCI_ETT_PT: + return true; + default: + g_assert_not_reached(); } - - return true; } static uint64_t get_frame_size(int8_t ett) @@ -424,9 +426,9 @@ static uint64_t get_frame_size(int8_t ett) return 1ULL << 20; case ZPCI_ETT_RT: return 1ULL << 31; + default: + g_assert_not_reached(); } - - return 0; } static uint64_t get_next_table_origin(uint64_t entry, int8_t ett) @@ -438,9 +440,9 @@ static uint64_t get_next_table_origin(uint64_t entry, int8_t ett) return get_st_pto(entry); case ZPCI_ETT_RT: return get_rt_sto(entry); + default: + g_assert_not_reached(); } - - return 0; } /** diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img Binary files differindex 47240f0..ff60978 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index dc69dd4..a0f24c9 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -47,7 +47,7 @@ EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables EXTRA_CFLAGS += -msoft-float EXTRA_CFLAGS += -std=gnu99 EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC) -EXTRA_LDFLAGS += -Wl,-pie -nostdlib -z noexecstack -z text +EXTRA_LDFLAGS += -static-pie -nostdlib -z noexecstack -z text cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null cc-option = if $(call cc-test, $1); then \ diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index 84062e9..eeaff78 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -159,7 +159,7 @@ static void boot_menu_prompt(bool retry) } } -static int get_boot_index(bool *valid_entries) +int menu_get_boot_index(bool *valid_entries) { int boot_index; bool retry = false; @@ -224,7 +224,7 @@ int menu_get_zipl_boot_index(const char *menu_data) } printf("\n"); - return get_boot_index(valid_entries); + return menu_get_boot_index(valid_entries); } int menu_get_enum_boot_index(bool *valid_entries) @@ -247,7 +247,7 @@ int menu_get_enum_boot_index(bool *valid_entries) } printf("\n"); - return get_boot_index(valid_entries); + return menu_get_boot_index(valid_entries); } void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout) diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index 719a547..a9521df 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -332,22 +332,64 @@ static int load_kernel_with_initrd(filename_ip_t *fn_ip, return rc; } -#define MAX_PXELINUX_ENTRIES 16 +static int net_boot_menu(int num_ent, int def_ent, + struct pl_cfg_entry *entries) +{ + bool valid_entries[MAX_BOOT_ENTRIES] = { false }; + int idx; + + puts("\ns390-ccw pxelinux.cfg boot menu:\n"); + printf(" [0] default (%d)\n", def_ent + 1); + valid_entries[0] = true; + + for (idx = 1; idx <= num_ent; idx++) { + printf(" [%d] %s\n", idx, entries[idx - 1].label); + valid_entries[idx] = true; + } + putchar('\n'); + + idx = menu_get_boot_index(valid_entries); + putchar('\n'); + + return idx; +} + +static int net_select_and_load_kernel(filename_ip_t *fn_ip, + int num_ent, int selected, + struct pl_cfg_entry *entries) +{ + unsigned int loadparm = get_loadparm_index(); + + if (num_ent <= 0) { + return -1; + } + + if (menu_is_enabled_enum() && num_ent > 1) { + loadparm = net_boot_menu(num_ent, selected, entries); + } + + IPL_assert(loadparm <= num_ent, + "loadparm is set to an entry that is not available in the " + "pxelinux.cfg file!"); + + if (loadparm > 0) { + selected = loadparm - 1; + } + + return load_kernel_with_initrd(fn_ip, &entries[selected]); +} static int net_try_pxelinux_cfg(filename_ip_t *fn_ip) { - struct pl_cfg_entry entries[MAX_PXELINUX_ENTRIES]; + struct pl_cfg_entry entries[MAX_BOOT_ENTRIES]; int num_ent, def_ent = 0; num_ent = pxelinux_load_parse_cfg(fn_ip, mac, get_uuid(), DEFAULT_TFTP_RETRIES, cfgbuf, sizeof(cfgbuf), - entries, MAX_PXELINUX_ENTRIES, &def_ent); - if (num_ent > 0) { - return load_kernel_with_initrd(fn_ip, &entries[def_ent]); - } + entries, MAX_BOOT_ENTRIES, &def_ent); - return -1; + return net_select_and_load_kernel(fn_ip, num_ent, def_ent, entries); } /** @@ -428,15 +470,13 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip) * a magic comment string. */ if (!strncasecmp("# pxelinux", cfgbuf, 10)) { - struct pl_cfg_entry entries[MAX_PXELINUX_ENTRIES]; + struct pl_cfg_entry entries[MAX_BOOT_ENTRIES]; int num_ent, def_ent = 0; num_ent = pxelinux_parse_cfg(cfgbuf, sizeof(cfgbuf), entries, - MAX_PXELINUX_ENTRIES, &def_ent); - if (num_ent <= 0) { - return -1; - } - return load_kernel_with_initrd(fn_ip, &entries[def_ent]); + MAX_BOOT_ENTRIES, &def_ent); + return net_select_and_load_kernel(fn_ip, num_ent, def_ent, + entries); } } diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 6cdce3e..b1dc35c 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -87,6 +87,7 @@ int menu_get_zipl_boot_index(const char *menu_data); bool menu_is_enabled_zipl(void); int menu_get_enum_boot_index(bool *valid_entries); bool menu_is_enabled_enum(void); +int menu_get_boot_index(bool *valid_entries); #define MAX_BOOT_ENTRIES 31 diff --git a/target/s390x/cpu-system.c b/target/s390x/cpu-system.c index 9b380e3..709ccd5 100644 --- a/target/s390x/cpu-system.c +++ b/target/s390x/cpu-system.c @@ -196,7 +196,7 @@ static bool disabled_wait(CPUState *cpu) (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK)); } -static unsigned s390_count_running_cpus(void) +unsigned s390_count_running_cpus(void) { CPUState *cpu; int nr_running = 0; @@ -214,7 +214,7 @@ static unsigned s390_count_running_cpus(void) return nr_running; } -unsigned int s390_cpu_halt(S390CPU *cpu) +void s390_cpu_halt(S390CPU *cpu) { CPUState *cs = CPU(cpu); trace_cpu_halt(cs->cpu_index); @@ -223,8 +223,6 @@ unsigned int s390_cpu_halt(S390CPU *cpu) cs->halted = 1; cs->exception_index = EXCP_HLT; } - - return s390_count_running_cpus(); } void s390_cpu_unhalt(S390CPU *cpu) diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 3c57c32..5c127da 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -91,7 +91,9 @@ void s390_handle_wait(S390CPU *cpu) { CPUState *cs = CPU(cpu); - if (s390_cpu_halt(cpu) == 0) { + s390_cpu_halt(cpu); + + if (s390_count_running_cpus() == 0) { if (is_special_wait_psw(cpu->env.psw.addr)) { qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); } else { diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 67d9a19..491cc5f 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -889,7 +889,7 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) return 0; } -static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr, +static struct kvm_hw_breakpoint *find_hw_breakpoint(vaddr addr, int len, int type) { int n; @@ -904,7 +904,7 @@ static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr, return NULL; } -static int insert_hw_breakpoint(target_ulong addr, int len, int type) +static int insert_hw_breakpoint(vaddr addr, int len, int type) { int size; diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h index a4ba622..56cce2e 100644 --- a/target/s390x/s390x-internal.h +++ b/target/s390x/s390x-internal.h @@ -238,7 +238,8 @@ uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, /* cpu.c */ #ifndef CONFIG_USER_ONLY -unsigned int s390_cpu_halt(S390CPU *cpu); +unsigned int s390_count_running_cpus(void); +void s390_cpu_halt(S390CPU *cpu); void s390_cpu_unhalt(S390CPU *cpu); void s390_cpu_system_init(Object *obj); bool s390_cpu_system_realize(DeviceState *dev, Error **errp); @@ -246,16 +247,6 @@ void s390_cpu_finalize(Object *obj); void s390_cpu_system_class_init(CPUClass *cc); void s390_cpu_machine_reset_cb(void *opaque); bool s390_cpu_has_work(CPUState *cs); - -#else -static inline unsigned int s390_cpu_halt(S390CPU *cpu) -{ - return 0; -} - -static inline void s390_cpu_unhalt(S390CPU *cpu) -{ -} #endif /* CONFIG_USER_ONLY */ diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index a03609a..f1acb16 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -126,8 +126,8 @@ static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr, /* An access covers at most 4096 bytes and therefore at most two pages. */ typedef struct S390Access { - target_ulong vaddr1; - target_ulong vaddr2; + vaddr vaddr1; + vaddr vaddr2; void *haddr1; void *haddr2; uint16_t size1; @@ -148,7 +148,7 @@ typedef struct S390Access { * For !CONFIG_USER_ONLY, the TEC is stored stored to env->tlb_fill_tec. * For CONFIG_USER_ONLY, the faulting address is stored to env->__excp_addr. */ -static inline int s390_probe_access(CPUArchState *env, target_ulong addr, +static inline int s390_probe_access(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t ra) @@ -258,7 +258,7 @@ static void access_memset(CPUS390XState *env, S390Access *desta, static uint8_t access_get_byte(CPUS390XState *env, S390Access *access, int offset, uintptr_t ra) { - target_ulong vaddr = access->vaddr1; + vaddr vaddr = access->vaddr1; void *haddr = access->haddr1; if (unlikely(offset >= access->size1)) { @@ -278,7 +278,7 @@ static uint8_t access_get_byte(CPUS390XState *env, S390Access *access, static void access_set_byte(CPUS390XState *env, S390Access *access, int offset, uint8_t byte, uintptr_t ra) { - target_ulong vaddr = access->vaddr1; + vaddr vaddr = access->vaddr1; void *haddr = access->haddr1; if (unlikely(offset >= access->size1)) { diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 050c900..ae5c52d 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -281,6 +281,7 @@ tests_rx_system_thorough = [ tests_s390x_system_thorough = [ 's390x_ccw_virtio', + 's390x_pxelinux', 's390x_replay', 's390x_topology', 's390x_tuxrun', @@ -373,7 +374,7 @@ foreach speed : ['quick', 'thorough'] target_tests = get_variable('tests_' + target_base + '_' + sysmode + '_' + speed, []) endif - test_deps = roms + test_deps = [roms, keymap_targets] test_env = environment() if have_tools test_env.set('QEMU_TEST_QEMU_IMG', meson.global_build_root() / 'qemu-img') diff --git a/tests/functional/test_ppc_bamboo.py b/tests/functional/test_ppc_bamboo.py index fddcc24..c634ae7 100755 --- a/tests/functional/test_ppc_bamboo.py +++ b/tests/functional/test_ppc_bamboo.py @@ -16,28 +16,32 @@ class BambooMachine(QemuSystemTest): timeout = 90 - ASSET_IMAGE = Asset( - ('http://landley.net/aboriginal/downloads/binaries/' - 'system-image-powerpc-440fp.tar.gz'), - 'c12b58f841c775a0e6df4832a55afe6b74814d1565d08ddeafc1fb949a075c5e') + ASSET_KERNEL = Asset( + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc_bamboo-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'), + 'a2e12eb45b73491ac62fc0bbeb68dead0dc5c0f22cf83146558389209b420ad1') + ASSET_INITRD = Asset( + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc_bamboo-2023.11-8-gdcd9f0f6eb-20240105/rootfs.cpio'), + 'd2a36bdb8763b389765dc8c29d4904cec2bd001c587f92e85ab9eb10d5ddda54') def test_ppc_bamboo(self): self.set_machine('bamboo') self.require_accelerator("tcg") self.require_netdev('user') - self.archive_extract(self.ASSET_IMAGE) + + kernel = self.ASSET_KERNEL.fetch() + initrd = self.ASSET_INITRD.fetch() + self.vm.set_console() - self.vm.add_args('-kernel', - self.scratch_file('system-image-powerpc-440fp', - 'linux'), - '-initrd', - self.scratch_file('system-image-powerpc-440fp', - 'rootfs.cpio.gz'), - '-nic', 'user,model=rtl8139,restrict=on') + self.vm.add_args('-kernel', kernel, + '-initrd', initrd, + '-nic', 'user,model=virtio-net-pci,restrict=on') self.vm.launch() - wait_for_console_pattern(self, 'Type exit when done') - exec_command_and_wait_for_pattern(self, 'ping 10.0.2.2', - '10.0.2.2 is alive!') + wait_for_console_pattern(self, 'buildroot login:') + exec_command_and_wait_for_pattern(self, 'root', '#') + exec_command_and_wait_for_pattern(self, 'ping -c1 10.0.2.2', + '1 packets transmitted, 1 packets received, 0% packet loss') exec_command_and_wait_for_pattern(self, 'halt', 'System Halted') if __name__ == '__main__': diff --git a/tests/functional/test_s390x_pxelinux.py b/tests/functional/test_s390x_pxelinux.py new file mode 100755 index 0000000..4fc33b8 --- /dev/null +++ b/tests/functional/test_s390x_pxelinux.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Functional test that checks the pxelinux.cfg network booting of a s390x VM +# (TFTP booting without config file is already tested by the pxe qtest, so +# we don't repeat that here). + +import os +import shutil + +from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern + + +pxelinux_cfg_contents='''# pxelinux.cfg style config file +default Debian +label Nonexisting +kernel kernel.notavailable +initrd initrd.notavailable +label Debian +kernel kernel.debian +initrd initrd.debian +append testoption=teststring +label Fedora +kernel kernel.fedora +''' + +class S390PxeLinux(QemuSystemTest): + + ASSET_DEBIAN_KERNEL = Asset( + ('https://snapshot.debian.org/archive/debian/' + '20201126T092837Z/dists/buster/main/installer-s390x/' + '20190702+deb10u6/images/generic/kernel.debian'), + 'd411d17c39ae7ad38d27534376cbe88b68b403c325739364122c2e6f1537e818') + + ASSET_DEBIAN_INITRD = Asset( + ('https://snapshot.debian.org/archive/debian/' + '20201126T092837Z/dists/buster/main/installer-s390x/' + '20190702+deb10u6/images/generic/initrd.debian'), + '836bbd0fe6a5ca81274c28c2b063ea315ce1868660866e9b60180c575fef9fd5') + + ASSET_FEDORA_KERNEL = Asset( + ('https://archives.fedoraproject.org/pub/archive' + '/fedora-secondary/releases/31/Server/s390x/os' + '/images/kernel.img'), + '480859574f3f44caa6cd35c62d70e1ac0609134e22ce2a954bbed9b110c06e0b') + + def pxelinux_launch(self, pl_name='default', extra_opts=None): + self.require_netdev('user') + self.set_machine('s390-ccw-virtio') + + debian_kernel = self.ASSET_DEBIAN_KERNEL.fetch() + debian_initrd = self.ASSET_DEBIAN_INITRD.fetch() + fedora_kernel = self.ASSET_FEDORA_KERNEL.fetch() + + # Prepare a folder for the TFTP "server": + tftpdir = self.scratch_file('tftp') + shutil.rmtree(tftpdir, ignore_errors=True) # Remove stale stuff + os.mkdir(tftpdir) + shutil.copy(debian_kernel, os.path.join(tftpdir, 'kernel.debian')) + shutil.copy(debian_initrd, os.path.join(tftpdir, 'initrd.debian')) + shutil.copy(fedora_kernel, os.path.join(tftpdir, 'kernel.fedora')) + + pxelinuxdir = self.scratch_file('tftp', 'pxelinux.cfg') + os.mkdir(pxelinuxdir) + + cfg_fname = self.scratch_file('tftp', 'pxelinux.cfg', pl_name) + with open(cfg_fname, 'w', encoding='utf-8') as f: + f.write(pxelinux_cfg_contents) + + virtio_net_dev = 'virtio-net-ccw,netdev=n1,bootindex=1' + if extra_opts: + virtio_net_dev += ',' + extra_opts + + self.vm.add_args('-m', '384', + '-netdev', f'user,id=n1,tftp={tftpdir}', + '-device', virtio_net_dev) + self.vm.set_console() + self.vm.launch() + + + def test_default(self): + self.pxelinux_launch() + # The kernel prints its arguments to the console, so we can use + # this to check whether the kernel parameters are correctly handled: + wait_for_console_pattern(self, 'testoption=teststring') + # Now also check that we've successfully loaded the initrd: + wait_for_console_pattern(self, 'Unpacking initramfs...') + wait_for_console_pattern(self, 'Run /init as init process') + + def test_mac(self): + self.pxelinux_launch(pl_name='01-02-ca-fe-ba-be-42', + extra_opts='mac=02:ca:fe:ba:be:42,loadparm=3') + wait_for_console_pattern(self, 'Linux version 5.3.7-301.fc31.s390x') + + def test_uuid(self): + # Also add a non-bootable disk to check the fallback to network boot: + self.vm.add_args('-blockdev', 'null-co,size=65536,node-name=d1', + '-device', 'virtio-blk,drive=d1,bootindex=0,loadparm=1', + '-uuid', '550e8400-e29b-11d4-a716-446655441234') + self.pxelinux_launch(pl_name='550e8400-e29b-11d4-a716-446655441234') + wait_for_console_pattern(self, 'Debian 4.19.146-1 (2020-09-17)') + + def test_ip(self): + self.vm.add_args('-M', 'loadparm=3') + self.pxelinux_launch(pl_name='0A00020F') + wait_for_console_pattern(self, 'Linux version 5.3.7-301.fc31.s390x') + + def test_menu(self): + self.vm.add_args('-boot', 'menu=on,splash-time=10') + self.pxelinux_launch(pl_name='0A00') + wait_for_console_pattern(self, '[1] Nonexisting') + wait_for_console_pattern(self, '[2] Debian') + wait_for_console_pattern(self, '[3] Fedora') + wait_for_console_pattern(self, 'Debian 4.19.146-1 (2020-09-17)') + + +if __name__ == '__main__': + QemuSystemTest.main() |