-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQIcBAABAgAGBQJVQBHQAAoJEH3vgQaq/DkOPd4QAIqIcGHd6Frr9ZFnETQ3WN0S TzQ834zgNV/zdrnSGoSF3Abcurq1XYEqqh3HUIDpOwqO0ZeeLXjrA1WG7HxAEb/y Cdcqg9isfD4am8dREgPKkKRVoKosxu1CJcwXcnu67USsX8MpyiZc6TD/Rmyjq5qO HtauRj82NffMPz1QtydwOvoRvlqmuyiGkuCThnaBgMDcBXtcIWmT2YjtGn93nEY2 i92m/cJyeRc/RZMByo2FOe3fGzt46tj3GNcDM2MrhrEOKaBGfzyvQa9hqBhTY5KE a1HwGtXYUPB0cXUmbfEMVUoQ1JUa4hFG8RVOJElt78GYpJhn5S6OF/PQO6JRLGJO WxcjDUDlIAJ+Vv0OD1xKbhaeM/mFF5beL9WbB3ow8pwRw9Mj/tn3IYr1WPUTb1dO +xd9MAJByEi2bAeiQ/WZB2tvRdrqJZDlFs5N/OB+VLTEmgbhXBZ++M98IR9O6dP3 chdctCfXSh/XrwskJ66La2SORpi+D6VRTkiiPe0OBaR+VKHI+UxLA5ie8LUxpVAj OStt3KXSnLlL76KZW88eWw0416a3BxmHWHKyG3azFWTBCPiEwfSexjjlX3o0uRAW Vj9/SpEKi29XIIWKwgxv8NHjONtCQp+6TYSY+g06Lqy87taO363z4JBtDWp8Gq6B UlNzwmHqp13c3Tn4jgQk =Kpae -----END PGP SIGNATURE----- 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>
This commit is contained in:
		
						commit
						a1fe58f6ad
					
				@ -535,8 +535,6 @@ struct FDCtrl {
 | 
				
			|||||||
    uint8_t pwrd;
 | 
					    uint8_t pwrd;
 | 
				
			||||||
    /* Floppy drives */
 | 
					    /* Floppy drives */
 | 
				
			||||||
    uint8_t num_floppies;
 | 
					    uint8_t num_floppies;
 | 
				
			||||||
    /* Sun4m quirks? */
 | 
					 | 
				
			||||||
    int sun4m;
 | 
					 | 
				
			||||||
    FDrive drives[MAX_FD];
 | 
					    FDrive drives[MAX_FD];
 | 
				
			||||||
    int reset_sensei;
 | 
					    int reset_sensei;
 | 
				
			||||||
    uint32_t check_media_rate;
 | 
					    uint32_t check_media_rate;
 | 
				
			||||||
@ -885,13 +883,6 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void fdctrl_raise_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)) {
 | 
					    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
 | 
				
			||||||
        qemu_set_irq(fdctrl->irq, 1);
 | 
					        qemu_set_irq(fdctrl->irq, 1);
 | 
				
			||||||
        fdctrl->sra |= FD_SRA_INTPEND;
 | 
					        fdctrl->sra |= FD_SRA_INTPEND;
 | 
				
			||||||
@ -1080,12 +1071,6 @@ static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
 | 
				
			|||||||
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
 | 
					    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
 | 
				
			||||||
    fdctrl->dor |= FD_DOR_nRESET;
 | 
					    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);
 | 
					    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return retval;
 | 
					    return retval;
 | 
				
			||||||
@ -2241,8 +2226,6 @@ static void sun4m_fdc_initfn(Object *obj)
 | 
				
			|||||||
    FDCtrlSysBus *sys = SYSBUS_FDC(obj);
 | 
					    FDCtrlSysBus *sys = SYSBUS_FDC(obj);
 | 
				
			||||||
    FDCtrl *fdctrl = &sys->state;
 | 
					    FDCtrl *fdctrl = &sys->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fdctrl->sun4m = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
 | 
					    memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
 | 
				
			||||||
                          fdctrl, "fdctrl", 0x08);
 | 
					                          fdctrl, "fdctrl", 0x08);
 | 
				
			||||||
    sysbus_init_mmio(sbd, &fdctrl->iomem);
 | 
					    sysbus_init_mmio(sbd, &fdctrl->iomem);
 | 
				
			||||||
 | 
				
			|||||||
@ -415,6 +415,7 @@ GCOV_OPTIONS = -n $(if $(V),-f,)
 | 
				
			|||||||
$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
 | 
					$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
 | 
				
			||||||
	$(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,)
 | 
						$(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,)
 | 
				
			||||||
	$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
 | 
						$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
 | 
				
			||||||
 | 
							QTEST_QEMU_IMG=qemu-img$(EXESUF) \
 | 
				
			||||||
		MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
 | 
							MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
 | 
				
			||||||
		gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
 | 
							gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
 | 
				
			||||||
	$(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \
 | 
						$(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \
 | 
				
			||||||
 | 
				
			|||||||
@ -39,11 +39,14 @@
 | 
				
			|||||||
#include "hw/pci/pci_ids.h"
 | 
					#include "hw/pci/pci_ids.h"
 | 
				
			||||||
#include "hw/pci/pci_regs.h"
 | 
					#include "hw/pci/pci_regs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Test-specific defines. */
 | 
					/* Test-specific defines -- in MiB */
 | 
				
			||||||
#define TEST_IMAGE_SIZE    (64 * 1024 * 1024)
 | 
					#define TEST_IMAGE_SIZE_MB (200 * 1024)
 | 
				
			||||||
 | 
					#define TEST_IMAGE_SECTORS ((TEST_IMAGE_SIZE_MB / AHCI_SECTOR_SIZE)     \
 | 
				
			||||||
 | 
					                            * 1024 * 1024)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*** Globals ***/
 | 
					/*** Globals ***/
 | 
				
			||||||
static char tmp_path[] = "/tmp/qtest.XXXXXX";
 | 
					static char tmp_path[] = "/tmp/qtest.XXXXXX";
 | 
				
			||||||
 | 
					static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
 | 
				
			||||||
static bool ahci_pedantic;
 | 
					static bool ahci_pedantic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*** Function Declarations ***/
 | 
					/*** 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.
 | 
					 * 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;
 | 
					    AHCIQState *s;
 | 
				
			||||||
    const char *cli;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s = g_malloc0(sizeof(AHCIQState));
 | 
					    s = g_malloc0(sizeof(AHCIQState));
 | 
				
			||||||
 | 
					    s->parent = qtest_pc_vboot(cli, ap);
 | 
				
			||||||
    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");
 | 
					 | 
				
			||||||
    alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT);
 | 
					    alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Verify that we have an AHCI device present. */
 | 
					    /* Verify that we have an AHCI device present. */
 | 
				
			||||||
@ -120,13 +116,36 @@ static AHCIQState *ahci_boot(void)
 | 
				
			|||||||
    return s;
 | 
					    return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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.
 | 
					 * Clean up the PCI device, then terminate the QEMU instance.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void ahci_shutdown(AHCIQState *ahci)
 | 
					static void ahci_shutdown(AHCIQState *ahci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QOSState *qs = ahci->parent;
 | 
					    QOSState *qs = ahci->parent;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ahci_clean_mem(ahci);
 | 
					    ahci_clean_mem(ahci);
 | 
				
			||||||
    free_ahci_device(ahci->dev);
 | 
					    free_ahci_device(ahci->dev);
 | 
				
			||||||
    g_free(ahci);
 | 
					    g_free(ahci);
 | 
				
			||||||
@ -137,10 +156,18 @@ static void ahci_shutdown(AHCIQState *ahci)
 | 
				
			|||||||
 * Boot and fully enable the HBA device.
 | 
					 * Boot and fully enable the HBA device.
 | 
				
			||||||
 * @see ahci_boot, ahci_pci_enable and ahci_hba_enable.
 | 
					 * @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;
 | 
					    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_pci_enable(ahci);
 | 
				
			||||||
    ahci_hba_enable(ahci);
 | 
					    ahci_hba_enable(ahci);
 | 
				
			||||||
@ -738,7 +765,7 @@ static void ahci_test_identify(AHCIQState *ahci)
 | 
				
			|||||||
    ahci_port_clear(ahci, px);
 | 
					    ahci_port_clear(ahci, px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
 | 
					    /* "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 */
 | 
					    /* Check serial number/version in the buffer */
 | 
				
			||||||
    /* NB: IDENTIFY strings are packed in 16bit little endian chunks.
 | 
					    /* 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);
 | 
					    g_assert_cmphex(rc, ==, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sect_size = le16_to_cpu(*((uint16_t *)(&buff[5])));
 | 
					    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,
 | 
					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;
 | 
					    uint64_t ptr;
 | 
				
			||||||
    uint8_t port;
 | 
					    uint8_t port;
 | 
				
			||||||
@ -781,9 +809,9 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
 | 
				
			|||||||
    memwrite(ptr, tx, bufsize);
 | 
					    memwrite(ptr, tx, bufsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Write this buffer to disk, then read it back to the DMA buffer. */
 | 
					    /* 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);
 | 
					    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 ***/
 | 
					    /*** Read back the Data ***/
 | 
				
			||||||
    memread(ptr, rx, bufsize);
 | 
					    memread(ptr, rx, bufsize);
 | 
				
			||||||
@ -794,6 +822,29 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
 | 
				
			|||||||
    g_free(rx);
 | 
					    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                                                            */
 | 
					/* Test Interfaces                                                            */
 | 
				
			||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
@ -804,7 +855,7 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
 | 
				
			|||||||
static void test_sanity(void)
 | 
					static void test_sanity(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
    ahci = ahci_boot();
 | 
					    ahci = ahci_boot(NULL);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -815,7 +866,7 @@ static void test_sanity(void)
 | 
				
			|||||||
static void test_pci_spec(void)
 | 
					static void test_pci_spec(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
    ahci = ahci_boot();
 | 
					    ahci = ahci_boot(NULL);
 | 
				
			||||||
    ahci_test_pci_spec(ahci);
 | 
					    ahci_test_pci_spec(ahci);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -827,8 +878,7 @@ static void test_pci_spec(void)
 | 
				
			|||||||
static void test_pci_enable(void)
 | 
					static void test_pci_enable(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
 | 
					    ahci = ahci_boot(NULL);
 | 
				
			||||||
    ahci = ahci_boot();
 | 
					 | 
				
			||||||
    ahci_pci_enable(ahci);
 | 
					    ahci_pci_enable(ahci);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -841,7 +891,7 @@ static void test_hba_spec(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ahci = ahci_boot();
 | 
					    ahci = ahci_boot(NULL);
 | 
				
			||||||
    ahci_pci_enable(ahci);
 | 
					    ahci_pci_enable(ahci);
 | 
				
			||||||
    ahci_test_hba_spec(ahci);
 | 
					    ahci_test_hba_spec(ahci);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
@ -855,7 +905,7 @@ static void test_hba_enable(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ahci = ahci_boot();
 | 
					    ahci = ahci_boot(NULL);
 | 
				
			||||||
    ahci_pci_enable(ahci);
 | 
					    ahci_pci_enable(ahci);
 | 
				
			||||||
    ahci_hba_enable(ahci);
 | 
					    ahci_hba_enable(ahci);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
@ -869,7 +919,7 @@ static void test_identify(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ahci = ahci_boot_and_enable();
 | 
					    ahci = ahci_boot_and_enable(NULL);
 | 
				
			||||||
    ahci_test_identify(ahci);
 | 
					    ahci_test_identify(ahci);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -890,7 +940,7 @@ static void test_dma_fragmented(void)
 | 
				
			|||||||
    unsigned char *rx = g_malloc0(bufsize);
 | 
					    unsigned char *rx = g_malloc0(bufsize);
 | 
				
			||||||
    uint64_t ptr;
 | 
					    uint64_t ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ahci = ahci_boot_and_enable();
 | 
					    ahci = ahci_boot_and_enable(NULL);
 | 
				
			||||||
    px = ahci_port_select(ahci);
 | 
					    px = ahci_port_select(ahci);
 | 
				
			||||||
    ahci_port_clear(ahci, px);
 | 
					    ahci_port_clear(ahci, px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -928,6 +978,50 @@ static void test_dma_fragmented(void)
 | 
				
			|||||||
    g_free(tx);
 | 
					    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                                           */
 | 
					/* AHCI I/O Test Matrix Definitions                                           */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -968,12 +1062,45 @@ enum IOOps {
 | 
				
			|||||||
    NUM_IO_OPS
 | 
					    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 {
 | 
					typedef struct AHCIIOTestOptions {
 | 
				
			||||||
    enum BuffLen length;
 | 
					    enum BuffLen length;
 | 
				
			||||||
    enum AddrMode address_type;
 | 
					    enum AddrMode address_type;
 | 
				
			||||||
    enum IOMode io_type;
 | 
					    enum IOMode io_type;
 | 
				
			||||||
 | 
					    enum OffsetType offset;
 | 
				
			||||||
} AHCIIOTestOptions;
 | 
					} 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.
 | 
					 * 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.
 | 
					 * transfer modes, and buffer sizes.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
 | 
					static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
 | 
				
			||||||
                                 unsigned bufsize)
 | 
					                                 unsigned bufsize, uint64_t sector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AHCIQState *ahci;
 | 
					    AHCIQState *ahci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ahci = ahci_boot_and_enable();
 | 
					    ahci = ahci_boot_and_enable(NULL);
 | 
				
			||||||
    ahci_test_io_rw_simple(ahci, bufsize,
 | 
					    ahci_test_io_rw_simple(ahci, bufsize, sector,
 | 
				
			||||||
                           io_cmds[dma][lba48][IO_READ],
 | 
					                           io_cmds[dma][lba48][IO_READ],
 | 
				
			||||||
                           io_cmds[dma][lba48][IO_WRITE]);
 | 
					                           io_cmds[dma][lba48][IO_WRITE]);
 | 
				
			||||||
    ahci_shutdown(ahci);
 | 
					    ahci_shutdown(ahci);
 | 
				
			||||||
@ -1019,6 +1146,7 @@ static void test_io_interface(gconstpointer opaque)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
 | 
					    AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
 | 
				
			||||||
    unsigned bufsize;
 | 
					    unsigned bufsize;
 | 
				
			||||||
 | 
					    uint64_t sector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (opts->length) {
 | 
					    switch (opts->length) {
 | 
				
			||||||
    case LEN_SIMPLE:
 | 
					    case LEN_SIMPLE:
 | 
				
			||||||
@ -1037,13 +1165,14 @@ static void test_io_interface(gconstpointer opaque)
 | 
				
			|||||||
        g_assert_not_reached();
 | 
					        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);
 | 
					    g_free(opts);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
 | 
					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;
 | 
					    static const char *arch;
 | 
				
			||||||
    char *name;
 | 
					    char *name;
 | 
				
			||||||
@ -1052,15 +1181,17 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
 | 
				
			|||||||
    opts->length = len;
 | 
					    opts->length = len;
 | 
				
			||||||
    opts->address_type = addr;
 | 
					    opts->address_type = addr;
 | 
				
			||||||
    opts->io_type = type;
 | 
					    opts->io_type = type;
 | 
				
			||||||
 | 
					    opts->offset = offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!arch) {
 | 
					    if (!arch) {
 | 
				
			||||||
        arch = qtest_get_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],
 | 
					                           io_mode_str[type],
 | 
				
			||||||
                           addr_mode_str[addr],
 | 
					                           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_test_add_data_func(name, opts, test_io_interface);
 | 
				
			||||||
    g_free(name);
 | 
					    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)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const char *arch;
 | 
					    const char *arch;
 | 
				
			||||||
    int fd;
 | 
					 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
    int c;
 | 
					    int c;
 | 
				
			||||||
    int i, j, k;
 | 
					    int i, j, k, m;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static struct option long_options[] = {
 | 
					    static struct option long_options[] = {
 | 
				
			||||||
        {"pedantic", no_argument, 0, 'p' },
 | 
					        {"pedantic", no_argument, 0, 'p' },
 | 
				
			||||||
@ -1108,11 +1239,13 @@ int main(int argc, char **argv)
 | 
				
			|||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Create a temporary raw image */
 | 
					    /* Create a temporary qcow2 image */
 | 
				
			||||||
    fd = mkstemp(tmp_path);
 | 
					    close(mkstemp(tmp_path));
 | 
				
			||||||
 | 
					    mkqcow2(tmp_path, TEST_IMAGE_SIZE_MB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Create temporary blkdebug instructions */
 | 
				
			||||||
 | 
					    fd = mkstemp(debug_path);
 | 
				
			||||||
    g_assert(fd >= 0);
 | 
					    g_assert(fd >= 0);
 | 
				
			||||||
    ret = ftruncate(fd, TEST_IMAGE_SIZE);
 | 
					 | 
				
			||||||
    g_assert(ret == 0);
 | 
					 | 
				
			||||||
    close(fd);
 | 
					    close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Run the tests */
 | 
					    /* Run the tests */
 | 
				
			||||||
@ -1126,17 +1259,23 @@ int main(int argc, char **argv)
 | 
				
			|||||||
    for (i = MODE_BEGIN; i < NUM_MODES; i++) {
 | 
					    for (i = MODE_BEGIN; i < NUM_MODES; i++) {
 | 
				
			||||||
        for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
 | 
					        for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
 | 
				
			||||||
            for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) {
 | 
					            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/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();
 | 
					    ret = g_test_run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Cleanup */
 | 
					    /* Cleanup */
 | 
				
			||||||
    unlink(tmp_path);
 | 
					    unlink(tmp_path);
 | 
				
			||||||
 | 
					    unlink(debug_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@
 | 
				
			|||||||
#include <glib.h>
 | 
					#include <glib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "libqtest.h"
 | 
					#include "libqtest.h"
 | 
				
			||||||
 | 
					#include "libqos/libqos.h"
 | 
				
			||||||
#include "libqos/pci-pc.h"
 | 
					#include "libqos/pci-pc.h"
 | 
				
			||||||
#include "libqos/malloc-pc.h"
 | 
					#include "libqos/malloc-pc.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -494,33 +495,10 @@ static void test_flush(void)
 | 
				
			|||||||
    ide_test_quit();
 | 
					    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)
 | 
					static void test_retry_flush(const char *machine)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t data;
 | 
					    uint8_t data;
 | 
				
			||||||
    const char *s;
 | 
					    const char *s;
 | 
				
			||||||
    QDict *response;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prepare_blkdebug_script(debug_path, "flush_to_disk");
 | 
					    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_set(data, BSY | DRDY);
 | 
				
			||||||
    assert_bit_clear(data, DF | ERR | DRQ);
 | 
					    assert_bit_clear(data, DF | ERR | DRQ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (;; response = NULL) {
 | 
					    qmp_eventwait("STOP");
 | 
				
			||||||
        response = qmp_receive();
 | 
					 | 
				
			||||||
        if ((qdict_haskey(response, "event")) &&
 | 
					 | 
				
			||||||
            (strcmp(qdict_get_str(response, "event"), "STOP") == 0)) {
 | 
					 | 
				
			||||||
            QDECREF(response);
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        QDECREF(response);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Complete the command */
 | 
					    /* Complete the command */
 | 
				
			||||||
    s = "{'execute':'cont' }";
 | 
					    s = "{'execute':'cont' }";
 | 
				
			||||||
 | 
				
			|||||||
@ -568,13 +568,15 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Given a guest buffer address, perform an IO operation */
 | 
					/* Given a guest buffer address, perform an IO operation */
 | 
				
			||||||
void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
 | 
					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;
 | 
					    AHCICommand *cmd;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    cmd = ahci_command_create(ide_cmd);
 | 
					    cmd = ahci_command_create(ide_cmd);
 | 
				
			||||||
    ahci_command_set_buffer(cmd, buffer);
 | 
					    ahci_command_set_buffer(cmd, buffer);
 | 
				
			||||||
    ahci_command_set_size(cmd, bufsize);
 | 
					    ahci_command_set_size(cmd, bufsize);
 | 
				
			||||||
 | 
					    if (sector) {
 | 
				
			||||||
 | 
					        ahci_command_set_offset(cmd, sector);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    ahci_command_commit(ahci, cmd, port);
 | 
					    ahci_command_commit(ahci, cmd, port);
 | 
				
			||||||
    ahci_command_issue(ahci, cmd);
 | 
					    ahci_command_issue(ahci, cmd);
 | 
				
			||||||
    ahci_command_verify(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. */
 | 
					/* 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 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;
 | 
					    uint64_t ptr;
 | 
				
			||||||
    AHCICommandProp *props;
 | 
					    AHCICommandProp *props;
 | 
				
			||||||
@ -626,7 +628,7 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
 | 
				
			|||||||
        memwrite(ptr, buffer, bufsize);
 | 
					        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) {
 | 
					    if (props->read) {
 | 
				
			||||||
        memread(ptr, buffer, bufsize);
 | 
					        memread(ptr, buffer, bufsize);
 | 
				
			||||||
 | 
				
			|||||||
@ -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 ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
 | 
				
			||||||
unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
 | 
					unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
 | 
				
			||||||
void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
 | 
					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 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 */
 | 
					/* Command Lifecycle */
 | 
				
			||||||
AHCICommand *ahci_command_create(uint8_t command_name);
 | 
					AHCICommand *ahci_command_create(uint8_t command_name);
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,11 @@ static QOSOps qos_ops = {
 | 
				
			|||||||
    .uninit_allocator = pc_alloc_uninit
 | 
					    .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 *qtest_pc_boot(const char *cmdline_fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QOSState *qs;
 | 
					    QOSState *qs;
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "libqos/libqos.h"
 | 
					#include "libqos/libqos.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap);
 | 
				
			||||||
QOSState *qtest_pc_boot(const char *cmdline_fmt, ...);
 | 
					QOSState *qtest_pc_boot(const char *cmdline_fmt, ...);
 | 
				
			||||||
void qtest_pc_shutdown(QOSState *qs);
 | 
					void qtest_pc_shutdown(QOSState *qs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -61,3 +61,69 @@ void qtest_shutdown(QOSState *qs)
 | 
				
			|||||||
    qtest_quit(qs->qts);
 | 
					    qtest_quit(qs->qts);
 | 
				
			||||||
    g_free(qs);
 | 
					    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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,9 @@ typedef struct QOSState {
 | 
				
			|||||||
QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap);
 | 
					QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap);
 | 
				
			||||||
QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...);
 | 
					QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...);
 | 
				
			||||||
void qtest_shutdown(QOSState *qs);
 | 
					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)
 | 
					static inline uint64_t qmalloc(QOSState *q, size_t bytes)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
				
			|||||||
@ -388,7 +388,12 @@ QDict *qtest_qmp_receive(QTestState *s)
 | 
				
			|||||||
    return qmp.response;
 | 
					    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;
 | 
					    va_list ap_copy;
 | 
				
			||||||
    QObject *qobj;
 | 
					    QObject *qobj;
 | 
				
			||||||
@ -417,6 +422,11 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
 | 
				
			|||||||
        QDECREF(qstr);
 | 
					        QDECREF(qstr);
 | 
				
			||||||
        qobject_decref(qobj);
 | 
					        qobject_decref(qobj);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qtest_async_qmpv(s, fmt, ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Receive reply */
 | 
					    /* Receive reply */
 | 
				
			||||||
    return qtest_qmp_receive(s);
 | 
					    return qtest_qmp_receive(s);
 | 
				
			||||||
@ -433,6 +443,15 @@ QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
 | 
				
			|||||||
    return response;
 | 
					    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)
 | 
					void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    QDict *response = qtest_qmpv(s, fmt, ap);
 | 
					    QDict *response = qtest_qmpv(s, fmt, ap);
 | 
				
			||||||
@ -450,9 +469,26 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...)
 | 
				
			|||||||
    QDECREF(response);
 | 
					    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 *qtest_get_arch(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const char *qemu = getenv("QTEST_QEMU_BINARY");
 | 
					    const char *qemu = getenv("QTEST_QEMU_BINARY");
 | 
				
			||||||
 | 
					    g_assert(qemu != NULL);
 | 
				
			||||||
    const char *end = strrchr(qemu, '/');
 | 
					    const char *end = strrchr(qemu, '/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return end + strlen("/qemu-system-");
 | 
					    return end + strlen("/qemu-system-");
 | 
				
			||||||
@ -695,6 +731,15 @@ QDict *qmp(const char *fmt, ...)
 | 
				
			|||||||
    return response;
 | 
					    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, ...)
 | 
					void qmp_discard_response(const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    va_list ap;
 | 
					    va_list ap;
 | 
				
			||||||
 | 
				
			|||||||
@ -63,6 +63,15 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
QDict *qtest_qmp(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:
 | 
					 * qtest_qmpv_discard_response:
 | 
				
			||||||
 * @s: #QTestState instance to operate on.
 | 
					 * @s: #QTestState instance to operate on.
 | 
				
			||||||
@ -83,6 +92,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);
 | 
					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:
 | 
					 * qtest_receive:
 | 
				
			||||||
 * @s: #QTestState instance to operate on.
 | 
					 * @s: #QTestState instance to operate on.
 | 
				
			||||||
@ -91,6 +110,15 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
QDict *qtest_qmp_receive(QTestState *s);
 | 
					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:
 | 
					 * qtest_get_irq:
 | 
				
			||||||
 * @s: #QTestState instance to operate on.
 | 
					 * @s: #QTestState instance to operate on.
 | 
				
			||||||
@ -410,6 +438,14 @@ static inline void qtest_end(void)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
QDict *qmp(const char *fmt, ...);
 | 
					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:
 | 
					 * qmp_discard_response:
 | 
				
			||||||
 * @fmt...: QMP message to send to qemu
 | 
					 * @fmt...: QMP message to send to qemu
 | 
				
			||||||
@ -428,6 +464,17 @@ static inline QDict *qmp_receive(void)
 | 
				
			|||||||
    return qtest_qmp_receive(global_qtest);
 | 
					    return qtest_qmp_receive(global_qtest);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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:
 | 
					 * get_irq:
 | 
				
			||||||
 * @num: Interrupt to observe.
 | 
					 * @num: Interrupt to observe.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user