提交 a1fe58f6 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
...@@ -535,8 +535,6 @@ struct FDCtrl { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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] = { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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); ...@@ -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 = { ...@@ -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 @@ ...@@ -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) ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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, ...) ...@@ -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, ...) ...@@ -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, ...) ...@@ -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, ...); ...@@ -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); ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册