diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-04-30 10:10:31 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-04-30 10:10:31 +0100 |
commit | a1fe58f6ad2282399da256b8579b49b43527e486 (patch) | |
tree | a3fd91e5e2e31f895a6db385a304db071220ab88 | |
parent | 52b7aba62f02cf90f57ee7e02f67d2d8445e7e40 (diff) | |
parent | c8368674980b299604e3cfe9215c4105acefa516 (diff) |
Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging
# gpg: Signature made Wed Apr 29 00:03:44 2015 BST using RSA key ID AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg: It is not certain that the signature belongs to the owner.
# Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB
# Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E
* remotes/jnsnow/tags/ide-pull-request:
qtest: Add assertion that required environment variable is set
qtest/ahci: add flush retry test
libqos: add blkdebug_prepare_script
libqtest: add qmp_async
libqtest: add qmp_eventwait
qtest/ahci: Allow override of default CLI options
qtest/ahci: Add simple flush test
qtest/ahci: test different disk sectors
qtest/ahci: add qcow2 support to ahci-test
fdc: remove sparc sun4m mutations
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/block/fdc.c | 17 | ||||
-rw-r--r-- | tests/Makefile | 1 | ||||
-rw-r--r-- | tests/ahci-test.c | 221 | ||||
-rw-r--r-- | tests/ide-test.c | 34 | ||||
-rw-r--r-- | tests/libqos/ahci.c | 10 | ||||
-rw-r--r-- | tests/libqos/ahci.h | 4 | ||||
-rw-r--r-- | tests/libqos/libqos-pc.c | 5 | ||||
-rw-r--r-- | tests/libqos/libqos-pc.h | 1 | ||||
-rw-r--r-- | tests/libqos/libqos.c | 66 | ||||
-rw-r--r-- | tests/libqos/libqos.h | 3 | ||||
-rw-r--r-- | tests/libqtest.c | 47 | ||||
-rw-r--r-- | tests/libqtest.h | 47 |
12 files changed, 359 insertions, 97 deletions
diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 2bf87c9eea..f72a392163 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -535,8 +535,6 @@ struct FDCtrl { uint8_t pwrd; /* Floppy drives */ uint8_t num_floppies; - /* Sun4m quirks? */ - int sun4m; FDrive drives[MAX_FD]; int reset_sensei; uint32_t check_media_rate; @@ -885,13 +883,6 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl) static void fdctrl_raise_irq(FDCtrl *fdctrl) { - /* Sparc mutation */ - if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) { - /* XXX: not sure */ - fdctrl->msr &= ~FD_MSR_CMDBUSY; - fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; - return; - } if (!(fdctrl->sra & FD_SRA_INTPEND)) { qemu_set_irq(fdctrl->irq, 1); fdctrl->sra |= FD_SRA_INTPEND; @@ -1080,12 +1071,6 @@ static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl) fdctrl->dsr &= ~FD_DSR_PWRDOWN; fdctrl->dor |= FD_DOR_nRESET; - /* Sparc mutation */ - if (fdctrl->sun4m) { - retval |= FD_MSR_DIO; - fdctrl_reset_irq(fdctrl); - }; - FLOPPY_DPRINTF("main status register: 0x%02x\n", retval); return retval; @@ -2241,8 +2226,6 @@ static void sun4m_fdc_initfn(Object *obj) FDCtrlSysBus *sys = SYSBUS_FDC(obj); FDCtrl *fdctrl = &sys->state; - fdctrl->sun4m = 1; - memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops, fdctrl, "fdctrl", 0x08); sysbus_init_mmio(sbd, &fdctrl->iomem); diff --git a/tests/Makefile b/tests/Makefile index 55aa7452b4..309e8697fd 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -415,6 +415,7 @@ GCOV_OPTIONS = -n $(if $(V),-f,) $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ + QTEST_QEMU_IMG=qemu-img$(EXESUF) \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \ diff --git a/tests/ahci-test.c b/tests/ahci-test.c index ea62e249f5..7c23bb2180 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -39,11 +39,14 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/pci_regs.h" -/* Test-specific defines. */ -#define TEST_IMAGE_SIZE (64 * 1024 * 1024) +/* Test-specific defines -- in MiB */ +#define TEST_IMAGE_SIZE_MB (200 * 1024) +#define TEST_IMAGE_SECTORS ((TEST_IMAGE_SIZE_MB / AHCI_SECTOR_SIZE) \ + * 1024 * 1024) /*** Globals ***/ static char tmp_path[] = "/tmp/qtest.XXXXXX"; +static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX"; static bool ahci_pedantic; /*** Function Declarations ***/ @@ -99,19 +102,12 @@ static void generate_pattern(void *buffer, size_t len, size_t cycle_len) /** * Start a Q35 machine and bookmark a handle to the AHCI device. */ -static AHCIQState *ahci_boot(void) +static AHCIQState *ahci_vboot(const char *cli, va_list ap) { AHCIQState *s; - const char *cli; s = g_malloc0(sizeof(AHCIQState)); - - cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s" - ",format=raw" - " -M q35 " - "-device ide-hd,drive=drive0 " - "-global ide-hd.ver=%s"; - s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version"); + s->parent = qtest_pc_vboot(cli, ap); alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT); /* Verify that we have an AHCI device present. */ @@ -121,12 +117,35 @@ static AHCIQState *ahci_boot(void) } /** + * Start a Q35 machine and bookmark a handle to the AHCI device. + */ +static AHCIQState *ahci_boot(const char *cli, ...) +{ + AHCIQState *s; + va_list ap; + + if (cli) { + va_start(ap, cli); + s = ahci_vboot(cli, ap); + va_end(ap); + } else { + cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s" + ",format=qcow2" + " -M q35 " + "-device ide-hd,drive=drive0 " + "-global ide-hd.ver=%s"; + s = ahci_boot(cli, tmp_path, "testdisk", "version"); + } + + return s; +} + +/** * Clean up the PCI device, then terminate the QEMU instance. */ static void ahci_shutdown(AHCIQState *ahci) { QOSState *qs = ahci->parent; - ahci_clean_mem(ahci); free_ahci_device(ahci->dev); g_free(ahci); @@ -137,10 +156,18 @@ static void ahci_shutdown(AHCIQState *ahci) * Boot and fully enable the HBA device. * @see ahci_boot, ahci_pci_enable and ahci_hba_enable. */ -static AHCIQState *ahci_boot_and_enable(void) +static AHCIQState *ahci_boot_and_enable(const char *cli, ...) { AHCIQState *ahci; - ahci = ahci_boot(); + va_list ap; + + if (cli) { + va_start(ap, cli); + ahci = ahci_vboot(cli, ap); + va_end(ap); + } else { + ahci = ahci_boot(NULL); + } ahci_pci_enable(ahci); ahci_hba_enable(ahci); @@ -738,7 +765,7 @@ static void ahci_test_identify(AHCIQState *ahci) ahci_port_clear(ahci, px); /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */ - ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize); + ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize, 0); /* Check serial number/version in the buffer */ /* NB: IDENTIFY strings are packed in 16bit little endian chunks. @@ -754,11 +781,12 @@ static void ahci_test_identify(AHCIQState *ahci) g_assert_cmphex(rc, ==, 0); sect_size = le16_to_cpu(*((uint16_t *)(&buff[5]))); - g_assert_cmphex(sect_size, ==, 0x200); + g_assert_cmphex(sect_size, ==, AHCI_SECTOR_SIZE); } static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, - uint8_t read_cmd, uint8_t write_cmd) + uint64_t sector, uint8_t read_cmd, + uint8_t write_cmd) { uint64_t ptr; uint8_t port; @@ -781,9 +809,9 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, memwrite(ptr, tx, bufsize); /* Write this buffer to disk, then read it back to the DMA buffer. */ - ahci_guest_io(ahci, port, write_cmd, ptr, bufsize); + ahci_guest_io(ahci, port, write_cmd, ptr, bufsize, sector); qmemset(ptr, 0x00, bufsize); - ahci_guest_io(ahci, port, read_cmd, ptr, bufsize); + ahci_guest_io(ahci, port, read_cmd, ptr, bufsize, sector); /*** Read back the Data ***/ memread(ptr, rx, bufsize); @@ -794,6 +822,29 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, g_free(rx); } +static void ahci_test_nondata(AHCIQState *ahci, uint8_t ide_cmd) +{ + uint8_t px; + AHCICommand *cmd; + + /* Sanitize */ + px = ahci_port_select(ahci); + ahci_port_clear(ahci, px); + + /* Issue Command */ + cmd = ahci_command_create(ide_cmd); + ahci_command_commit(ahci, cmd, px); + ahci_command_issue(ahci, cmd); + ahci_command_verify(ahci, cmd); + ahci_command_free(cmd); +} + +static void ahci_test_flush(AHCIQState *ahci) +{ + ahci_test_nondata(ahci, CMD_FLUSH_CACHE); +} + + /******************************************************************************/ /* Test Interfaces */ /******************************************************************************/ @@ -804,7 +855,7 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, static void test_sanity(void) { AHCIQState *ahci; - ahci = ahci_boot(); + ahci = ahci_boot(NULL); ahci_shutdown(ahci); } @@ -815,7 +866,7 @@ static void test_sanity(void) static void test_pci_spec(void) { AHCIQState *ahci; - ahci = ahci_boot(); + ahci = ahci_boot(NULL); ahci_test_pci_spec(ahci); ahci_shutdown(ahci); } @@ -827,8 +878,7 @@ static void test_pci_spec(void) static void test_pci_enable(void) { AHCIQState *ahci; - - ahci = ahci_boot(); + ahci = ahci_boot(NULL); ahci_pci_enable(ahci); ahci_shutdown(ahci); } @@ -841,7 +891,7 @@ static void test_hba_spec(void) { AHCIQState *ahci; - ahci = ahci_boot(); + ahci = ahci_boot(NULL); ahci_pci_enable(ahci); ahci_test_hba_spec(ahci); ahci_shutdown(ahci); @@ -855,7 +905,7 @@ static void test_hba_enable(void) { AHCIQState *ahci; - ahci = ahci_boot(); + ahci = ahci_boot(NULL); ahci_pci_enable(ahci); ahci_hba_enable(ahci); ahci_shutdown(ahci); @@ -869,7 +919,7 @@ static void test_identify(void) { AHCIQState *ahci; - ahci = ahci_boot_and_enable(); + ahci = ahci_boot_and_enable(NULL); ahci_test_identify(ahci); ahci_shutdown(ahci); } @@ -890,7 +940,7 @@ static void test_dma_fragmented(void) unsigned char *rx = g_malloc0(bufsize); uint64_t ptr; - ahci = ahci_boot_and_enable(); + ahci = ahci_boot_and_enable(NULL); px = ahci_port_select(ahci); ahci_port_clear(ahci, px); @@ -928,6 +978,50 @@ static void test_dma_fragmented(void) g_free(tx); } +static void test_flush(void) +{ + AHCIQState *ahci; + + ahci = ahci_boot_and_enable(NULL); + ahci_test_flush(ahci); + ahci_shutdown(ahci); +} + +static void test_flush_retry(void) +{ + AHCIQState *ahci; + AHCICommand *cmd; + uint8_t port; + const char *s; + + prepare_blkdebug_script(debug_path, "flush_to_disk"); + ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0," + "format=qcow2,cache=writeback," + "rerror=stop,werror=stop " + "-M q35 " + "-device ide-hd,drive=drive0 ", + debug_path, + tmp_path); + + /* Issue Flush Command */ + port = ahci_port_select(ahci); + ahci_port_clear(ahci, port); + cmd = ahci_command_create(CMD_FLUSH_CACHE); + ahci_command_commit(ahci, cmd, port); + ahci_command_issue_async(ahci, cmd); + qmp_eventwait("STOP"); + + /* Complete the command */ + s = "{'execute':'cont' }"; + qmp_async(s); + qmp_eventwait("RESUME"); + ahci_command_wait(ahci, cmd); + ahci_command_verify(ahci, cmd); + + ahci_command_free(cmd); + ahci_shutdown(ahci); +} + /******************************************************************************/ /* AHCI I/O Test Matrix Definitions */ @@ -968,12 +1062,45 @@ enum IOOps { NUM_IO_OPS }; +enum OffsetType { + OFFSET_BEGIN = 0, + OFFSET_ZERO = OFFSET_BEGIN, + OFFSET_LOW, + OFFSET_HIGH, + NUM_OFFSETS +}; + +static const char *offset_str[NUM_OFFSETS] = { "zero", "low", "high" }; + typedef struct AHCIIOTestOptions { enum BuffLen length; enum AddrMode address_type; enum IOMode io_type; + enum OffsetType offset; } AHCIIOTestOptions; +static uint64_t offset_sector(enum OffsetType ofst, + enum AddrMode addr_type, + uint64_t buffsize) +{ + uint64_t ceil; + uint64_t nsectors; + + switch (ofst) { + case OFFSET_ZERO: + return 0; + case OFFSET_LOW: + return 1; + case OFFSET_HIGH: + ceil = (addr_type == ADDR_MODE_LBA28) ? 0xfffffff : 0xffffffffffff; + ceil = MIN(ceil, TEST_IMAGE_SECTORS - 1); + nsectors = buffsize / AHCI_SECTOR_SIZE; + return ceil - nsectors + 1; + default: + g_assert_not_reached(); + } +} + /** * Table of possible I/O ATA commands given a set of enumerations. */ @@ -1001,12 +1128,12 @@ static const uint8_t io_cmds[NUM_MODES][NUM_ADDR_MODES][NUM_IO_OPS] = { * transfer modes, and buffer sizes. */ static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma, - unsigned bufsize) + unsigned bufsize, uint64_t sector) { AHCIQState *ahci; - ahci = ahci_boot_and_enable(); - ahci_test_io_rw_simple(ahci, bufsize, + ahci = ahci_boot_and_enable(NULL); + ahci_test_io_rw_simple(ahci, bufsize, sector, io_cmds[dma][lba48][IO_READ], io_cmds[dma][lba48][IO_WRITE]); ahci_shutdown(ahci); @@ -1019,6 +1146,7 @@ static void test_io_interface(gconstpointer opaque) { AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque; unsigned bufsize; + uint64_t sector; switch (opts->length) { case LEN_SIMPLE: @@ -1037,13 +1165,14 @@ static void test_io_interface(gconstpointer opaque) g_assert_not_reached(); } - test_io_rw_interface(opts->address_type, opts->io_type, bufsize); + sector = offset_sector(opts->offset, opts->address_type, bufsize); + test_io_rw_interface(opts->address_type, opts->io_type, bufsize, sector); g_free(opts); return; } static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, - enum BuffLen len) + enum BuffLen len, enum OffsetType offset) { static const char *arch; char *name; @@ -1052,15 +1181,17 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, opts->length = len; opts->address_type = addr; opts->io_type = type; + opts->offset = offset; if (!arch) { arch = qtest_get_arch(); } - name = g_strdup_printf("/%s/ahci/io/%s/%s/%s", arch, + name = g_strdup_printf("/%s/ahci/io/%s/%s/%s/%s", arch, io_mode_str[type], addr_mode_str[addr], - buff_len_str[len]); + buff_len_str[len], + offset_str[offset]); g_test_add_data_func(name, opts, test_io_interface); g_free(name); @@ -1071,10 +1202,10 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, int main(int argc, char **argv) { const char *arch; - int fd; int ret; + int fd; int c; - int i, j, k; + int i, j, k, m; static struct option long_options[] = { {"pedantic", no_argument, 0, 'p' }, @@ -1108,11 +1239,13 @@ int main(int argc, char **argv) return 0; } - /* Create a temporary raw image */ - fd = mkstemp(tmp_path); + /* Create a temporary qcow2 image */ + close(mkstemp(tmp_path)); + mkqcow2(tmp_path, TEST_IMAGE_SIZE_MB); + + /* Create temporary blkdebug instructions */ + fd = mkstemp(debug_path); g_assert(fd >= 0); - ret = ftruncate(fd, TEST_IMAGE_SIZE); - g_assert(ret == 0); close(fd); /* Run the tests */ @@ -1126,17 +1259,23 @@ int main(int argc, char **argv) for (i = MODE_BEGIN; i < NUM_MODES; i++) { for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) { for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) { - create_ahci_io_test(i, j, k); + for (m = OFFSET_BEGIN; m < NUM_OFFSETS; m++) { + create_ahci_io_test(i, j, k, m); + } } } } qtest_add_func("/ahci/io/dma/lba28/fragmented", test_dma_fragmented); + qtest_add_func("/ahci/flush/simple", test_flush); + qtest_add_func("/ahci/flush/retry", test_flush_retry); + ret = g_test_run(); /* Cleanup */ unlink(tmp_path); + unlink(debug_path); return ret; } diff --git a/tests/ide-test.c b/tests/ide-test.c index b28a3023c2..78382e9c75 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -29,6 +29,7 @@ #include <glib.h> #include "libqtest.h" +#include "libqos/libqos.h" #include "libqos/pci-pc.h" #include "libqos/malloc-pc.h" @@ -494,33 +495,10 @@ static void test_flush(void) ide_test_quit(); } -static void prepare_blkdebug_script(const char *debug_fn, const char *event) -{ - FILE *debug_file = fopen(debug_fn, "w"); - int ret; - - fprintf(debug_file, "[inject-error]\n"); - fprintf(debug_file, "event = \"%s\"\n", event); - fprintf(debug_file, "errno = \"5\"\n"); - fprintf(debug_file, "state = \"1\"\n"); - fprintf(debug_file, "immediately = \"off\"\n"); - fprintf(debug_file, "once = \"on\"\n"); - - fprintf(debug_file, "[set-state]\n"); - fprintf(debug_file, "event = \"%s\"\n", event); - fprintf(debug_file, "new_state = \"2\"\n"); - fflush(debug_file); - g_assert(!ferror(debug_file)); - - ret = fclose(debug_file); - g_assert(ret == 0); -} - static void test_retry_flush(const char *machine) { uint8_t data; const char *s; - QDict *response; prepare_blkdebug_script(debug_path, "flush_to_disk"); @@ -539,15 +517,7 @@ static void test_retry_flush(const char *machine) assert_bit_set(data, BSY | DRDY); assert_bit_clear(data, DF | ERR | DRQ); - for (;; response = NULL) { - response = qmp_receive(); - if ((qdict_haskey(response, "event")) && - (strcmp(qdict_get_str(response, "event"), "STOP") == 0)) { - QDECREF(response); - break; - } - QDECREF(response); - } + qmp_eventwait("STOP"); /* Complete the command */ s = "{'execute':'cont' }"; diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index b0f39a5e32..a18c12bcc1 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -568,13 +568,15 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd) /* Given a guest buffer address, perform an IO operation */ void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, - uint64_t buffer, size_t bufsize) + uint64_t buffer, size_t bufsize, uint64_t sector) { AHCICommand *cmd; - cmd = ahci_command_create(ide_cmd); ahci_command_set_buffer(cmd, buffer); ahci_command_set_size(cmd, bufsize); + if (sector) { + ahci_command_set_offset(cmd, sector); + } ahci_command_commit(ahci, cmd, port); ahci_command_issue(ahci, cmd); ahci_command_verify(ahci, cmd); @@ -612,7 +614,7 @@ static AHCICommandProp *ahci_command_find(uint8_t command_name) /* Given a HOST buffer, create a buffer address and perform an IO operation. */ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, - void *buffer, size_t bufsize) + void *buffer, size_t bufsize, uint64_t sector) { uint64_t ptr; AHCICommandProp *props; @@ -626,7 +628,7 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, memwrite(ptr, buffer, bufsize); } - ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize); + ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector); if (props->read) { memread(ptr, buffer, bufsize); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 888545d5a2..40e8ca48ba 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -523,9 +523,9 @@ void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr); unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, - uint64_t gbuffer, size_t size); + uint64_t gbuffer, size_t size, uint64_t sector); void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, - void *buffer, size_t bufsize); + void *buffer, size_t bufsize, uint64_t sector); /* Command Lifecycle */ AHCICommand *ahci_command_create(uint8_t command_name); diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index bbace893fb..1403699377 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -6,6 +6,11 @@ static QOSOps qos_ops = { .uninit_allocator = pc_alloc_uninit }; +QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) +{ + return qtest_vboot(&qos_ops, cmdline_fmt, ap); +} + QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) { QOSState *qs; diff --git a/tests/libqos/libqos-pc.h b/tests/libqos/libqos-pc.h index 316857d32f..b1820c5739 100644 --- a/tests/libqos/libqos-pc.h +++ b/tests/libqos/libqos-pc.h @@ -3,6 +3,7 @@ #include "libqos/libqos.h" +QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap); QOSState *qtest_pc_boot(const char *cmdline_fmt, ...); void qtest_pc_shutdown(QOSState *qs); diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index bc8beb281f..7e7207856e 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -61,3 +61,69 @@ void qtest_shutdown(QOSState *qs) qtest_quit(qs->qts); g_free(qs); } + +void mkimg(const char *file, const char *fmt, unsigned size_mb) +{ + gchar *cli; + bool ret; + int rc; + GError *err = NULL; + char *qemu_img_path; + gchar *out, *out2; + char *abs_path; + + qemu_img_path = getenv("QTEST_QEMU_IMG"); + abs_path = realpath(qemu_img_path, NULL); + assert(qemu_img_path); + + cli = g_strdup_printf("%s create -f %s %s %uM", abs_path, + fmt, file, size_mb); + ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err); + if (err) { + fprintf(stderr, "%s\n", err->message); + g_error_free(err); + } + g_assert(ret && !err); + + /* In glib 2.34, we have g_spawn_check_exit_status. in 2.12, we don't. + * glib 2.43.91 implementation assumes that any non-zero is an error for + * windows, but uses extra precautions for Linux. However, + * 0 is only possible if the program exited normally, so that should be + * sufficient for our purposes on all platforms, here. */ + if (rc) { + fprintf(stderr, "qemu-img returned status code %d\n", rc); + } + g_assert(!rc); + + g_free(out); + g_free(out2); + g_free(cli); + free(abs_path); +} + +void mkqcow2(const char *file, unsigned size_mb) +{ + return mkimg(file, "qcow2", size_mb); +} + +void prepare_blkdebug_script(const char *debug_fn, const char *event) +{ + FILE *debug_file = fopen(debug_fn, "w"); + int ret; + + fprintf(debug_file, "[inject-error]\n"); + fprintf(debug_file, "event = \"%s\"\n", event); + fprintf(debug_file, "errno = \"5\"\n"); + fprintf(debug_file, "state = \"1\"\n"); + fprintf(debug_file, "immediately = \"off\"\n"); + fprintf(debug_file, "once = \"on\"\n"); + + fprintf(debug_file, "[set-state]\n"); + fprintf(debug_file, "event = \"%s\"\n", event); + fprintf(debug_file, "new_state = \"2\"\n"); + fflush(debug_file); + g_assert(!ferror(debug_file)); + + ret = fclose(debug_file); + g_assert(ret == 0); +} diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 612d41e5e9..f57362b688 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -19,6 +19,9 @@ typedef struct QOSState { QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); void qtest_shutdown(QOSState *qs); +void mkimg(const char *file, const char *fmt, unsigned size_mb); +void mkqcow2(const char *file, unsigned size_mb); +void prepare_blkdebug_script(const char *debug_fn, const char *event); static inline uint64_t qmalloc(QOSState *q, size_t bytes) { diff --git a/tests/libqtest.c b/tests/libqtest.c index 12d65bd1e6..a525dc532c 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -388,7 +388,12 @@ QDict *qtest_qmp_receive(QTestState *s) return qmp.response; } -QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) +/** + * Allow users to send a message without waiting for the reply, + * in the case that they choose to discard all replies up until + * a particular EVENT is received. + */ +void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) { va_list ap_copy; QObject *qobj; @@ -417,6 +422,11 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) QDECREF(qstr); qobject_decref(qobj); } +} + +QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) +{ + qtest_async_qmpv(s, fmt, ap); /* Receive reply */ return qtest_qmp_receive(s); @@ -433,6 +443,15 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...) return response; } +void qtest_async_qmp(QTestState *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qtest_async_qmpv(s, fmt, ap); + va_end(ap); +} + void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap) { QDict *response = qtest_qmpv(s, fmt, ap); @@ -450,9 +469,26 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...) QDECREF(response); } +void qtest_qmp_eventwait(QTestState *s, const char *event) +{ + QDict *response; + + for (;;) { + response = qtest_qmp_receive(s); + if ((qdict_haskey(response, "event")) && + (strcmp(qdict_get_str(response, "event"), event) == 0)) { + QDECREF(response); + break; + } + QDECREF(response); + } +} + + const char *qtest_get_arch(void) { const char *qemu = getenv("QTEST_QEMU_BINARY"); + g_assert(qemu != NULL); const char *end = strrchr(qemu, '/'); return end + strlen("/qemu-system-"); @@ -695,6 +731,15 @@ QDict *qmp(const char *fmt, ...) return response; } +void qmp_async(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qtest_async_qmpv(global_qtest, fmt, ap); + va_end(ap); +} + void qmp_discard_response(const char *fmt, ...) { va_list ap; diff --git a/tests/libqtest.h b/tests/libqtest.h index 03469b8781..4b54b5da9e 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -64,6 +64,15 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...); QDict *qtest_qmp(QTestState *s, const char *fmt, ...); /** + * qtest_async_qmp: + * @s: #QTestState instance to operate on. + * @fmt...: QMP message to send to qemu + * + * Sends a QMP message to QEMU and leaves the response in the stream. + */ +void qtest_async_qmp(QTestState *s, const char *fmt, ...); + +/** * qtest_qmpv_discard_response: * @s: #QTestState instance to operate on. * @fmt: QMP message to send to QEMU @@ -84,6 +93,16 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap); QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap); /** + * qtest_async_qmpv: + * @s: #QTestState instance to operate on. + * @fmt: QMP message to send to QEMU + * @ap: QMP message arguments + * + * Sends a QMP message to QEMU and leaves the response in the stream. + */ +void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap); + +/** * qtest_receive: * @s: #QTestState instance to operate on. * @@ -92,6 +111,15 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap); QDict *qtest_qmp_receive(QTestState *s); /** + * qtest_qmp_eventwait: + * @s: #QTestState instance to operate on. + * @s: #event event to wait for. + * + * Continuosly polls for QMP responses until it receives the desired event. + */ +void qtest_qmp_eventwait(QTestState *s, const char *event); + +/** * qtest_get_irq: * @s: #QTestState instance to operate on. * @num: Interrupt to observe. @@ -411,6 +439,14 @@ static inline void qtest_end(void) QDict *qmp(const char *fmt, ...); /** + * qmp_async: + * @fmt...: QMP message to send to qemu + * + * Sends a QMP message to QEMU and leaves the response in the stream. + */ +void qmp_async(const char *fmt, ...); + +/** * qmp_discard_response: * @fmt...: QMP message to send to qemu * @@ -429,6 +465,17 @@ static inline QDict *qmp_receive(void) } /** + * qmp_eventwait: + * @s: #event event to wait for. + * + * Continuosly polls for QMP responses until it receives the desired event. + */ +static inline void qmp_eventwait(const char *event) +{ + return qtest_qmp_eventwait(global_qtest, event); +} + +/** * get_irq: * @num: Interrupt to observe. * |