From 96dcf1aaca4fcf3c837f8297cf22dfdb6ab2249d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 23 Feb 2023 20:32:57 +0100 Subject: [PATCH 01/13] docs/about/build-platforms: Refine the distro support policy For long-term distributions that release a new version only very seldom, we limit the support to five years after the initial release. Otherwise, we might need to support distros like openSUSE 15 for up to 7 or even more years in total due to our "two more years after the next major release" rule, which is just way too much to handle in a project like QEMU that only has limited human resources. Message-Id: <20230223193257.1068205-1-thuth@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Thomas Huth --- docs/about/build-platforms.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index 20b97c3310..89cae5a6bb 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -67,7 +67,8 @@ Non-supported architectures may be removed in the future following the Linux OS, macOS, FreeBSD, NetBSD, OpenBSD ----------------------------------------- -The project aims to support the most recent major version at all times. Support +The project aims to support the most recent major version at all times for +up to five years after its initial release. Support for the previous major version will be dropped 2 years after the new major version is released or when the vendor itself drops support, whichever comes first. In this context, third-party efforts to extend the lifetime of a distro From 243ec1c284af7676847cedadf42a8d4465a123e9 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Tue, 7 Feb 2023 11:52:31 -0300 Subject: [PATCH 02/13] Hexagon (meson.build): define min bison version Hexagon's idef-parser machinery uses some bison features that are not available at older versions. The most preeminent example (as it can be used as a sentinel) is "%define parse.error verbose". This was introduced in version 3.0 of the tool, which is able to compile qemu-hexagon just fine. However, compilation fails with the previous minor bison release, v2.7. So let's assert the minimum version at meson.build to give a more comprehensive error message for those trying to compile QEMU. [1]: https://www.gnu.org/software/bison/manual/html_node/_0025define-Summary.html#index-_0025define-parse_002eerror Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Thomas Huth Reviewed-by: Alessandro Di Federico Reviewed-by: Taylor Simpson Message-Id: Signed-off-by: Thomas Huth --- target/hexagon/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index c9d31d095c..42b03c81e6 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -183,7 +183,7 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs ) bison = generator( - find_program('bison'), + find_program('bison', version: '>=3.0'), output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'], arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'] ) From 4d1bc58de7fa272dfa2e06a99355be5f67a4614a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 1 Mar 2023 11:44:50 +0100 Subject: [PATCH 03/13] test: Check vnc enable before compiling vnc test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan Quintela Message-Id: <20230301104450.1017-1-quintela@redhat.com> Reviewed-by: Thomas Huth Reviewed-by: Marc-André Lureau Signed-off-by: Thomas Huth --- tests/qtest/meson.build | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 29a4efb4c2..62eecf2edf 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -309,10 +309,12 @@ qtests = { 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), } -gvnc = dependency('gvnc-1.0', required: false) -if gvnc.found() - qtests += {'vnc-display-test': [gvnc]} - qtests_generic += [ 'vnc-display-test' ] +if vnc.found() + gvnc = dependency('gvnc-1.0', required: false) + if gvnc.found() + qtests += {'vnc-display-test': [gvnc]} + qtests_generic += [ 'vnc-display-test' ] + endif endif if dbus_display From 094f40be27ff2df74da1b7a3397e4acd95c1c6fa Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 8 Feb 2023 15:34:48 +0100 Subject: [PATCH 04/13] include/hw/i386: Clean up includes in x86.h nmi.h and notify.h are not needed here, drop them to speed up the compiling a little bit. Message-Id: <20230210111438.1114600-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- include/hw/i386/x86.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 0b337a036c..da19ae1546 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -18,10 +18,8 @@ #define HW_I386_X86_H #include "exec/hwaddr.h" -#include "qemu/notify.h" #include "hw/boards.h" -#include "hw/nmi.h" #include "hw/intc/ioapic.h" #include "hw/isa/isa.h" #include "qom/object.h" From 5c27baf9519a990729e864cf984e08e15f3d9431 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 6 Mar 2023 09:46:54 +0100 Subject: [PATCH 05/13] docs/about/deprecated: Deprecate 32-bit x86 hosts for system emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardly anybody still uses 32-bit x86 hosts today, so we should start deprecating them to stop wasting our time and CI minutes here. Reviewed-by: Daniel P. Berrangé Reviewed-by: Wilfred Mallawa Message-Id: <20230306084658.29709-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/about/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 15084f7bea..1ca9dc33d6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -196,6 +196,17 @@ CI coverage support may bitrot away before the deprecation process completes. The little endian variants of MIPS (both 32 and 64 bit) are still a supported host architecture. +System emulation on 32-bit x86 hosts (since 8.0) +'''''''''''''''''''''''''''''''''''''''''''''''' + +Support for 32-bit x86 host deployments is increasingly uncommon in mainstream +OS distributions given the widespread availability of 64-bit x86 hardware. +The QEMU project no longer considers 32-bit x86 support for system emulation to +be an effective use of its limited resources, and thus intends to discontinue +it. Since all recent x86 hardware from the past >10 years is capable of the +64-bit x86 extensions, a corresponding 64-bit OS should be used instead. + + QEMU API (QAPI) events ---------------------- From 4f9a8315e65561bafa03651518aa5d22af09bdee Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 6 Mar 2023 09:46:56 +0100 Subject: [PATCH 06/13] gitlab-ci.d/crossbuilds: Drop the i386 system emulation job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardly anybody still uses 32-bit x86 environments for running QEMU with full system emulation, so let's stop wasting our scarce CI minutes with this job. (There are still the 32-bit MinGW and TCI jobs around for having some compile test coverage on 32-bit) Reviewed-by: Daniel P. Berrangé Reviewed-by: Wilfred Mallawa Message-Id: <20230306084658.29709-4-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- .gitlab-ci.d/crossbuilds.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index d3a31a2112..a25cb87ae4 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -43,16 +43,6 @@ cross-arm64-user: variables: IMAGE: debian-arm64-cross -cross-i386-system: - extends: - - .cross_system_build_job - - .cross_test_artifacts - needs: - job: i386-fedora-cross-container - variables: - IMAGE: fedora-i386-cross - MAKE_CHECK_ARGS: check-qtest - cross-i386-user: extends: - .cross_user_build_job From 1d0a8eba38cdddd028ea02c6e0b68f0a4c9a3cbf Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 6 Mar 2023 09:46:57 +0100 Subject: [PATCH 07/13] docs/about/deprecated: Deprecate 32-bit arm hosts for system emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For running QEMU in system emulation mode, the user needs a rather strong host system, i.e. not only an embedded low-frequency controller. All recent beefy arm host machines should support 64-bit now, it's unlikely that anybody is still seriously using QEMU on a 32-bit arm CPU, so we deprecate the 32-bit arm hosts here to finally save use some time and precious CI minutes. Reviewed-by: Daniel P. Berrangé Reviewed-by: Wilfred Mallawa Message-Id: <20230306084658.29709-5-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- docs/about/deprecated.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 1ca9dc33d6..33b942283f 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -206,6 +206,15 @@ be an effective use of its limited resources, and thus intends to discontinue it. Since all recent x86 hardware from the past >10 years is capable of the 64-bit x86 extensions, a corresponding 64-bit OS should be used instead. +System emulation on 32-bit arm hosts (since 8.0) +'''''''''''''''''''''''''''''''''''''''''''''''' + +Since QEMU needs a strong host machine for running full system emulation, and +all recent powerful arm hosts support 64-bit, the QEMU project deprecates the +support for running any system emulation on 32-bit arm hosts in general. Use +64-bit arm hosts for system emulation instead. (Note: "user" mode emulation +continues to be supported on 32-bit arm hosts, too) + QEMU API (QAPI) events ---------------------- From 3f0760ea3136cc65b0254823af89133d0a35e0d9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 6 Mar 2023 09:46:58 +0100 Subject: [PATCH 08/13] gitlab-ci.d/crossbuilds: Drop the 32-bit arm system emulation jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardly anybody still uses 32-bit arm environments for running QEMU, so let's stop wasting our scarce CI minutes with these jobs. Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Wilfred Mallawa Message-Id: <20230306084658.29709-6-thuth@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/crossbuilds.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index a25cb87ae4..61b8ac86ee 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -1,13 +1,6 @@ include: - local: '/.gitlab-ci.d/crossbuild-template.yml' -cross-armel-system: - extends: .cross_system_build_job - needs: - job: armel-debian-cross-container - variables: - IMAGE: debian-armel-cross - cross-armel-user: extends: .cross_user_build_job needs: @@ -15,13 +8,6 @@ cross-armel-user: variables: IMAGE: debian-armel-cross -cross-armhf-system: - extends: .cross_system_build_job - needs: - job: armhf-debian-cross-container - variables: - IMAGE: debian-armhf-cross - cross-armhf-user: extends: .cross_user_build_job needs: From 79571e7f141139338df795229cfb06f2845134da Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 28 Feb 2023 22:15:28 +0100 Subject: [PATCH 09/13] tests/qtest/readconfig: Rework test_object_rng_resp into a generic function test_object_rng_resp() can be reworked quite easily to allow testing for arbitrary objects in the qom-list response. Message-Id: <20230228211533.201837-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/qtest/readconfig-test.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/qtest/readconfig-test.c b/tests/qtest/readconfig-test.c index 9ef870643d..26d79b5e4b 100644 --- a/tests/qtest/readconfig-test.c +++ b/tests/qtest/readconfig-test.c @@ -124,13 +124,15 @@ static void test_spice(void) } #endif -static void test_object_rng_resp(QObject *res) +static void test_object_available(QObject *res, const char *name, + const char *type) { Visitor *v; g_autoptr(ObjectPropertyInfoList) objs = NULL; ObjectPropertyInfoList *tmp; ObjectPropertyInfo *obj; - bool seen_rng = false; + bool object_available = false; + g_autofree char *childtype = g_strdup_printf("child<%s>", type); g_assert(res); v = qobject_input_visitor_new(res); @@ -142,16 +144,15 @@ static void test_object_rng_resp(QObject *res) g_assert(tmp->value); obj = tmp->value; - if (g_str_equal(obj->name, "rng0") && - g_str_equal(obj->type, "child")) { - seen_rng = true; + if (g_str_equal(obj->name, name) && g_str_equal(obj->type, childtype)) { + object_available = true; break; } tmp = tmp->next; } - g_assert(seen_rng); + g_assert(object_available); visit_free(v); } @@ -170,7 +171,7 @@ static void test_object_rng(void) resp = qtest_qmp(qts, "{ 'execute': 'qom-list'," " 'arguments': {'path': '/objects' }}"); - test_object_rng_resp(qdict_get(resp, "return")); + test_object_available(qdict_get(resp, "return"), "rng0", "rng-builtin"); qobject_unref(resp); qtest_quit(qts); From 201aa17efd4ddd512d6a04b98847424c6178318d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 28 Feb 2023 22:15:29 +0100 Subject: [PATCH 10/13] tests/qtest/readconfig: Test docs/config/ich9-ehci-uhci.cfg We've got some sample config files in docs/config/ but no means of regression checking them. Thus let's test them in our readconfig qtest, starting with ich9-ehci-uhci.cfg. Note: To enable the test to read the config files from the build folder, we have to install a symlink for docs/config in the build directory. Message-Id: <20230228211533.201837-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- configure | 1 + tests/qtest/readconfig-test.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/configure b/configure index 219ff13748..7290493729 100755 --- a/configure +++ b/configure @@ -2262,6 +2262,7 @@ fi # tests might fail. Prefer to keep the relevant files in their own # directory and symlink the directory instead. LINKS="Makefile" +LINKS="$LINKS docs/config" LINKS="$LINKS pc-bios/optionrom/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" LINKS="$LINKS pc-bios/vof/Makefile" diff --git a/tests/qtest/readconfig-test.c b/tests/qtest/readconfig-test.c index 26d79b5e4b..2160603880 100644 --- a/tests/qtest/readconfig-test.c +++ b/tests/qtest/readconfig-test.c @@ -177,6 +177,26 @@ static void test_object_rng(void) qtest_quit(qts); } +static void test_docs_config_ich9(void) +{ + QTestState *qts; + QDict *resp; + QObject *qobj; + + qts = qtest_initf("-nodefaults -readconfig docs/config/ich9-ehci-uhci.cfg"); + + resp = qtest_qmp(qts, "{ 'execute': 'qom-list'," + " 'arguments': {'path': '/machine/peripheral' }}"); + qobj = qdict_get(resp, "return"); + test_object_available(qobj, "ehci", "ich9-usb-ehci1"); + test_object_available(qobj, "uhci-1", "ich9-usb-uhci1"); + test_object_available(qobj, "uhci-2", "ich9-usb-uhci2"); + test_object_available(qobj, "uhci-3", "ich9-usb-uhci3"); + qobject_unref(resp); + + qtest_quit(qts); +} + int main(int argc, char *argv[]) { const char *arch; @@ -187,6 +207,7 @@ int main(int argc, char *argv[]) if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) { qtest_add_func("readconfig/x86/memdev", test_x86_memdev); + qtest_add_func("readconfig/x86/ich9-ehci-uhci", test_docs_config_ich9); } #ifdef CONFIG_SPICE qtest_add_func("readconfig/spice", test_spice); From 4477035ec685be4c20d1213779f7ca00e867c3b8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 28 Feb 2023 22:15:30 +0100 Subject: [PATCH 11/13] docs/config: Set the "kvm" accelerator via "[accel]" section Configuring the accelerator should nowadays be done via the "-accel" command line parameter, and thus via the "[accel]" section in config files. We also need this change for the upcoming qtests that will use these config files, since the qtests are already using "-accel" for setting the "qtest" accelerator and QEMU does not like mixing "-accel ..." and "-machine accel=...". Message-Id: <20230228211533.201837-4-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/config/mach-virt-graphical.cfg | 4 +++- docs/config/mach-virt-serial.cfg | 4 +++- docs/config/q35-emulated.cfg | 2 ++ docs/config/q35-virtio-graphical.cfg | 2 ++ docs/config/q35-virtio-serial.cfg | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/config/mach-virt-graphical.cfg b/docs/config/mach-virt-graphical.cfg index d6d31b17f5..eba76eb198 100644 --- a/docs/config/mach-virt-graphical.cfg +++ b/docs/config/mach-virt-graphical.cfg @@ -56,9 +56,11 @@ [machine] type = "virt" - accel = "kvm" gic-version = "host" +[accel] + accel = "kvm" + [memory] size = "1024" diff --git a/docs/config/mach-virt-serial.cfg b/docs/config/mach-virt-serial.cfg index 18a7c83731..324b0542ff 100644 --- a/docs/config/mach-virt-serial.cfg +++ b/docs/config/mach-virt-serial.cfg @@ -62,9 +62,11 @@ [machine] type = "virt" - accel = "kvm" gic-version = "host" +[accel] + accel = "kvm" + [memory] size = "1024" diff --git a/docs/config/q35-emulated.cfg b/docs/config/q35-emulated.cfg index 99ac918e78..c8806e6d36 100644 --- a/docs/config/q35-emulated.cfg +++ b/docs/config/q35-emulated.cfg @@ -61,6 +61,8 @@ [machine] type = "q35" + +[accel] accel = "kvm" [memory] diff --git a/docs/config/q35-virtio-graphical.cfg b/docs/config/q35-virtio-graphical.cfg index 4207f11e4f..148b5d2c5e 100644 --- a/docs/config/q35-virtio-graphical.cfg +++ b/docs/config/q35-virtio-graphical.cfg @@ -55,6 +55,8 @@ [machine] type = "q35" + +[accel] accel = "kvm" [memory] diff --git a/docs/config/q35-virtio-serial.cfg b/docs/config/q35-virtio-serial.cfg index d2830aec5e..023291390e 100644 --- a/docs/config/q35-virtio-serial.cfg +++ b/docs/config/q35-virtio-serial.cfg @@ -60,6 +60,8 @@ [machine] type = "q35" + +[accel] accel = "kvm" [memory] From 8af5d141713f5d20c4bc1719eb746ef8b1746bd6 Mon Sep 17 00:00:00 2001 From: Jared Rossi Date: Tue, 21 Feb 2023 12:45:48 -0500 Subject: [PATCH 12/13] pc-bios: Add support for List-Directed IPL from ECKD DASD Check for a List Directed IPL Boot Record, which would supersede the CCW type entries. If the record is valid, proceed to use the new style pointers and perform LD-IPL. Each block pointer is interpreted as either an LD-IPL pointer or a legacy CCW pointer depending on the type of IPL initiated. In either case CCW- or LD-IPL is transparent to the user and will boot the same image regardless of which set of pointers is used. Because the interactive boot menu is only written with the old style pointers, the menu will be disabled for List Directed IPL from ECKD DASD. If the LD-IPL fails, retry the IPL using the CCW type pointers. If no LD-IPL boot record is found, simply perform CCW type IPL as usual. Signed-off-by: Jared Rossi Message-Id: <20230221174548.1866861-2-jrossi@linux.ibm.com> [thuth: Drop some superfluous parantheses] Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/bootmap.c | 161 ++++++++++++++++++++++++++++--------- pc-bios/s390-ccw/bootmap.h | 30 ++++++- 2 files changed, 150 insertions(+), 41 deletions(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 994e59c0b0..a2137449dc 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -72,42 +72,74 @@ static inline void verify_boot_info(BootInfo *bip) "Bad block size in zIPL section of the 1st record."); } -static block_number_t eckd_block_num(EckdCHS *chs) +static void eckd_format_chs(ExtEckdBlockPtr *ptr, bool ldipl, + uint64_t *c, + uint64_t *h, + uint64_t *s) +{ + if (ldipl) { + *c = ptr->ldptr.chs.cylinder; + *h = ptr->ldptr.chs.head; + *s = ptr->ldptr.chs.sector; + } else { + *c = ptr->bptr.chs.cylinder; + *h = ptr->bptr.chs.head; + *s = ptr->bptr.chs.sector; + } +} + +static block_number_t eckd_chs_to_block(uint64_t c, uint64_t h, uint64_t s) { const uint64_t sectors = virtio_get_sectors(); const uint64_t heads = virtio_get_heads(); - const uint64_t cylinder = chs->cylinder - + ((chs->head & 0xfff0) << 12); - const uint64_t head = chs->head & 0x000f; + const uint64_t cylinder = c + ((h & 0xfff0) << 12); + const uint64_t head = h & 0x000f; const block_number_t block = sectors * heads * cylinder + sectors * head - + chs->sector - - 1; /* block nr starts with zero */ + + s - 1; /* block nr starts with zero */ return block; } -static bool eckd_valid_address(BootMapPointer *p) +static block_number_t eckd_block_num(EckdCHS *chs) { - const uint64_t head = p->eckd.chs.head & 0x000f; + return eckd_chs_to_block(chs->cylinder, chs->head, chs->sector); +} +static block_number_t gen_eckd_block_num(ExtEckdBlockPtr *ptr, bool ldipl) +{ + uint64_t cyl, head, sec; + eckd_format_chs(ptr, ldipl, &cyl, &head, &sec); + return eckd_chs_to_block(cyl, head, sec); +} + +static bool eckd_valid_chs(uint64_t cyl, uint64_t head, uint64_t sector) +{ if (head >= virtio_get_heads() - || p->eckd.chs.sector > virtio_get_sectors() - || p->eckd.chs.sector <= 0) { + || sector > virtio_get_sectors() + || sector <= 0) { return false; } if (!virtio_guessed_disk_nature() && - eckd_block_num(&p->eckd.chs) >= virtio_get_blocks()) { + eckd_chs_to_block(cyl, head, sector) >= virtio_get_blocks()) { return false; } return true; } -static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address) +static bool eckd_valid_address(ExtEckdBlockPtr *ptr, bool ldipl) +{ + uint64_t cyl, head, sec; + eckd_format_chs(ptr, ldipl, &cyl, &head, &sec); + return eckd_valid_chs(cyl, head, sec); +} + +static block_number_t load_eckd_segments(block_number_t blk, bool ldipl, + uint64_t *address) { block_number_t block_nr; - int j, rc; + int j, rc, count; BootMapPointer *bprs = (void *)_bprs; bool more_data; @@ -117,7 +149,7 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address) do { more_data = false; for (j = 0;; j++) { - block_nr = eckd_block_num(&bprs[j].xeckd.bptr.chs); + block_nr = gen_eckd_block_num(&bprs[j].xeckd, ldipl); if (is_null_block_number(block_nr)) { /* end of chunk */ break; } @@ -129,11 +161,26 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address) break; } - IPL_assert(block_size_ok(bprs[j].xeckd.bptr.size), + /* List directed pointer does not store block size */ + IPL_assert(ldipl || block_size_ok(bprs[j].xeckd.bptr.size), "bad chunk block size"); - IPL_assert(eckd_valid_address(&bprs[j]), "bad chunk ECKD addr"); - if ((bprs[j].xeckd.bptr.count == 0) && unused_space(&(bprs[j+1]), + if (!eckd_valid_address(&bprs[j].xeckd, ldipl)) { + /* + * If an invalid address is found during LD-IPL then break and + * retry as CCW + */ + IPL_assert(ldipl, "bad chunk ECKD addr"); + break; + } + + if (ldipl) { + count = bprs[j].xeckd.ldptr.count; + } else { + count = bprs[j].xeckd.bptr.count; + } + + if (count == 0 && unused_space(&bprs[j + 1], sizeof(EckdBlockPtr))) { /* This is a "continue" pointer. * This ptr should be the last one in the current @@ -149,11 +196,10 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address) /* Load (count+1) blocks of code at (block_nr) * to memory (address). */ - rc = virtio_read_many(block_nr, (void *)(*address), - bprs[j].xeckd.bptr.count+1); + rc = virtio_read_many(block_nr, (void *)(*address), count + 1); IPL_assert(rc == 0, "code chunk read failed"); - *address += (bprs[j].xeckd.bptr.count+1) * virtio_get_block_size(); + *address += (count + 1) * virtio_get_block_size(); } } while (more_data); return block_nr; @@ -237,8 +283,10 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr, uint64_t address; BootMapTable *bmt = (void *)sec; BootMapScript *bms = (void *)sec; + /* The S1B block number is NULL_BLOCK_NR if and only if it's an LD-IPL */ + bool ldipl = (s1b_block_nr == NULL_BLOCK_NR); - if (menu_is_enabled_zipl()) { + if (menu_is_enabled_zipl() && !ldipl) { loadparm = eckd_get_boot_menu_index(s1b_block_nr); } @@ -249,7 +297,7 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr, memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(bmt_block_nr, sec, "Cannot read Boot Map Table"); - block_nr = eckd_block_num(&bmt->entry[loadparm].xeckd.bptr.chs); + block_nr = gen_eckd_block_num(&bmt->entry[loadparm].xeckd, ldipl); IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry"); memset(sec, FREE_SPACE_FILLER, sizeof(sec)); @@ -264,13 +312,18 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr, } address = bms->entry[i].address.load_address; - block_nr = eckd_block_num(&bms->entry[i].blkptr.xeckd.bptr.chs); + block_nr = gen_eckd_block_num(&bms->entry[i].blkptr.xeckd, ldipl); do { - block_nr = load_eckd_segments(block_nr, &address); + block_nr = load_eckd_segments(block_nr, ldipl, &address); } while (block_nr != -1); } + if (ldipl && bms->entry[i].type != BOOT_SCRIPT_EXEC) { + /* Abort LD-IPL and retry as CCW-IPL */ + return; + } + IPL_assert(bms->entry[i].type == BOOT_SCRIPT_EXEC, "Unknown script entry type"); write_reset_psw(bms->entry[i].address.load_address); /* no return */ @@ -380,6 +433,23 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode) /* no return */ } +static block_number_t eckd_find_bmt(ExtEckdBlockPtr *ptr) +{ + block_number_t blockno; + uint8_t tmp_sec[MAX_SECTOR_SIZE]; + BootRecord *br; + + blockno = gen_eckd_block_num(ptr, 0); + read_block(blockno, tmp_sec, "Cannot read boot record"); + br = (BootRecord *)tmp_sec; + if (!magic_match(br->magic, ZIPL_MAGIC)) { + /* If the boot record is invalid, return and try CCW-IPL instead */ + return NULL_BLOCK_NR; + } + + return gen_eckd_block_num(&br->pgt.xeckd, 1); +} + static void print_eckd_msg(void) { char msg[] = "Using ECKD scheme (block size *****), "; @@ -401,28 +471,43 @@ static void print_eckd_msg(void) static void ipl_eckd(void) { - XEckdMbr *mbr = (void *)sec; - LDL_VTOC *vlbl = (void *)sec; + IplVolumeLabel *vlbl = (void *)sec; + LDL_VTOC *vtoc = (void *)sec; + block_number_t ldipl_bmt; /* Boot Map Table for List-Directed IPL */ print_eckd_msg(); - /* Grab the MBR again */ - memset(sec, FREE_SPACE_FILLER, sizeof(sec)); - read_block(0, mbr, "Cannot read block 0 on DASD"); - - if (magic_match(mbr->magic, IPL1_MAGIC)) { - ipl_eckd_cdl(); /* only returns in case of error */ - return; - } - - /* LDL/CMS? */ + /* Block 2 can contain either the CDL VOL1 label or the LDL VTOC */ memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(2, vlbl, "Cannot read block 2"); - if (magic_match(vlbl->magic, CMS1_MAGIC)) { + /* + * First check for a list-directed-format pointer which would + * supersede the CCW pointer. + */ + if (eckd_valid_address((ExtEckdBlockPtr *)&vlbl->f.br, 0)) { + ldipl_bmt = eckd_find_bmt((ExtEckdBlockPtr *)&vlbl->f.br); + if (ldipl_bmt) { + sclp_print("List-Directed\n"); + /* LD-IPL does not use the S1B bock, just make it NULL */ + run_eckd_boot_script(ldipl_bmt, NULL_BLOCK_NR); + /* Only return in error, retry as CCW-IPL */ + sclp_print("Retrying IPL "); + print_eckd_msg(); + } + memset(sec, FREE_SPACE_FILLER, sizeof(sec)); + read_block(2, vtoc, "Cannot read block 2"); + } + + /* Not list-directed */ + if (magic_match(vtoc->magic, VOL1_MAGIC)) { + ipl_eckd_cdl(); /* may return in error */ + } + + if (magic_match(vtoc->magic, CMS1_MAGIC)) { ipl_eckd_ldl(ECKD_CMS); /* no return */ } - if (magic_match(vlbl->magic, LNX1_MAGIC)) { + if (magic_match(vtoc->magic, LNX1_MAGIC)) { ipl_eckd_ldl(ECKD_LDL); /* no return */ } diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h index 3946aa3f8d..d4690a88c2 100644 --- a/pc-bios/s390-ccw/bootmap.h +++ b/pc-bios/s390-ccw/bootmap.h @@ -45,9 +45,23 @@ typedef struct EckdBlockPtr { * it's 0 for TablePtr, ScriptPtr, and SectionPtr */ } __attribute__ ((packed)) EckdBlockPtr; -typedef struct ExtEckdBlockPtr { +typedef struct LdEckdCHS { + uint32_t cylinder; + uint8_t head; + uint8_t sector; +} __attribute__ ((packed)) LdEckdCHS; + +typedef struct LdEckdBlockPtr { + LdEckdCHS chs; /* cylinder/head/sector is an address of the block */ + uint8_t reserved[4]; + uint16_t count; + uint32_t pad; +} __attribute__ ((packed)) LdEckdBlockPtr; + +/* bptr is used for CCW type IPL, while ldptr is for list-directed IPL */ +typedef union ExtEckdBlockPtr { EckdBlockPtr bptr; - uint8_t reserved[8]; + LdEckdBlockPtr ldptr; } __attribute__ ((packed)) ExtEckdBlockPtr; typedef union BootMapPointer { @@ -57,6 +71,15 @@ typedef union BootMapPointer { ExtEckdBlockPtr xeckd; } __attribute__ ((packed)) BootMapPointer; +typedef struct BootRecord { + uint8_t magic[4]; + uint32_t version; + uint64_t res1; + BootMapPointer pgt; + uint8_t reserved[510 - 32]; + uint16_t os_id; +} __attribute__ ((packed)) BootRecord; + /* aka Program Table */ typedef struct BootMapTable { uint8_t magic[4]; @@ -292,7 +315,8 @@ typedef struct IplVolumeLabel { struct { unsigned char key[4]; /* == "VOL1" */ unsigned char volser[6]; - unsigned char reserved[6]; + unsigned char reserved[64]; + EckdCHS br; /* Location of Boot Record for list-directed IPL */ } f; }; } __attribute__((packed)) IplVolumeLabel; From e3b27e7985d57ce22fe0e308a27615acb07a1724 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 6 Mar 2023 12:05:10 +0100 Subject: [PATCH 13/13] pc-bios/s390-ccw: Update s390-ccw.img with the list-directed IPL fix This update includes the list-directed IPL fix from Jared Rossi. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw.img | Bin 42608 -> 42608 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 554fcbd1b7af8ea5f8f0d887fba98d52b7a8611d..c9a5a21c50b9e78a7048d456d842ddbfdf9e6ba3 100644 GIT binary patch delta 7990 zcmZu$3tZGy_P_VXD2Sp1A`A~S^k&Qp~WZ2Z_hb{ZvJ=qeCGH2{?0k~-gD3EK5!gX z9EX+KlkOWGg8w!;K58*Y?`f~~7`m#u-H_ilIQz9pW7o;23fDriQmOpO2-}nrdTCuY z#%Eu#bf^#8E(zh)hn|DJw`qmQ{?4Wsq9N>PKgT;-aa7}I)M{B~B>dnKsd)K=qFJg8 z=!E5(bKY4eh~+t-nq;*yo(*L^g1ocd;*at46zR;iG@5&Ckow4niu6`N^z=+ytq|`| zH|T4{J(|y4C~}>uc+ZAUTx)_dz9G4OcbYUJmeF&<<8aNohUORCz{izw;Wnc@TP?%_)41c-O{QPRJL zhw;m+2Fl!ZN_qpl4ZU^owj=1GuhDTS{<>M)3K?6epy{SN+i;qL{ShJGcYI!4K@{-TfY z*qYT(ZCWAvTT%tR!(cQvZgtl&WT)yWl{m|dZ##oH%uT6^BVX09s zQ%?iUJa1|*|GPaZla9Z!_=_fwsmn|Vck=x5cxW89X@dww%j`wF>~R#`x64lQP+AX? z^+?249FZPFh?K5&WUms%^@s3^8k;5u{ zcrH4Ueo&HCwleoEc67NTzFVg%j1dx3$UxKoaXe0k%VyvPo^_a|NO;<;$T3pUOPd1=`ei7c zS7ArLxbPp{b*o8#adj-?|YLmS#R zHHALhk)*1(55NL#p!da{HnR}t_jJ2s1-7q-H?_LHsT{NJXd9G$1HROT241Y8<^kW( z$g&B?RPK#=vAWK)B<}nunn{7y@jlDFq4f(Ae6Aa2v%k97w%V_XL{*vE54Y40+{(&aN-k zITiDt4hQ?kny%o?Fh5YaerWRsYCY@+{&poi0s{?sl5m&kj z^)zswr*N`0qNfGhpab$PIuSJBZA-Xvoxw~y6oM6IPpdO2zK7_Gp}pPZ+DZZ})q#ab_1t;F3N zt5rM6vO`GhEE;D{ixTIupCCo#WHO`fz|KMu)1(tGuwx9=Eq3%VcfA&e>2}HOi}%&4 zQvV8B1HuM&n;0#-PaVbT)yM&4cI^90nCk04xMw64T@1fl&g|(K$}=W!`(O;XJ9w1U~?gx)~br6xfbtdXLslGsdN`Sw6+AClgAHxlX^GXohP=sEoy5NL0v-c$ej6;l?qk z+Hv_3G@)HsG5$*VIoz9C_q=G?CUAq+H3VZ^+oUm3ehIhrlwVa{YIly^p#}#({vQ#> z0d{a3EAnRwg02rqHfarazKaK%$C!)Hh+T|PURAHxVYu`liwNPn*{>eA203;Uhk(=Z z&LAMsTb$uHoXaTk73f|#2$8o@pu+}obe+pI*h%n!L6Am>YaYi@VIr>p`x)E z@1B_D#hB$TnBRI6vUgGv}F#Scw|0F!z!T2YVZ2y)e z8?a)d=vfx!TH50Ti=JiC?^v{nxo_|Qe`Jj2r1gz4E+UARGfrUq9ODeem4uV==z=l} z?(NHIsU0x}SB4_w_7lUZd9c4wojS7|Y(ashGv%1b9PGZlg%CDO1C4nqnx(*AYc6%h zkWZCg9a5&Q7iKKXVvgNlo`;r>HX@73-NJ;hK7bNp}t z{ufL7@weyyki-=c?XUT7&ci3EzSs+}J53H2Wm^w}5U0<dt#0 z%}E+5@fqq*a|Efh>hh7G<2LHS^(?uQ{BUzMNhX^ao17;l^2qQR=#c_ToN&RGl$%S) zA*bs|`t+-0r|vZvT7%s^YpBxFU_Ns>T2DZU{~%L89)20_qADh9kKlqP&aIc$DtsSZ zFRahvyBXh$@clW`7vp;uX81CvI|t0*lCTw5oaf1n)}`bs>vK*w-gp7&CG5s}?Gnl}a zgcyAVCI;wzG$NlN z&tS~CcVh}3EFZ?T2>m%M2mR?Ra}#Oar=H=|IyLiNTo1@)&l#QR@&8lf`cdWv6lu)@ zed$IfVxQKC9DLJ?Gz5EcAr-ndIM1`Tc2&KLfr$zZ!a_;OneGgn`#UOACl#<$`uj?_ za1rA>nq&+gTqUkLdD!jK_Xn8wy8#v<6>9_Xr;&1KO0F+==XZZO*Q0;2J2d1ZTys^D zzk_GnNG$hPiKW~mQv2Vr`A2l-!Qyn^bjfeSmf$FD`%7fElTEt%Q`L?wjxA6Ys8ddE zgB!sk{gZj~tZ-cQ52UVC-c%?1L7_g|^*s3`=>}}jhbt$I@VS1VoDApmq24zRSsJux zJar!q%;&YF(cl#ls+@F#;UVG5iMud0WSVq`PeVe&rlAZ6Q{peAvfNL-CSGRDr^m$o z&=nGF;wmDylNJtO84OXJ+-!Q@;1hk~dT#YP%dBLXpIN4mF)k=5pT`)N55x~KKET*O zINnK5a~g{%*Na-O;W0kEC+(=NPlEc;gnIy5?7L8$6)tj2G9h@Tq;S3{Fc*9X|q z|G124(PEAEcIv|`B?(m9o`NbD?fu@!vdAgP2e6rTe-FvD#G)9Iw@W8 zhQ!s?R)97xAeB2);duC9?`v`0Qzk|-GyK3iB2KyH0mg_Yd(*9BF-3L9VQ7d*)?fY1 zvP12{t)j%^%s%1E6$INRd_^bUjs{R7Q{`63h}0_`RWKc2SIc2Vf>?j4dk_XW9`(hL1yKp0R zPzcwy&h5-yN-aCz;d7Nm{hnzRkTrOyoDXG#!!kKRJIk@pzcFt-_WK35nS+k`J6cYP zJhZ(Oxg+%kx_Uw-UAvfKfNux;C?Xkt9-JPK#Ek~gv-N?StDzr3#*pXSvk!ACk=@+* z`H%sMd>W1qja0I>H+Bv!m!4bMmsTM%e?_rb@!mJ&1qvHa&l~6D6E;=q7K?VrMd!w`NheHABgt zSdzD9F~& z61<03DBpO&i^D&N<`wg15Vii<%~=919bFEZeazRC3*kmG@?i^19Wh)1L zjw5&lSt@$w6gYO`P2p}*Kl)8*NUM(Ejpg+)QsyTQtjPB-5~4B5?q0@nEDv@;e!7qT z;AtC9<>2O=iZ&f)yTILfGv4Rv9hXVl<_l1h{+3(;p&5HZXeU%=Z{af9$t=BF^CP&%%jSomD=SKA?hjGf*hm8pWiNA`%<8-g2eZe?;h-~|lCj`0 zOz}%51%C4)1;Tjm{u}a{lhM*kZLWYj!b`iu2KhHRrJ{s?gu-g9veHYvMq4RnS z=gnu6@Fm2%^E&IWvhjRwh>HhD(p9{EP}P5gLZ2}c+%;UKa2+D(IhNv!yh%tZ208SH*h9}1?j$c7RDNVf#y!36ecjs=i*r7=)aG7YsP#JU6e zKv|G0zadbG;1+?42r38^KAkHI>*mM6mk5p#NGuyCn{hHGSzTBDvRuuh{HRl>1@h(o%T_G}TWz6XOJz zfW7~O=c{$vz5n=qY3`fZxTQKyiSgh)`LS>Dn!=3xE{xM-%~+#_?^Zs^#v{~Vl*&C@ zp>x?2%AR9Tw7hi8EKZ3hDSZ3*F`mqrk275p7*At5m#jW~tw}n+fUzkddmj+Z`$Eu-~a#s delta 7429 zcmZ`;30#!r)_2^geal0;&nM*3AsneoaIhc_tF!!7@db?lu`{wuKegE%y&htEHf6n`2Z&2(F zO68Xx>xA>SPJD3HBm*+Daz2}QzHHi>;Twxrp1pbW-8X()4{6E_<>eu;MVUx9t;<`+ z9xK!bj^6d(38CFV*VyUxS|NIr)a!-V8GXjbzELaAXzaCGE%RK5MweJcyB8GAJSE^A zSfKejAoqD5@}McXuQJv^v1@ohZZ19eG|^RL^Kh@)YS(pAZ}`4QZxuw(yj))?#EwxW zeWiFr3v`1bw-JiJ20n6I8lF9k_`Kh$(})B{RkTvim5f(Gk-J67u7dUM1|@q19C05I zo}I-*NoKu$FQYCrA-fmjXfU?d2W7_EOid=Cxpkl^PH5cj(vV*qOl&`FK-g8kD7DOS zf=Cfha_Pf%kJfwFms-k)vcCg~SfAif=j$>5!#l8KJU6 zsG=`}ogH))=&~_rj@>Nd3Pc+inR=V7iY{$axR2vyqwow!wiQ@~cwG$^j=F`yFC@J# zRQRi1gbzOD;hm@(>fA*@ou>$~>8%=3sU|oasHawFkREw!m)%b0adW$Mz+NN_5BGg? zH_4effj0GA{m3t#D~OuAoT)F8DO$e3i6wTUFw~#Mn3C#)+rp+tCXLzH#NH2o9JYAp zS3GIcmm>8{lKl&D(QK;GIn2wGXl&c%h)u?@hyUmK68e0LfR;ulV4@P#qRh$v_(^f4^^+`** z)`J8OJ51gemAt*irpI0JN}JXxf?^>7XNhZZaLOk_Zh>EXW_IX-mSkl-a$%}Av%*5_ zbePU2>c@Br;hgb|(P$3GgIz?)=*pB47^hz_dW!i97!P8;x0$aKQ+gB5G&0U(&TPgx z%(B6VCXN@vDsQGhXI~Kc{!lKIj{ViR^fFB&x%?9%^AzM5{%@ zmz2I*K$)7^1WSE$l-B!j$T!JwHAuINgy=+xQl?mRMHt10)eMo3K_}`>sP zJ>a)ZH$z>jbgT;!@w6dr_RS5R`~?j0iyEJCgdRLzBI)j*c|6%f8F9R7n>7N{vFU)n zRl)nu6bH6X>Z@_`r|cv{{X*QuM}1TDta_;B|A|T83?v&AXzg4PJEi$Wq3C6DB1Q48u|-li zgH1n1_fRkoxE`2LF&8znGWR~T@J^bY&ROg3+>Hfvf1l`?o0(4~Ved5&rQ0#WEeh{B zm+*rY#;%N;v3MA`7}T+uu`vX5q} zIuRcDo@!8bQXpR5!pUr)!sASOy-*XJNzZF&D7G$h1r7X7GFlz37jypU~+ zaObVYsa?_1SUWH{XRh9673x0cQoP7a(m(hfM!+~+CWq^d#-`PF$0~AH_`nribVW^- zwAbWm?KP@F{8r_H_oa^S>jFgVEkEHZyht?M7Lm=!HE6mq1FKh*5t9{7;g4!8Cfj_L zqz3D;g8iusj>M4^pGC41o7os&k_kT3sc$NR48Zoh-$Y8#Lb&x-b*<2#V=vmOt*+vA znyRY{-hcsYK|A{NuC^)x?-4a53ZEUDHVY9D85pk~5q)q5o&h{Ig2tF`5xG^us=>s{ zq>+xFqZms?jLm3u6O~vMD^l^%Y&IDs$%}v8dCL!3T0Jg_Y)qN0ZWD6%U`+pgLR+U3 zGf>F)oH}5}S0ZAkhdfsoDK@AU#}{Okv_zWg_B2P2jd3C23@)v1{aOFt*U~a*Xf0;4 zdli|m%u)9+Cb$eVEc*Y9+fc^B{XtqehSJihzw$PE-tt4nA-ttO;{bBo@1w}+Xj4-i zL<9#9c2(&V_%kV8H&UVc+8HnusgZw;R8}0F`*l3;zpFrRuVIt<(_SA&!1~~h6*W4P z8w+VE#`8)(%nVd?_PgQi&Lqbl*Ae-toiKzm9j$0M3a4=xh$$2}`&bj*91P#xTo~_) zdK}-1#@~M4<+P}#aydxdi`AGsyGD(7v;^-~k2r1@Q8fKhg0_%hot1M2c9mtc;ahTL&RQyPfs z`Ufvk!uVIh-F{+>+M@#9d2}#u!H0Ot2RwR(=xL3NFY+vI16=X2z*(V4nIO^^@U+L6 z_3w;36HX6d9LcyH<4(+Tg>fJs?yKx3XY18H9gp_{HA%RjhFA&2G%6yEtU{v=s-pt@ z8ZSO-V>%9}Fcc@iJEC*NP?l~wo_VEDYfo#Ce!5Cp%kchBEDF!#eLvo3;e9vKXX71< zvvt0+>;w(PU@8-Dl3i>&}Dnn!1R zqY3)zBPw>T7WSQ_oaP#C--XfFv_;Bn#$Td~Gk8lZ^p4G|lkGLUa65cDx;n-A)W?BO zpD-7`_n>+ajGd|mGsdO{>6{p8?7w?nM9)jx!~<^3ghv%JNybYE|Na1N@X&ePBGGw8 zJcc$yfnO%=FP#F9u&_Y~&}*E$L3!-84>7GZ)g#dA7F%WYWTzhj#|N)QNGeM{|D#uNjxO}d#FzedC^vY>uJnZdo?wf zmoi{jcz8u>4LX#&6_*RncoM?p4DFmejh1t1Kx&55)p+XmK{+lPH?S&&AJpd%i$PmJRN{Vr3c!`WvO@-nmf#McNsTDf)!0v>1cf3a- zj|&OfI-Ra<%h68QP~6%@CU?7QHrWs3YtsQ#uul!LVss$uh=&WgW97c?+ytqEkm)P3 zLh5niYUapD#Ul@K;jMS=y`5G_dl|+@#c6-L!Kwx8He4vT*Vt>oJ4~lsbcc_k@zD$$J_88=d;b>lQ{ z-gE1=y;K<5QM@#N1mj|oJH=r9JbYEh#l3k-1dTuO66}mgt7v}SW)v9B^;(C+QEM~e z!Umi6v=A(1^Eex_BE?E{+BNkvmfIWiKrZoh;iOCXlxeJ8(*Tm@);IP^PS>S;K?2}A zP9d)9j{BG#j@^4O0NQ<=jCO~yv3=zx*by75w6?*?*zt<}0vJ0F2x{Gkwm!_76`;L2 z1zO*PHJuX!>??_kD$_tH>C!qE&UH>w?9)IKH@d@l+L4aT)PF2p!Dc^9Q`t2Z2q%akjiB~GujoP+Q#dgb=#VCphFn(AH#wmVWoy&;;S5)GwB zV5hNEjwWLyABRu6^pgL8cJXg1x5HsW{O|~~+1LK@YC(yLxxt0?m+#L@u^e-!%yAM< zC4@s(!ei1KCM7t0hZ9%px7fOzWuHC^a}uKzmtc4&F)>JKqu#=%MOCPS+rS(n;7Vea zl6Mk99=jCAVbU6I(^unH1#D2Fbbh$W8e;7FIcSq+$~RzXQnFkLA0>5;jHJz4w(=-< zK`k5kT|;$tx?PK)Evc&<3`t$1bAMpo5?pg1^Jj9$Me`@1WA>xvq}+kFmvU2{-Xv^B zEeh$@#*}JU*)>R!YhZKN>`t+~5ci5dP5;lx==vtKbe-d2PUKm_99O%*7^ujhuqGu| zF}1JVpHd=y>EqxS%KD!D$fG^SLQb0AvuA;tDZVASdZyM+O7oRo&gO=#d21&sF+b%15)Be9Zh&k>a<3H$n<8h)G4l~70IH51&ADPp}_*>>oB1-&z!VlhM{D3jH z6$xAk9{|(0FntAME@%&4GG+=T-v0=bQjnR zAII-!dixC$_oNvtJ^n{dg6lmFMCvh^i)~lwqZTcEHxHjVOz!5=)}7nnP|p- z9Z$Mm9|i`?cIgSHEjcO2AHD*yj(1x>B<2|ImhYEf3Uf%syh+pUKZj%TSTpp<4-Q^L zl%}c7y@K&X!cn84G(ToCXJS)-9_3(a>cyib<}_orZQuPla!Cktf{(Dy6!Y9Pwb{MK+Ku6AL+xe8XR`vZD;&7y&yX4CcSgD_y=`_f$7 zGEhpd?L=~L7pt!Xk3n5K%_GXKa=LzX6r=RtjYITJ7&2(8@|6mQ2Bl(UYaUb~JHxEO zZ=)uDh1nh7p($Q zY?c!C8|a@3jL4xCZp<&zHhJoju_wESA9_;p&zI~F_ALx~s*n73!n|JA+U7RGWjid zjGixd!%L%Il{;YJ*bL}5W|@SC$P-$6a1 z!-)1XEp?JbPKP;@mdGJcKP4VwCyzuqiF?;%3+_m?@W18Dy^K~OdYeZbf3wI8MkP}U z5YkE>_c`=NHMth~q&sD__onzO#xIpF6O3R*Ad@@v}?hXdXN=J6|pV zk2xjMm7iC~Exd1XwY*pTsk~ECF2S4UrufEkm^1Nh>dqXQ8n?0Tz`P zp`#kh-<4nS$fg%8(#R-qzD2$d&&;1J55kf8Q@o~72%hJD<7i*VS)kJ%&Hc|(?HyA) zenFBF?|G9L&z{0>3f0(%5k8JJTLioEON|ks2BTIUbcOv3pHU8`f^N~|KEsHyZ8U|m zr)11cx@R!sLZ;&fTjb#q=E)_!jZ0Vu{_xsnW}atiPcHgi*4mdiTtfO6ihh=ULO*N5 zjG2>5iuGdHz*T)x;j>b2