From 4367a20cc442c56b05611b4224de9a61908f9eac Mon Sep 17 00:00:00 2001 From: Mauro Matteo Cascella Date: Mon, 11 Jul 2022 14:33:16 +0200 Subject: [PATCH 01/20] scsi/lsi53c895a: really fix use-after-free in lsi_do_msgout (CVE-2022-0216) Set current_req to NULL, not current_req->req, to prevent reusing a free'd buffer in case of repeated SCSI cancel requests. Also apply the fix to CLEAR QUEUE and BUS DEVICE RESET messages as well, since they also cancel the request. Thanks to Alexander Bulekov for providing a reproducer. Fixes: CVE-2022-0216 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972 Signed-off-by: Mauro Matteo Cascella Tested-by: Alexander Bulekov Message-Id: <20220711123316.421279-1-mcascell@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/lsi53c895a.c | 3 +- tests/qtest/fuzz-lsi53c895a-test.c | 76 ++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 99ea42d49b..ad5f5e5f39 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s) trace_lsi_do_msgout_abort(current_tag); if (current_req && current_req->req) { scsi_req_cancel(current_req->req); - current_req->req = NULL; + current_req = NULL; } lsi_disconnect(s); break; @@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s) /* clear the current I/O process */ if (s->current) { scsi_req_cancel(s->current->req); + current_req = NULL; } /* As the current implemented devices scsi_disk and scsi_generic diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c index 2e8e67859e..b23d3ecf45 100644 --- a/tests/qtest/fuzz-lsi53c895a-test.c +++ b/tests/qtest/fuzz-lsi53c895a-test.c @@ -8,6 +8,79 @@ #include "qemu/osdep.h" #include "libqtest.h" +/* + * This used to trigger a UAF in lsi_do_msgout() + * https://gitlab.com/qemu-project/qemu/-/issues/972 + */ +static void test_lsi_do_msgout_cancel_req(void) +{ + QTestState *s; + + if (sizeof(void *) == 4) { + g_test_skip("memory size too big for 32-bit build"); + return; + } + + s = qtest_init("-M q35 -m 4G -display none -nodefaults " + "-device lsi53c895a,id=scsi " + "-device scsi-hd,drive=disk0 " + "-drive file=null-co://,id=disk0,if=none,format=raw"); + + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outl(s, 0xcf8, 0xc000); + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outw(s, 0xcfc, 0x7); + qtest_outl(s, 0xcf8, 0x80000810); + qtest_outl(s, 0xcfc, 0xc000); + qtest_outl(s, 0xcf8, 0x80000804); + qtest_outw(s, 0xcfc, 0x05); + qtest_writeb(s, 0x69736c10, 0x08); + qtest_writeb(s, 0x69736c13, 0x58); + qtest_writeb(s, 0x69736c1a, 0x01); + qtest_writeb(s, 0x69736c1b, 0x06); + qtest_writeb(s, 0x69736c22, 0x01); + qtest_writeb(s, 0x69736c23, 0x07); + qtest_writeb(s, 0x69736c2b, 0x02); + qtest_writeb(s, 0x69736c48, 0x08); + qtest_writeb(s, 0x69736c4b, 0x58); + qtest_writeb(s, 0x69736c52, 0x04); + qtest_writeb(s, 0x69736c53, 0x06); + qtest_writeb(s, 0x69736c5b, 0x02); + qtest_outl(s, 0xc02d, 0x697300); + qtest_writeb(s, 0x5a554662, 0x01); + qtest_writeb(s, 0x5a554663, 0x07); + qtest_writeb(s, 0x5a55466a, 0x10); + qtest_writeb(s, 0x5a55466b, 0x22); + qtest_writeb(s, 0x5a55466c, 0x5a); + qtest_writeb(s, 0x5a55466d, 0x5a); + qtest_writeb(s, 0x5a55466e, 0x34); + qtest_writeb(s, 0x5a55466f, 0x5a); + qtest_writeb(s, 0x5a345a5a, 0x77); + qtest_writeb(s, 0x5a345a5b, 0x55); + qtest_writeb(s, 0x5a345a5c, 0x51); + qtest_writeb(s, 0x5a345a5d, 0x27); + qtest_writeb(s, 0x27515577, 0x41); + qtest_outl(s, 0xc02d, 0x5a5500); + qtest_writeb(s, 0x364001d0, 0x08); + qtest_writeb(s, 0x364001d3, 0x58); + qtest_writeb(s, 0x364001da, 0x01); + qtest_writeb(s, 0x364001db, 0x26); + qtest_writeb(s, 0x364001dc, 0x0d); + qtest_writeb(s, 0x364001dd, 0xae); + qtest_writeb(s, 0x364001de, 0x41); + qtest_writeb(s, 0x364001df, 0x5a); + qtest_writeb(s, 0x5a41ae0d, 0xf8); + qtest_writeb(s, 0x5a41ae0e, 0x36); + qtest_writeb(s, 0x5a41ae0f, 0xd7); + qtest_writeb(s, 0x5a41ae10, 0x36); + qtest_writeb(s, 0x36d736f8, 0x0c); + qtest_writeb(s, 0x36d736f9, 0x80); + qtest_writeb(s, 0x36d736fa, 0x0d); + qtest_outl(s, 0xc02d, 0x364000); + + qtest_quit(s); +} + /* * This used to trigger the assert in lsi_do_dma() * https://bugs.launchpad.net/qemu/+bug/697510 @@ -44,5 +117,8 @@ int main(int argc, char **argv) qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue", test_lsi_do_dma_empty_queue); + qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req", + test_lsi_do_msgout_cancel_req); + return g_test_run(); } From cf60ccc3306ca4726cbd286a156863863b00ff4f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 24 Jun 2022 23:50:37 +0900 Subject: [PATCH 02/20] cutils: Introduce bundle mechanism Developers often run QEMU without installing. The bundle mechanism allows to look up files which should be present in installation even in such a situation. It is a general mechanism and can find any files in the installation tree. The build tree will have a new directory, qemu-bundle, to represent what files the installation tree would have for reference by the executables. Note that it abandons compatibility with Windows older than 8. The extended support for the prior version, 7 ended more than 2 years ago, and it is unlikely that someone would like to run the latest QEMU on such an old system. Signed-off-by: Akihiko Odaki Suggested-by: Paolo Bonzini Message-Id: <20220624145039.49929-3-akihiko.odaki@gmail.com> Signed-off-by: Paolo Bonzini --- Makefile | 2 +- docs/about/build-platforms.rst | 2 +- include/qemu/cutils.h | 18 +++++++-- meson.build | 4 ++ scripts/symlink-install-tree.py | 33 +++++++++++++++++ util/cutils.c | 66 +++++++++++++++++++++++---------- util/meson.build | 1 + 7 files changed, 101 insertions(+), 25 deletions(-) create mode 100644 scripts/symlink-install-tree.py diff --git a/Makefile b/Makefile index b4feda93c8..13234f2aa4 100644 --- a/Makefile +++ b/Makefile @@ -216,7 +216,7 @@ qemu-%.tar.bz2: distclean: clean -$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || : - rm -f config-host.mak + rm -f config-host.mak qemu-bundle rm -f tests/tcg/config-*.mak rm -f config.status rm -f roms/seabios/config.mak diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index 1958edb430..ebde20f981 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -88,7 +88,7 @@ Windows The project aims to support the two most recent versions of Windows that are still supported by the vendor. The minimum Windows API that is currently -targeted is "Windows 7", so theoretically the QEMU binaries can still be run +targeted is "Windows 8", so theoretically the QEMU binaries can still be run on older versions of Windows, too. However, such old versions of Windows are not tested anymore, so it is recommended to use one of the latest versions of Windows instead. diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index d3e532b64c..92c436d8c7 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -224,9 +224,21 @@ const char *qemu_get_exec_dir(void); * @dir: the directory (typically a `CONFIG_*DIR` variable) to be relocated. * * Returns a path for @dir that uses the directory of the running executable - * as the prefix. For example, if `bindir` is `/usr/bin` and @dir is - * `/usr/share/qemu`, the function will append `../share/qemu` to the - * directory that contains the running executable and return the result. + * as the prefix. + * + * When a directory named `qemu-bundle` exists in the directory of the running + * executable, the path to the directory will be prepended to @dir. For + * example, if the directory of the running executable is `/qemu/build` @dir + * is `/usr/share/qemu`, the result will be + * `/qemu/build/qemu-bundle/usr/share/qemu`. The directory is expected to exist + * in the build tree. + * + * Otherwise, the directory of the running executable will be used as the + * prefix and it appends the relative path from `bindir` to @dir. For example, + * if the directory of the running executable is `/opt/qemu/bin`, `bindir` is + * `/usr/bin` and @dir is `/usr/share/qemu`, the result will be + * `/opt/qemu/bin/../share/qemu`. + * * The returned string should be freed by the caller. */ char *get_relocated_path(const char *dir); diff --git a/meson.build b/meson.build index ad92d288a6..da76edc7c7 100644 --- a/meson.build +++ b/meson.build @@ -7,6 +7,8 @@ add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true) add_test_setup('slow', exclude_suites: ['thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow']) add_test_setup('thorough', env: ['G_TEST_SLOW=1', 'SPEED=thorough']) +meson.add_postconf_script(find_program('scripts/symlink-install-tree.py')) + not_found = dependency('', required: false) keyval = import('keyval') ss = import('sourceset') @@ -356,10 +358,12 @@ nvmm =not_found hvf = not_found midl = not_found widl = not_found +pathcch = not_found host_dsosuf = '.so' if targetos == 'windows' midl = find_program('midl', required: false) widl = find_program('widl', required: false) + pathcch = cc.find_library('pathcch') socket = cc.find_library('ws2_32') winmm = cc.find_library('winmm') diff --git a/scripts/symlink-install-tree.py b/scripts/symlink-install-tree.py new file mode 100644 index 0000000000..a5bf0b0d6d --- /dev/null +++ b/scripts/symlink-install-tree.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +from pathlib import PurePath +import errno +import json +import os +import subprocess +import sys + +def destdir_join(d1: str, d2: str) -> str: + if not d1: + return d2 + # c:\destdir + c:\prefix must produce c:\destdir\prefix + return str(PurePath(d1, *PurePath(d2).parts[1:])) + +introspect = os.environ.get('MESONINTROSPECT') +out = subprocess.run([*introspect.split(' '), '--installed'], + stdout=subprocess.PIPE, check=True).stdout +for source, dest in json.loads(out).items(): + assert os.path.isabs(source) + bundle_dest = destdir_join('qemu-bundle', dest) + path = os.path.dirname(bundle_dest) + try: + os.makedirs(path, exist_ok=True) + except BaseException as e: + print(f'error making directory {path}', file=sys.stderr) + raise e + try: + os.symlink(source, bundle_dest) + except BaseException as e: + if not isinstance(e, OSError) or e.errno != errno.EEXIST: + print(f'error making symbolic link {dest}', file=sys.stderr) + raise e diff --git a/util/cutils.c b/util/cutils.c index 6d04e52907..8199dac598 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -35,6 +35,11 @@ #include #endif +#ifdef G_OS_WIN32 +#include +#include +#endif + #include "qemu/ctype.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -1074,31 +1079,52 @@ char *get_relocated_path(const char *dir) /* Fail if qemu_init_exec_dir was not called. */ assert(exec_dir[0]); - if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) { - return g_strdup(dir); - } result = g_string_new(exec_dir); + g_string_append(result, "/qemu-bundle"); + if (access(result->str, R_OK) == 0) { +#ifdef G_OS_WIN32 + size_t size = mbsrtowcs(NULL, &dir, 0, &(mbstate_t){0}) + 1; + PWSTR wdir = g_new(WCHAR, size); + mbsrtowcs(wdir, &dir, size, &(mbstate_t){0}); - /* Advance over common components. */ - len_dir = len_bindir = prefix_len; - do { - dir += len_dir; - bindir += len_bindir; - dir = next_component(dir, &len_dir); - bindir = next_component(bindir, &len_bindir); - } while (len_dir && len_dir == len_bindir && !memcmp(dir, bindir, len_dir)); + PCWSTR wdir_skipped_root; + PathCchSkipRoot(wdir, &wdir_skipped_root); - /* Ascend from bindir to the common prefix with dir. */ - while (len_bindir) { - bindir += len_bindir; - g_string_append(result, "/.."); - bindir = next_component(bindir, &len_bindir); + size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0}); + char *cursor = result->str + result->len; + g_string_set_size(result, result->len + size); + wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0}); + g_free(wdir); +#else + g_string_append(result, dir); +#endif + } else if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) { + g_string_assign(result, dir); + } else { + g_string_assign(result, exec_dir); + + /* Advance over common components. */ + len_dir = len_bindir = prefix_len; + do { + dir += len_dir; + bindir += len_bindir; + dir = next_component(dir, &len_dir); + bindir = next_component(bindir, &len_bindir); + } while (len_dir && len_dir == len_bindir && !memcmp(dir, bindir, len_dir)); + + /* Ascend from bindir to the common prefix with dir. */ + while (len_bindir) { + bindir += len_bindir; + g_string_append(result, "/.."); + bindir = next_component(bindir, &len_bindir); + } + + if (*dir) { + assert(G_IS_DIR_SEPARATOR(dir[-1])); + g_string_append(result, dir - 1); + } } - if (*dir) { - assert(G_IS_DIR_SEPARATOR(dir[-1])); - g_string_append(result, dir - 1); - } return g_string_free(result, false); } diff --git a/util/meson.build b/util/meson.build index 8cce8f8968..5e282130df 100644 --- a/util/meson.build +++ b/util/meson.build @@ -23,6 +23,7 @@ util_ss.add(when: 'CONFIG_WIN32', if_true: files('event_notifier-win32.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: files('oslib-win32.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: files('qemu-thread-win32.c')) util_ss.add(when: 'CONFIG_WIN32', if_true: winmm) +util_ss.add(when: 'CONFIG_WIN32', if_true: pathcch) util_ss.add(files('envlist.c', 'path.c', 'module.c')) util_ss.add(files('host-utils.c')) util_ss.add(files('bitmap.c', 'bitops.c')) From 882084a04ae9bec00e510a2319feba1d1a653fb1 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 24 Jun 2022 23:50:38 +0900 Subject: [PATCH 03/20] datadir: Use bundle mechanism softmmu/datadir.c had its own implementation to find files in the build tree, but now bundle mechanism provides the unified implementation which works for datadir and the other files. Signed-off-by: Akihiko Odaki Message-Id: <20220624145039.49929-4-akihiko.odaki@gmail.com> Signed-off-by: Paolo Bonzini --- .travis.yml | 2 +- pc-bios/keymaps/meson.build | 21 ++++++--------------- pc-bios/meson.build | 13 +++---------- scripts/oss-fuzz/build.sh | 8 ++++---- softmmu/datadir.c | 22 +--------------------- tests/qtest/fuzz/fuzz.c | 18 ------------------ 6 files changed, 15 insertions(+), 69 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9afc4a54b8..4fdc9a6785 100644 --- a/.travis.yml +++ b/.travis.yml @@ -223,7 +223,7 @@ jobs: - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? - | if [ "$BUILD_RC" -eq 0 ] ; then - mv pc-bios/s390-ccw/*.img pc-bios/ ; + mv pc-bios/s390-ccw/*.img qemu-bundle/usr/local/share/qemu ; ${TEST_CMD} ; else $(exit $BUILD_RC); diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index 44247a12b5..2837eb34f4 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -40,9 +40,9 @@ else endif cp = find_program('cp') -t = [] -foreach km, args: keymaps - if native_qemu_keymap.found() +if native_qemu_keymap.found() + t = [] + foreach km, args: keymaps # generate with qemu-kvm t += custom_target(km, build_by_default: true, @@ -50,20 +50,11 @@ foreach km, args: keymaps command: [native_qemu_keymap, '-f', '@OUTPUT@', args.split()], install: true, install_dir: qemu_datadir / 'keymaps') - else - # copy from source tree - t += custom_target(km, - build_by_default: true, - input: km, - output: km, - command: [cp, '@INPUT@', '@OUTPUT@'], - install: true, - install_dir: qemu_datadir / 'keymaps') - endif -endforeach + endforeach -if native_qemu_keymap.found() alias_target('update-keymaps', t) +else + install_data(keymaps.keys(), install_dir: qemu_datadir / 'keymaps') endif install_data(['sl', 'sv'], install_dir: qemu_datadir / 'keymaps') diff --git a/pc-bios/meson.build b/pc-bios/meson.build index 41ba1c0ec7..388e0db6e4 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -85,16 +85,9 @@ blobs = [ 'vof-nvram.bin', ] -ln_s = [find_program('ln', required: true), '-sf'] -foreach f : blobs - roms += custom_target(f, - build_by_default: have_system, - output: f, - input: files('meson.build'), # dummy input - install: get_option('install_blobs'), - install_dir: qemu_datadir, - command: [ ln_s, meson.project_source_root() / 'pc-bios' / f, '@OUTPUT@' ]) -endforeach +if get_option('install_blobs') + install_data(blobs, install_dir: qemu_datadir) +endif subdir('descriptors') subdir('keymaps') diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh index aaf485cb55..2656a89aea 100755 --- a/scripts/oss-fuzz/build.sh +++ b/scripts/oss-fuzz/build.sh @@ -64,7 +64,7 @@ mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here # Build once to get the list of dynamic lib paths, and copy them over ../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \ - --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \ + --prefix="/opt/qemu-oss-fuzz" \ --extra-cflags="$EXTRA_CFLAGS" --target-list="i386-softmmu" if ! make "-j$(nproc)" qemu-fuzz-i386; then @@ -81,14 +81,14 @@ if [ "$GITLAB_CI" != "true" ]; then # Build a second time to build the final binary with correct rpath ../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \ - --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \ + --prefix="/opt/qemu-oss-fuzz" \ --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="-Wl,-rpath,\$ORIGIN/lib" \ --target-list="i386-softmmu" make "-j$(nproc)" qemu-fuzz-i386 V=1 fi -# Copy over the datadir -cp -r ../pc-bios/ "$DEST_DIR/pc-bios" +# Prepare a preinstalled tree +make install DESTDIR=$DEST_DIR/qemu-bundle targets=$(./qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}') base_copy="$DEST_DIR/qemu-fuzz-i386-target-$(echo "$targets" | head -n 1)" diff --git a/softmmu/datadir.c b/softmmu/datadir.c index 160cac999a..697cffea93 100644 --- a/softmmu/datadir.c +++ b/softmmu/datadir.c @@ -83,26 +83,6 @@ void qemu_add_data_dir(char *path) data_dir[data_dir_idx++] = path; } -/* - * Find a likely location for support files using the location of the binary. - * When running from the build tree this will be "$bindir/pc-bios". - * Otherwise, this is CONFIG_QEMU_DATADIR (possibly relocated). - * - * The caller must use g_free() to free the returned data when it is - * no longer required. - */ -static char *find_datadir(void) -{ - g_autofree char *dir = NULL; - - dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL); - if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { - return g_steal_pointer(&dir); - } - - return get_relocated_path(CONFIG_QEMU_DATADIR); -} - void qemu_add_default_firmwarepath(void) { char **dirs; @@ -116,7 +96,7 @@ void qemu_add_default_firmwarepath(void) g_strfreev(dirs); /* try to find datadir relative to the executable path */ - qemu_add_data_dir(find_datadir()); + qemu_add_data_dir(get_relocated_path(CONFIG_QEMU_DATADIR)); } void qemu_list_data_dirs(void) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 0ad4ba9e94..2b3bc1fb9d 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -158,8 +158,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) { char *target_name; - const char *bindir; - char *datadir; GString *cmd_line; gchar *pretty_cmd_line; bool serialize = false; @@ -174,22 +172,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) target_name = strstr(**argv, "-target-"); if (target_name) { /* The binary name specifies the target */ target_name += strlen("-target-"); - /* - * With oss-fuzz, the executable is kept in the root of a directory (we - * cannot assume the path). All data (including bios binaries) must be - * in the same dir, or a subdir. Thus, we cannot place the pc-bios so - * that it would be in exec_dir/../pc-bios. - * As a workaround, oss-fuzz allows us to use argv[0] to get the - * location of the executable. Using this we add exec_dir/pc-bios to - * the datadirs. - */ - bindir = qemu_get_exec_dir(); - datadir = g_build_filename(bindir, "pc-bios", NULL); - if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { - qemu_add_data_dir(datadir); - } else { - g_free(datadir); - } } else if (*argc > 1) { /* The target is specified as an argument */ target_name = (*argv)[1]; if (!strstr(target_name, "--fuzz-target=")) { From 98753e9a8fc1791b60f1a674452ceb1184eb613a Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 24 Jun 2022 23:50:39 +0900 Subject: [PATCH 04/20] module: Use bundle mechanism Before this change, the directory of the executable was being added to resolve modules in the build tree. However, get_relocated_path() can now resolve them with the new bundle mechanism. Signed-off-by: Akihiko Odaki Message-Id: <20220624145039.49929-5-akihiko.odaki@gmail.com> Signed-off-by: Paolo Bonzini --- util/module.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util/module.c b/util/module.c index 6bb4ad915a..8ddb0e18f5 100644 --- a/util/module.c +++ b/util/module.c @@ -274,7 +274,6 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail) dirs[n_dirs++] = g_strdup_printf("%s", search_dir); } dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR); - dirs[n_dirs++] = g_strdup(qemu_get_exec_dir()); #ifdef CONFIG_MODULE_UPGRADES version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION), From 8154f5e64b0cfb836803ec6c11360075be66cd00 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 25 Jun 2022 00:40:42 +0900 Subject: [PATCH 05/20] meson: Prefix each element of firmware path Signed-off-by: Akihiko Odaki Message-Id: <20220624154042.51512-1-akihiko.odaki@gmail.com> [Rewrite shell function without using Bash extensions. - Paolo] Signed-off-by: Paolo Bonzini --- configure | 15 +++++++++++++++ meson.build | 11 +++++++++-- meson_options.txt | 2 +- scripts/meson-buildoptions.py | 7 +++++-- scripts/meson-buildoptions.sh | 4 ++-- softmmu/datadir.c | 8 +++++--- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/configure b/configure index e8cc850727..f02635b087 100755 --- a/configure +++ b/configure @@ -676,6 +676,21 @@ fi werror="" +meson_option_build_array() { + printf '[' + (if test "$targetos" == windows; then + IFS=\; + else + IFS=: + fi + for e in $1; do + e=${e/'\'/'\\'} + e=${e/\"/'\"'} + printf '"""%s""",' "$e" + done) + printf ']\n' +} + . $source_path/scripts/meson-buildoptions.sh meson_options= diff --git a/meson.build b/meson.build index da76edc7c7..ad16fc1aa8 100644 --- a/meson.build +++ b/meson.build @@ -1718,7 +1718,13 @@ config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix')) config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir) config_host_data.set_quoted('CONFIG_QEMU_DATADIR', get_option('prefix') / qemu_datadir) config_host_data.set_quoted('CONFIG_QEMU_DESKTOPDIR', get_option('prefix') / qemu_desktopdir) -config_host_data.set_quoted('CONFIG_QEMU_FIRMWAREPATH', get_option('prefix') / get_option('qemu_firmwarepath')) + +qemu_firmwarepath = '' +foreach k : get_option('qemu_firmwarepath') + qemu_firmwarepath += '"' + get_option('prefix') / k + '", ' +endforeach +config_host_data.set('CONFIG_QEMU_FIRMWAREPATH', qemu_firmwarepath) + config_host_data.set_quoted('CONFIG_QEMU_HELPERDIR', get_option('prefix') / get_option('libexecdir')) config_host_data.set_quoted('CONFIG_QEMU_ICONDIR', get_option('prefix') / qemu_icondir) config_host_data.set_quoted('CONFIG_QEMU_LOCALEDIR', get_option('prefix') / get_option('localedir')) @@ -3683,7 +3689,8 @@ endif summary_info = {} summary_info += {'Install prefix': get_option('prefix')} summary_info += {'BIOS directory': qemu_datadir} -summary_info += {'firmware path': get_option('prefix') / get_option('qemu_firmwarepath')} +pathsep = targetos == 'windows' ? ';' : ':' +summary_info += {'firmware path': pathsep.join(get_option('qemu_firmwarepath'))} summary_info += {'binary directory': get_option('prefix') / get_option('bindir')} summary_info += {'library directory': get_option('prefix') / get_option('libdir')} summary_info += {'module directory': qemu_moddir} diff --git a/meson_options.txt b/meson_options.txt index 9a034f875b..e58e158396 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,7 +6,7 @@ option('qemu_suffix', type : 'string', value: 'qemu', description: 'Suffix for QEMU data/modules/config directories (can be empty)') option('docdir', type : 'string', value : 'share/doc', description: 'Base directory for documentation installation (can be empty)') -option('qemu_firmwarepath', type : 'string', value : 'share/qemu-firmware', +option('qemu_firmwarepath', type : 'array', value : ['share/qemu-firmware'], description: 'search PATH for firmware files') option('pkgversion', type : 'string', value : '', description: 'use specified string as sub-version of the package') diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index e624c16b01..3e2b478538 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -156,7 +156,7 @@ def cli_metavar(opt): if opt["type"] == "string": return "VALUE" if opt["type"] == "array": - return "CHOICES" + return "CHOICES" if "choices" in opt else "VALUES" return "CHOICE" @@ -199,7 +199,10 @@ def print_parse(options): key = cli_option(opt) name = opt["name"] if require_arg(opt): - print(f' --{key}=*) quote_sh "-D{name}=$2" ;;') + if opt["type"] == "array" and not "choices" in opt: + print(f' --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;') + else: + print(f' --{key}=*) quote_sh "-D{name}=$2" ;;') elif opt["type"] == "boolean": print(f' --enable-{key}) printf "%s" -D{name}=true ;;') print(f' --disable-{key}) printf "%s" -D{name}=false ;;') diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 4b7b8ffaa2..359b04e0e6 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -42,7 +42,7 @@ meson_options_help() { printf "%s\n" ' --enable-trace-backends=CHOICES' printf "%s\n" ' Set available tracing backends [log] (choices:' printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)' - printf "%s\n" ' --firmwarepath=VALUE search PATH for firmware files [share/qemu-firmware]' + printf "%s\n" ' --firmwarepath=VALUES search PATH for firmware files [share/qemu-firmware]' printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler' printf "%s\n" ' --includedir=VALUE Header file directory [include]' printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for' @@ -363,7 +363,7 @@ _meson_option_parse() { --disable-qcow1) printf "%s" -Dqcow1=disabled ;; --enable-qed) printf "%s" -Dqed=enabled ;; --disable-qed) printf "%s" -Dqed=disabled ;; - --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$2" ;; + --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$(meson_option_build_array $2)" ;; --enable-qga-vss) printf "%s" -Dqga_vss=enabled ;; --disable-qga-vss) printf "%s" -Dqga_vss=disabled ;; --enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;; diff --git a/softmmu/datadir.c b/softmmu/datadir.c index 697cffea93..c9237cb5d4 100644 --- a/softmmu/datadir.c +++ b/softmmu/datadir.c @@ -85,15 +85,17 @@ void qemu_add_data_dir(char *path) void qemu_add_default_firmwarepath(void) { - char **dirs; + static const char * const dirs[] = { + CONFIG_QEMU_FIRMWAREPATH + NULL + }; + size_t i; /* add configured firmware directories */ - dirs = g_strsplit(CONFIG_QEMU_FIRMWAREPATH, G_SEARCHPATH_SEPARATOR_S, 0); for (i = 0; dirs[i] != NULL; i++) { qemu_add_data_dir(get_relocated_path(dirs[i])); } - g_strfreev(dirs); /* try to find datadir relative to the executable path */ qemu_add_data_dir(get_relocated_path(CONFIG_QEMU_DATADIR)); From 3412f9c3b41c3a98f85f81476d5542ac7662bb06 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:01 +0100 Subject: [PATCH 06/20] scsi-disk: add new quirks bitmap to SCSIDiskState Since the MacOS SCSI implementation is quite old (and Apple added some firmware customisations to their drives for m68k Macs) there is need to add a mechanism to correctly handle Apple-specific quirks. Add a new quirks bitmap to SCSIDiskState that can be used to enable these features as required. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20220622105314.802852-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 91acb5c0ce..55c19fb25d 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -94,6 +94,7 @@ struct SCSIDiskState { uint16_t port_index; uint64_t max_unmap_size; uint64_t max_io_size; + uint32_t quirks; QEMUBH *bh; char *version; char *serial; From 09d37867627a86f23248c138f380bd38bada4073 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:02 +0100 Subject: [PATCH 07/20] scsi-disk: add MODE_PAGE_APPLE_VENDOR quirk for Macintosh One of the mechanisms MacOS uses to identify CDROM drives compatible with MacOS is to send a custom MODE SELECT command for page 0x30 to the drive. The response to this is a hard-coded manufacturer string which must match in order for the CDROM to be usable within MacOS. Add an implementation of the MODE SELECT page 0x30 response guarded by a newly defined SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR quirk bit so that CDROM drives attached to non-Apple machines function exactly as before. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20220622105314.802852-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 17 +++++++++++++++++ include/hw/scsi/scsi.h | 3 +++ include/scsi/constants.h | 1 + 3 files changed, 21 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 55c19fb25d..2672730eca 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1085,6 +1085,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, [MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM), [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM), + [MODE_PAGE_APPLE_VENDOR] = (1 << TYPE_ROM), }; uint8_t *p = *p_outbuf + 2; @@ -1229,6 +1230,20 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, p[19] = (16 * 176) & 0xff; break; + case MODE_PAGE_APPLE_VENDOR: + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR)) { + length = 0x1e; + if (page_control == 1) { /* Changeable Values */ + break; + } + + memset(p, 0, length); + strcpy((char *)p + 8, "APPLE COMPUTER, INC "); + break; + } else { + return -1; + } + default: return -1; } @@ -3085,6 +3100,8 @@ static Property scsi_cd_properties[] = { DEFAULT_MAX_IO_SIZE), DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, 5), + DEFINE_PROP_BIT("quirk_mode_page_apple_vendor", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 1ffb367f94..e090ea1b40 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -226,4 +226,7 @@ SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun); /* scsi-generic.c. */ extern const SCSIReqOps scsi_generic_req_ops; +/* scsi-disk.c */ +#define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0 + #endif diff --git a/include/scsi/constants.h b/include/scsi/constants.h index 2a32c08b5e..891aa0f45c 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -234,6 +234,7 @@ #define MODE_PAGE_FAULT_FAIL 0x1c #define MODE_PAGE_TO_PROTECT 0x1d #define MODE_PAGE_CAPABILITIES 0x2a +#define MODE_PAGE_APPLE_VENDOR 0x30 #define MODE_PAGE_ALLS 0x3f /* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor * of MODE_PAGE_SENSE_POWER */ From f358241029d6c3b8a4a292880cc6857eb520f4a8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:03 +0100 Subject: [PATCH 08/20] q800: implement compat_props to enable quirk_mode_page_apple_vendor for scsi-cd devices By default quirk_mode_page_apple_vendor should be enabled for all scsi-cd devices connected to the q800 machine to enable MacOS to detect and use them. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/m68k/q800.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 099a758c6f..6fabd35529 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -686,6 +686,11 @@ static void q800_init(MachineState *machine) } } +static GlobalProperty hw_compat_q800[] = { + { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, +}; +static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); + static void q800_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -695,6 +700,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->max_cpus = 1; mc->block_default_type = IF_SCSI; mc->default_ram_id = "m68k_mac.ram"; + compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len); } static const TypeInfo q800_machine_typeinfo = { From f43c2b94cd1764ba0a47fc1f848681b0e89d4892 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:04 +0100 Subject: [PATCH 09/20] scsi-disk: add SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD quirk for Macintosh During SCSI bus enumeration A/UX sends a MODE SENSE command to the CDROM with the DBD bit unset and expects the response to include a block descriptor. As per the latest SCSI documentation, QEMU currently force-disables the block descriptor for CDROM devices but the A/UX driver expects the requested block descriptor to be returned. If the block descriptor is not returned in the response then A/UX becomes confused, since the block descriptor returned in the MODE SENSE response is used to generate a subsequent MODE SELECT command which is then invalid. Add a new SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD quirk to allow this behaviour to be enabled as required. Note that an additional workaround is required for the previous SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR quirk which must never return a block descriptor even though the DBD bit is left unset. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-5-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 27 +++++++++++++++++++++++---- include/hw/scsi/scsi.h | 1 + 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 2672730eca..b1d08bfba5 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1279,10 +1279,27 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) dev_specific_param |= 0x80; /* Readonly. */ } } else { - /* MMC prescribes that CD/DVD drives have no block descriptors, - * and defines no device-specific parameter. */ - dev_specific_param = 0x00; - dbd = true; + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD)) { + /* Use DBD from the request... */ + dev_specific_param = 0x00; + + /* + * ... unless we receive a request for MODE_PAGE_APPLE_VENDOR + * which should never return a block descriptor even though DBD is + * not set, otherwise CDROM detection fails in MacOS + */ + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR) && + page == MODE_PAGE_APPLE_VENDOR) { + dbd = true; + } + } else { + /* + * MMC prescribes that CD/DVD drives have no block descriptors, + * and defines no device-specific parameter. + */ + dev_specific_param = 0x00; + dbd = true; + } } if (r->req.cmd.buf[0] == MODE_SENSE) { @@ -3102,6 +3119,8 @@ static Property scsi_cd_properties[] = { 5), DEFINE_PROP_BIT("quirk_mode_page_apple_vendor", SCSIDiskState, quirks, SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0), + DEFINE_PROP_BIT("quirk_mode_sense_rom_use_dbd", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index e090ea1b40..845d05722b 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -228,5 +228,6 @@ extern const SCSIReqOps scsi_generic_req_ops; /* scsi-disk.c */ #define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0 +#define SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD 1 #endif From f7c30a0f4197ec5604386e91cb39ea19a82ea224 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:05 +0100 Subject: [PATCH 10/20] q800: implement compat_props to enable quirk_mode_sense_rom_use_dbd for scsi-cd devices By default quirk_mode_sense_rom_use_dbd should be enabled for all scsi-cd devices connected to the q800 machine to correctly report the CDROM block descriptor back to A/UX. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20220622105314.802852-6-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/m68k/q800.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 6fabd35529..4745f72c92 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -688,6 +688,7 @@ static void q800_init(MachineState *machine) static GlobalProperty hw_compat_q800[] = { { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, + { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, }; static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); From 09274de1f70e0773b95f865ef4980599e51aa67d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:06 +0100 Subject: [PATCH 11/20] scsi-disk: add SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE quirk for Macintosh Both MacOS and A/UX make use of vendor-specific MODE SELECT commands with PF=0 to identify SCSI devices: - MacOS sends a MODE SELECT command with PF=0 for the MODE_PAGE_VENDOR_SPECIFIC (0x0) mode page containing 2 bytes before initialising a disk - A/UX (installed on disk) sends a MODE SELECT command with PF=0 during SCSI bus enumeration, and gets stuck in an infinite loop if it fails Add a new SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE quirk to allow both PF=0 MODE SELECT commands and implement a MODE_PAGE_VENDOR_SPECIFIC (0x0) mode page which is compatible with MacOS. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-7-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 30 ++++++++++++++++++++++++++++-- include/hw/scsi/scsi.h | 1 + include/scsi/constants.h | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index b1d08bfba5..2cdbba7ccc 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1079,6 +1079,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, int page_control) { static const int mode_sense_valid[0x3f] = { + [MODE_PAGE_VENDOR_SPECIFIC] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM), @@ -1244,6 +1245,22 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, return -1; } + case MODE_PAGE_VENDOR_SPECIFIC: + if (s->qdev.type == TYPE_DISK && (s->quirks & + (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) { + length = 0x2; + if (page_control == 1) { /* Changeable Values */ + p[0] = 0xff; + p[1] = 0xff; + break; + } + p[0] = 0; + p[1] = 0; + break; + } else { + return -1; + } + default: return -1; } @@ -1570,9 +1587,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) int bd_len; int pass; - /* We only support PF=1, SP=0. */ if ((r->req.cmd.buf[1] & 0x11) != 0x10) { - goto invalid_field; + if (!(s->quirks & + (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) { + /* We only support PF=1, SP=0. */ + goto invalid_field; + } } if (len < hdr_len) { @@ -3069,6 +3089,9 @@ static Property scsi_hd_properties[] = { DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, 5), + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -3121,6 +3144,9 @@ static Property scsi_cd_properties[] = { SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0), DEFINE_PROP_BIT("quirk_mode_sense_rom_use_dbd", SCSIDiskState, quirks, SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD, 0), + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 845d05722b..011cb84753 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -229,5 +229,6 @@ extern const SCSIReqOps scsi_generic_req_ops; /* scsi-disk.c */ #define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0 #define SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD 1 +#define SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE 2 #endif diff --git a/include/scsi/constants.h b/include/scsi/constants.h index 891aa0f45c..6a8bad556a 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -225,6 +225,7 @@ #define TYPE_NO_LUN 0x7f /* Mode page codes for mode sense/set */ +#define MODE_PAGE_VENDOR_SPECIFIC 0x00 #define MODE_PAGE_R_W_ERROR 0x01 #define MODE_PAGE_HD_GEOMETRY 0x04 #define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05 From d9a107d153bf7e00c0e05c2e9cbc42621a42c44c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:07 +0100 Subject: [PATCH 12/20] q800: implement compat_props to enable quirk_mode_page_vendor_specific_apple for scsi devices By default quirk_mode_page_vendor_specific_apple should be enabled for both scsi-hd and scsi-cd devices to allow MacOS to format SCSI disk devices, and A/UX to enumerate SCSI CDROM devices succesfully without getting stuck in a loop. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-8-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/m68k/q800.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 4745f72c92..b774a5b20a 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -687,8 +687,10 @@ static void q800_init(MachineState *machine) } static GlobalProperty hw_compat_q800[] = { + { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on"}, { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, + { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, }; static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); From 6ab717610fe7ef791454df6c61e2b5736d26c8bf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:08 +0100 Subject: [PATCH 13/20] scsi-disk: add FORMAT UNIT command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When initialising a drive ready to install MacOS, Apple HD SC Setup first attempts to format the drive. Add a simple FORMAT UNIT command which simply returns success to allow the format to succeed. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20220622105314.802852-9-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 4 ++++ hw/scsi/trace-events | 1 + 2 files changed, 5 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 2cdbba7ccc..9413b33bac 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2180,6 +2180,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) trace_scsi_disk_emulate_command_WRITE_SAME( req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer); break; + case FORMAT_UNIT: + trace_scsi_disk_emulate_command_FORMAT_UNIT(r->req.cmd.xfer); + break; default: trace_scsi_disk_emulate_command_UNKNOWN(buf[0], scsi_command_name(buf[0])); @@ -2585,6 +2588,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { [VERIFY_10] = &scsi_disk_emulate_reqops, [VERIFY_12] = &scsi_disk_emulate_reqops, [VERIFY_16] = &scsi_disk_emulate_reqops, + [FORMAT_UNIT] = &scsi_disk_emulate_reqops, [READ_6] = &scsi_disk_dma_reqops, [READ_10] = &scsi_disk_dma_reqops, diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 20fb0dc162..03b2640934 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -334,6 +334,7 @@ scsi_disk_emulate_command_UNMAP(size_t xfer) "Unmap (len %zd)" scsi_disk_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)" scsi_disk_emulate_command_WRITE_SAME(int cmd, size_t xfer) "WRITE SAME %d (len %zd)" scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)" +scsi_disk_emulate_command_FORMAT_UNIT(size_t xfer) "Format Unit (len %zu)" scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)" scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)" scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s" From 389e18eb9aa4877f33326afa426643769185d014 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:09 +0100 Subject: [PATCH 14/20] scsi-disk: add SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED quirk for Macintosh When A/UX configures the CDROM device it sends a truncated MODE SELECT request for page 1 (MODE_PAGE_R_W_ERROR) which is only 6 bytes in length rather than 10. This seems to be due to bug in Apple's code which calculates the CDB message length incorrectly. The work at [1] suggests that this truncated request is accepted on real hardware whereas in QEMU it generates an INVALID_PARAM_LEN sense code which causes A/UX to get stuck in a loop retrying the command in an attempt to succeed. Alter the mode page request length check so that truncated requests are allowed if the SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED quirk is enabled, whilst also adding a trace event to enable the condition to be detected. [1] https://68kmla.org/bb/index.php?threads/scsi2sd-project-anyone-interested.29040/page-7#post-316444 Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-10-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 7 ++++++- hw/scsi/trace-events | 1 + include/hw/scsi/scsi.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 9413b33bac..2b2e496ebd 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1552,7 +1552,10 @@ static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) goto invalid_param; } if (page_len > len) { - goto invalid_param_len; + if (!(s->quirks & SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED)) { + goto invalid_param_len; + } + trace_scsi_disk_mode_select_page_truncated(page, page_len, len); } if (!change) { @@ -3151,6 +3154,8 @@ static Property scsi_cd_properties[] = { DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, 0), + DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 03b2640934..8e927ff62d 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -339,6 +339,7 @@ scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 " scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)" scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s" scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd=0x%x (sector %" PRId64 ", count %d) timeout=%u" +scsi_disk_mode_select_page_truncated(int page, int len, int page_len) "page %d expected length %d but received length %d" # scsi-generic.c scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d" diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 011cb84753..e284e3a4ec 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -230,5 +230,6 @@ extern const SCSIReqOps scsi_generic_req_ops; #define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0 #define SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD 1 #define SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE 2 +#define SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED 3 #endif From 2724b90dfbdde98cd681d6bb62e835029ca4e9e2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:10 +0100 Subject: [PATCH 15/20] q800: implement compat_props to enable quirk_mode_page_truncated for scsi-cd devices By default quirk_mode_page_truncated should be enabled for all scsi-cd devices connected to the q800 machine to allow A/UX to enumerate SCSI CDROM devices without hanging. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-11-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/m68k/q800.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index b774a5b20a..3254ffb5c4 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -691,6 +691,7 @@ static GlobalProperty hw_compat_q800[] = { { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-cd", "quirk_mode_page_truncated", "on"}, }; static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); From 4536fba00ad5a6018ee3c0451808f5c5698796ee Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:11 +0100 Subject: [PATCH 16/20] scsi-disk: allow the MODE_PAGE_R_W_ERROR AWRE bit to be changeable for CDROM drives A/UX sends a MODE_PAGE_R_W_ERROR command with the AWRE bit set to 0 when enumerating CDROM drives. Since the bit is currently hardcoded to 1 then indicate that the AWRE bit can be changed (even though we don't care about the value) so that the MODE_PAGE_R_W_ERROR page can be set successfully. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-12-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 2b2e496ebd..db27e834da 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1188,6 +1188,10 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, case MODE_PAGE_R_W_ERROR: length = 10; if (page_control == 1) { /* Changeable Values */ + if (s->qdev.type == TYPE_ROM) { + /* Automatic Write Reallocation Enabled */ + p[0] = 0x80; + } break; } p[0] = 0x80; /* Automatic Write Reallocation Enabled */ From 356c4c441ec01910314c5867c680bef80d1dd373 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:12 +0100 Subject: [PATCH 17/20] scsi-disk: allow MODE SELECT block descriptor to set the block size The MODE SELECT command can contain an optional block descriptor that can be used to set the device block size. If the block descriptor is present then update the block size on the SCSI device accordingly. This allows CDROMs to be used with A/UX which requires a CDROM drive which is capable of switching from a 2048 byte sector size to a 512 byte sector size. Signed-off-by: Mark Cave-Ayland Message-Id: <20220622105314.802852-13-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 6 ++++++ hw/scsi/trace-events | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index db27e834da..f5cdb9ad4b 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1616,6 +1616,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) goto invalid_param; } + /* Allow changing the block size */ + if (bd_len && p[6] != (s->qdev.blocksize >> 8)) { + s->qdev.blocksize = p[6] << 8; + trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize); + } + len -= bd_len; p += bd_len; diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 8e927ff62d..ab238293f0 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -340,6 +340,7 @@ scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(se scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s" scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd=0x%x (sector %" PRId64 ", count %d) timeout=%u" scsi_disk_mode_select_page_truncated(int page, int len, int page_len) "page %d expected length %d but received length %d" +scsi_disk_mode_select_set_blocksize(int blocksize) "set block size to %d" # scsi-generic.c scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d" From 0fc37adac6a8445a06802d0dd4b5dd639758e660 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:13 +0100 Subject: [PATCH 18/20] q800: add default vendor and product information for scsi-hd devices The Apple HD SC Setup program uses a SCSI INQUIRY command to check that any SCSI hard disks detected match a whitelist of vendors and products before allowing the "Initialise" button to prepare an empty disk. Add known-good default vendor and product information using the existing compat_prop mechanism so the user doesn't have to use long command lines to set the qdev properties manually. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20220622105314.802852-14-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/m68k/q800.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 3254ffb5c4..dccf192e55 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -688,6 +688,9 @@ static void q800_init(MachineState *machine) static GlobalProperty hw_compat_q800[] = { { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-hd", "vendor", " SEAGATE" }, + { "scsi-hd", "product", " ST225N" }, + { "scsi-hd", "ver", "1.0 " }, { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, From 74518fb615d5bf84d3fea3abf7b3f465d0ffbfe6 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 22 Jun 2022 11:53:14 +0100 Subject: [PATCH 19/20] q800: add default vendor and product information for scsi-cd devices The MacOS CDROM driver uses a SCSI INQUIRY command to check that any SCSI CDROMs detected match a whitelist of vendors and products before adding them to the list of available devices. Add known-good default vendor and product information using the existing compat_prop mechanism so the user doesn't have to use long command lines to set the qdev properties manually. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20220622105314.802852-15-mark.cave-ayland@ilande.co.uk> Signed-off-by: Paolo Bonzini --- hw/m68k/q800.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index dccf192e55..101ab0f803 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -695,6 +695,9 @@ static GlobalProperty hw_compat_q800[] = { { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, { "scsi-cd", "quirk_mode_page_truncated", "on"}, + { "scsi-cd", "vendor", "MATSHITA" }, + { "scsi-cd", "product", "CD-ROM CR-8005" }, + { "scsi-cd", "ver", "1.0k" }, }; static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); From c0b3607d5938f5ee7fd16ff1e102afe938fd4b39 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 May 2022 12:55:15 +0200 Subject: [PATCH 20/20] pc-bios/s390-ccw: add -Wno-array-bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The option generates a lot of warnings for integers casted to pointers, for example: /home/pbonzini/work/upstream/qemu/pc-bios/s390-ccw/dasd-ipl.c:174:19: warning: array subscript 0 is outside array bounds of ‘CcwSeekData[0]’ [-Warray-bounds] 174 | seekData->cyl = 0x00; | ~~~~~~~~~~~~~~^~~~~~ Signed-off-by: Paolo Bonzini --- pc-bios/s390-ccw/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 26ad40f94e..c8784c2a08 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -35,6 +35,7 @@ EXTRA_CFLAGS += $(call cc-option,-Werror $(EXTRA_CFLAGS),-Wno-stringop-overflow) EXTRA_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS), -fno-stack-protector) +EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS), -Wno-array-bounds) EXTRA_CFLAGS += -msoft-float EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS),-march=z900,-march=z10) EXTRA_CFLAGS += -std=gnu99