Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging

Pull request

# gpg: Signature made Fri 08 Jun 2018 18:46:24 BST
# gpg:                using RSA key 7DEF8106AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>"
# 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: (30 commits)
  ide: introduce ide_transfer_start_norecurse
  atapi: call ide_set_irq before ide_transfer_start
  ide: make ide_transfer_stop idempotent
  ide: call ide_cmd_done from ide_transfer_stop
  ide: push end_transfer_func out of start_transfer callback, rename callback
  ahci: move PIO Setup FIS before transfer, fix it for ATAPI commands
  libqos/ahci: track sector size
  MAINTAINERS: Add the cdrom-test to John's section
  tests/cdrom-test: Test that -cdrom parameter is working
  tests/cdrom-test: Test booting from CD-ROM ISO image file
  tests/boot-sector: Add magic bytes to s390x boot code header
  ahci: make ahci_mem_write traces more descriptive
  ahci: delete old host register address definitions
  ahci: adjust ahci_mem_write to work on registers
  ahci: fix spacing damage on ahci_mem_write
  ahci: make mem_read_32 traces more descriptive
  ahci: modify ahci_mem_read_32 to work on register numbers
  ahci: fix host register max address
  ahci: add host register enumeration
  ahci: delete old port register address definitions
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2018-06-11 11:12:46 +01:00
12 changed files with 572 additions and 244 deletions
+1
View File
@@ -1003,6 +1003,7 @@ F: hw/block/cdrom.c
F: hw/block/hd-geometry.c
F: tests/ide-test.c
F: tests/ahci-test.c
F: tests/cdrom-test.c
F: tests/libqos/ahci*
T: git git://github.com/jnsnow/qemu.git ide
+214 -155
View File
File diff suppressed because it is too large Load Diff
+41 -22
View File
@@ -55,11 +55,20 @@
#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
/* global controller registers */
#define HOST_CAP 0x00 /* host capabilities */
#define HOST_CTL 0x04 /* global host control */
#define HOST_IRQ_STAT 0x08 /* interrupt status */
#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
enum AHCIHostReg {
AHCI_HOST_REG_CAP = 0, /* CAP: host capabilities */
AHCI_HOST_REG_CTL = 1, /* GHC: global host control */
AHCI_HOST_REG_IRQ_STAT = 2, /* IS: interrupt status */
AHCI_HOST_REG_PORTS_IMPL = 3, /* PI: bitmap of implemented ports */
AHCI_HOST_REG_VERSION = 4, /* VS: AHCI spec. version compliancy */
AHCI_HOST_REG_CCC_CTL = 5, /* CCC_CTL: CCC Control */
AHCI_HOST_REG_CCC_PORTS = 6, /* CCC_PORTS: CCC Ports */
AHCI_HOST_REG_EM_LOC = 7, /* EM_LOC: Enclosure Mgmt Location */
AHCI_HOST_REG_EM_CTL = 8, /* EM_CTL: Enclosure Mgmt Control */
AHCI_HOST_REG_CAP2 = 9, /* CAP2: host capabilities, extended */
AHCI_HOST_REG_BOHC = 10, /* BOHC: firmare/os handoff ctrl & status */
AHCI_HOST_REG__COUNT = 11
};
/* HOST_CTL bits */
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
@@ -75,21 +84,32 @@
#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
#define PORT_IRQ_STAT 0x10 /* interrupt status */
#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
#define PORT_CMD 0x18 /* port command */
#define PORT_TFDATA 0x20 /* taskfile data */
#define PORT_SIG 0x24 /* device TF signature */
#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
#define PORT_CMD_ISSUE 0x38 /* command issue */
#define PORT_RESERVED 0x3c /* reserved */
enum AHCIPortReg {
AHCI_PORT_REG_LST_ADDR = 0, /* PxCLB: command list DMA addr */
AHCI_PORT_REG_LST_ADDR_HI = 1, /* PxCLBU: command list DMA addr hi */
AHCI_PORT_REG_FIS_ADDR = 2, /* PxFB: FIS rx buf addr */
AHCI_PORT_REG_FIS_ADDR_HI = 3, /* PxFBU: FIX rx buf addr hi */
AHCI_PORT_REG_IRQ_STAT = 4, /* PxIS: interrupt status */
AHCI_PORT_REG_IRQ_MASK = 5, /* PxIE: interrupt enable/disable mask */
AHCI_PORT_REG_CMD = 6, /* PxCMD: port command */
/* RESERVED */
AHCI_PORT_REG_TFDATA = 8, /* PxTFD: taskfile data */
AHCI_PORT_REG_SIG = 9, /* PxSIG: device TF signature */
AHCI_PORT_REG_SCR_STAT = 10, /* PxSSTS: SATA phy register: SStatus */
AHCI_PORT_REG_SCR_CTL = 11, /* PxSCTL: SATA phy register: SControl */
AHCI_PORT_REG_SCR_ERR = 12, /* PxSERR: SATA phy register: SError */
AHCI_PORT_REG_SCR_ACT = 13, /* PxSACT: SATA phy register: SActive */
AHCI_PORT_REG_CMD_ISSUE = 14, /* PxCI: command issue */
AHCI_PORT_REG_SCR_NOTIF = 15, /* PxSNTF: SATA phy register: SNotification */
AHCI_PORT_REG_FIS_CTL = 16, /* PxFBS: Port multiplier switching ctl */
AHCI_PORT_REG_DEV_SLEEP = 17, /* PxDEVSLP: device sleep control */
/* RESERVED */
AHCI_PORT_REG_VENDOR_1 = 28, /* PxVS: Vendor Specific */
AHCI_PORT_REG_VENDOR_2 = 29,
AHCI_PORT_REG_VENDOR_3 = 30,
AHCI_PORT_REG_VENDOR_4 = 31,
AHCI_PORT_REG__COUNT = 32
};
/* Port interrupt bit descriptors */
enum AHCIPortIRQ {
@@ -198,8 +218,7 @@ enum AHCIPortIRQ {
#define SATA_SIGNATURE_CDROM 0xeb140101
#define SATA_SIGNATURE_DISK 0x00000101
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
/* Shouldn't this be 0x2c? */
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x2c
#define AHCI_PORT_REGS_START_ADDR 0x100
#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
+24 -20
View File
@@ -245,15 +245,11 @@ static uint16_t atapi_byte_count_limit(IDEState *s)
void ide_atapi_cmd_reply_end(IDEState *s)
{
int byte_count_limit, size, ret;
trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
s->elementary_transfer_size,
s->io_buffer_index);
if (s->packet_transfer_size <= 0) {
/* end of transfer */
ide_atapi_cmd_ok(s);
ide_set_irq(s->bus);
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
} else {
while (s->packet_transfer_size > 0) {
trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
s->elementary_transfer_size,
s->io_buffer_index);
/* see if a new sector must be read */
if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
if (!s->elementary_transfer_size) {
@@ -279,14 +275,10 @@ void ide_atapi_cmd_reply_end(IDEState *s)
size = s->cd_sector_size - s->io_buffer_index;
if (size > s->elementary_transfer_size)
size = s->elementary_transfer_size;
s->packet_transfer_size -= size;
s->elementary_transfer_size -= size;
s->io_buffer_index += size;
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
size, ide_atapi_cmd_reply_end);
} else {
/* a new transfer is needed */
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
ide_set_irq(s->bus);
byte_count_limit = atapi_byte_count_limit(s);
trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit);
size = s->packet_transfer_size;
@@ -304,15 +296,27 @@ void ide_atapi_cmd_reply_end(IDEState *s)
if (size > (s->cd_sector_size - s->io_buffer_index))
size = (s->cd_sector_size - s->io_buffer_index);
}
s->packet_transfer_size -= size;
s->elementary_transfer_size -= size;
s->io_buffer_index += size;
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
size, ide_atapi_cmd_reply_end);
ide_set_irq(s->bus);
trace_ide_atapi_cmd_reply_end_new(s, s->status);
}
s->packet_transfer_size -= size;
s->elementary_transfer_size -= size;
s->io_buffer_index += size;
/* Some adapters process PIO data right away. In that case, we need
* to avoid mutual recursion between ide_transfer_start
* and ide_atapi_cmd_reply_end.
*/
if (!ide_transfer_start_norecurse(s,
s->io_buffer + s->io_buffer_index - size,
size, ide_atapi_cmd_reply_end)) {
return;
}
}
/* end of transfer */
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
ide_atapi_cmd_ok(s);
ide_set_irq(s->bus);
}
/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
+20 -19
View File
@@ -523,18 +523,28 @@ static void ide_clear_retry(IDEState *s)
}
/* prepare data transfer and tell what to do after */
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func)
bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func)
{
s->end_transfer_func = end_transfer_func;
s->data_ptr = buf;
s->data_end = buf + size;
ide_set_retry(s);
if (!(s->status & ERR_STAT)) {
s->status |= DRQ_STAT;
}
if (s->bus->dma->ops->start_transfer) {
s->bus->dma->ops->start_transfer(s->bus->dma);
if (!s->bus->dma->ops->pio_transfer) {
s->end_transfer_func = end_transfer_func;
return false;
}
s->bus->dma->ops->pio_transfer(s->bus->dma);
return true;
}
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func)
{
if (ide_transfer_start_norecurse(s, buf, size, end_transfer_func)) {
end_transfer_func(s);
}
}
@@ -545,27 +555,18 @@ static void ide_cmd_done(IDEState *s)
}
}
static void ide_transfer_halt(IDEState *s,
void(*end_transfer_func)(IDEState *),
bool notify)
static void ide_transfer_halt(IDEState *s)
{
s->end_transfer_func = end_transfer_func;
s->end_transfer_func = ide_transfer_stop;
s->data_ptr = s->io_buffer;
s->data_end = s->io_buffer;
s->status &= ~DRQ_STAT;
if (notify) {
ide_cmd_done(s);
}
}
void ide_transfer_stop(IDEState *s)
{
ide_transfer_halt(s, ide_transfer_stop, true);
}
static void ide_transfer_cancel(IDEState *s)
{
ide_transfer_halt(s, ide_transfer_cancel, false);
ide_transfer_halt(s);
ide_cmd_done(s);
}
int64_t ide_get_sector(IDEState *s)
@@ -1362,7 +1363,7 @@ static bool cmd_nop(IDEState *s, uint8_t cmd)
static bool cmd_device_reset(IDEState *s, uint8_t cmd)
{
/* Halt PIO (in the DRQ phase), then DMA */
ide_transfer_cancel(s);
ide_transfer_halt(s);
ide_cancel_dma_sync(s);
/* Reset any PIO commands, reset signature, etc */
+11 -4
View File
@@ -63,16 +63,23 @@ ide_atapi_cmd_read_dma_cb_aio(void *s, int lba, int n) "IDEState: %p; aio read:
ide_atapi_cmd_packet(void *s, uint16_t limit, const char *packet) "IDEState: %p; limit=0x%x packet: %s"
# hw/ide/ahci.c
ahci_port_read(void *s, int port, int offset, uint32_t ret) "ahci(%p)[%d]: port read @ 0x%x: 0x%08x"
ahci_port_read(void *s, int port, const char *reg, int offset, uint32_t ret) "ahci(%p)[%d]: port read [reg:%s] @ 0x%x: 0x%08x"
ahci_port_read_default(void *s, int port, const char *reg, int offset) "ahci(%p)[%d]: unimplemented port read [reg:%s] @ 0x%x"
ahci_irq_raise(void *s) "ahci(%p): raise irq"
ahci_irq_lower(void *s) "ahci(%p): lower irq"
ahci_check_irq(void *s, uint32_t old, uint32_t new) "ahci(%p): check irq 0x%08x --> 0x%08x"
ahci_trigger_irq(void *s, int port, const char *name, uint32_t val, uint32_t old, uint32_t new, uint32_t effective) "ahci(%p)[%d]: trigger irq +%s (0x%08x); irqstat: 0x%08x --> 0x%08x; effective: 0x%08x"
ahci_port_write(void *s, int port, int offset, uint32_t val) "ahci(%p)[%d]: port write @ 0x%x: 0x%08x"
ahci_port_write(void *s, int port, const char *reg, int offset, uint32_t val) "ahci(%p)[%d]: port write [reg:%s] @ 0x%x: 0x%08x"
ahci_port_write_unimpl(void *s, int port, const char *reg, int offset, uint32_t val) "ahci(%p)[%d]: unimplemented port write [reg:%s] @ 0x%x: 0x%08x"
ahci_mem_read_32(void *s, uint64_t addr, uint32_t val) "ahci(%p): mem read @ 0x%"PRIx64": 0x%08x"
ahci_mem_read_32_default(void *s, uint64_t addr, uint32_t val) "ahci(%p): mem read @ 0x%"PRIx64": 0x%08x"
ahci_mem_read_32_host(void *s, const char *reg, uint64_t addr, uint32_t val) "ahci(%p): mem read [reg:%s] @ 0x%"PRIx64": 0x%08x"
ahci_mem_read_32_host_default(void *s, const char *reg, uint64_t addr) "ahci(%p): unimplemented mem read [reg:%s] @ 0x%"PRIx64
ahci_mem_read(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): read%u @ 0x%"PRIx64": 0x%016"PRIx64
ahci_mem_write(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u @ 0x%"PRIx64": 0x%016"PRIx64
ahci_mem_write_unknown(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64
ahci_mem_write_host_unimpl(void *s, unsigned size, const char *reg, uint64_t addr) "ahci(%p) unimplemented write%u [reg:%s] @ 0x%"PRIx64
ahci_mem_write_host(void *s, unsigned size, const char *reg, uint64_t addr, uint64_t val) "ahci(%p) write%u [reg:%s] @ 0x%"PRIx64": 0x%016"PRIx64
ahci_mem_write_unimpl(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64
ahci_set_signature(void *s, int port, uint8_t nsector, uint8_t sector, uint8_t lcyl, uint8_t hcyl, uint32_t sig) "ahci(%p)[%d]: set signature sector:0x%02x nsector:0x%02x lcyl:0x%02x hcyl:0x%02x (cumulatively: 0x%08x)"
ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port"
ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL FIS address"
@@ -101,7 +108,7 @@ handle_cmd_badport(void *s, int port) "ahci(%p)[%d]: guest accessed unused port"
handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cmd FIS"
handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80"
handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x"
ahci_start_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist"
ahci_pio_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist"
ahci_start_dma(void *s, int port) "ahci(%p)[%d]: start dma"
ahci_dma_prepare_buf(void *s, int port, int32_t io_buffer_size, int32_t limit) "ahci(%p)[%d]: prepare buf limit=%"PRId32" prepared=%"PRId32
ahci_dma_prepare_buf_fail(void *s, int port) "ahci(%p)[%d]: sglist population failed"
+3 -1
View File
@@ -444,7 +444,7 @@ struct IDEState {
struct IDEDMAOps {
DMAStartFunc *start_dma;
DMAVoidFunc *start_transfer;
DMAVoidFunc *pio_transfer;
DMAInt32Func *prepare_buf;
DMAu32Func *commit_buf;
DMAIntFunc *rw_buf;
@@ -623,6 +623,8 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val);
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
void ide_transfer_stop(IDEState *s);
void ide_set_inactive(IDEState *s, bool more);
BlockAIOCB *ide_issue_trim(
+2
View File
@@ -179,6 +179,7 @@ check-qtest-generic-y = tests/qmp-test$(EXESUF)
gcov-files-generic-y = monitor.c qapi/qmp-dispatch.c
check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
gcov-files-generic-y = qdev-monitor.c qmp.c
check-qtest-generic-y += tests/cdrom-test$(EXESUF)
gcov-files-ipack-y += hw/ipack/ipack.c
check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
@@ -844,6 +845,7 @@ tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)
tests/numa-test$(EXESUF): tests/numa-test.o
tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y)
tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
tests/migration/stress$(EXESUF): tests/migration/stress.o
$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
+6 -3
View File
@@ -68,8 +68,11 @@ static uint8_t x86_boot_sector[512] = {
};
/* For s390x, use a mini "kernel" with the appropriate signature */
static const uint8_t s390x_psw[] = {
0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00
static const uint8_t s390x_psw_and_magic[] = {
0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, /* Program status word */
0x02, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x50, /* Magic: */
0x02, 0x00, 0x00, 0x68, 0x60, 0x00, 0x00, 0x50, /* see linux_s390_magic */
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* in the s390-ccw bios */
};
static const uint8_t s390x_code[] = {
0xa7, 0xf4, 0x00, 0x0a, /* j 0x10010 */
@@ -110,7 +113,7 @@ int boot_sector_init(char *fname)
} else if (g_str_equal(arch, "s390x")) {
len = 0x10000 + sizeof(s390x_code);
boot_code = g_malloc0(len);
memcpy(boot_code, s390x_psw, sizeof(s390x_psw));
memcpy(boot_code, s390x_psw_and_magic, sizeof(s390x_psw_and_magic));
memcpy(&boot_code[0x10000], s390x_code, sizeof(s390x_code));
} else {
g_assert_not_reached();
+222
View File
@@ -0,0 +1,222 @@
/*
* Various tests for emulated CD-ROM drives.
*
* Copyright (c) 2018 Red Hat Inc.
*
* Author:
* Thomas Huth <thuth@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2
* or later. See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "libqtest.h"
#include "boot-sector.h"
#include "qapi/qmp/qdict.h"
static char isoimage[] = "cdrom-boot-iso-XXXXXX";
static int exec_genisoimg(const char **args)
{
gchar *out_err = NULL;
gint exit_status = -1;
bool success;
success = g_spawn_sync(NULL, (gchar **)args, NULL,
G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
NULL, NULL, NULL, &out_err, &exit_status, NULL);
if (!success) {
return -ENOENT;
}
if (out_err) {
fputs(out_err, stderr);
g_free(out_err);
}
return exit_status;
}
static int prepare_image(const char *arch, char *isoimage)
{
char srcdir[] = "cdrom-test-dir-XXXXXX";
char *codefile = NULL;
int ifh, ret = -1;
const char *args[] = {
"genisoimage", "-quiet", "-l", "-no-emul-boot",
"-b", NULL, "-o", isoimage, srcdir, NULL
};
ifh = mkstemp(isoimage);
if (ifh < 0) {
perror("Error creating temporary iso image file");
return -1;
}
if (!mkdtemp(srcdir)) {
perror("Error creating temporary directory");
goto cleanup;
}
if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
g_str_equal(arch, "s390x")) {
codefile = g_strdup_printf("%s/bootcode-XXXXXX", srcdir);
ret = boot_sector_init(codefile);
if (ret) {
goto cleanup;
}
} else {
/* Just create a dummy file */
char txt[] = "empty disc";
codefile = g_strdup_printf("%s/readme.txt", srcdir);
if (!g_file_set_contents(codefile, txt, sizeof(txt) - 1, NULL)) {
fprintf(stderr, "Failed to create '%s'\n", codefile);
goto cleanup;
}
}
args[5] = strchr(codefile, '/') + 1;
ret = exec_genisoimg(args);
if (ret) {
fprintf(stderr, "genisoimage failed: %i\n", ret);
}
unlink(codefile);
cleanup:
g_free(codefile);
rmdir(srcdir);
close(ifh);
return ret;
}
/**
* Check that at least the -cdrom parameter is basically working, i.e. we can
* see the filename of the ISO image in the output of "info block" afterwards
*/
static void test_cdrom_param(gconstpointer data)
{
QTestState *qts;
char *resp;
qts = qtest_startf("-M %s -cdrom %s", (const char *)data, isoimage);
resp = qtest_hmp(qts, "info block");
g_assert(strstr(resp, isoimage) != 0);
g_free(resp);
qtest_quit(qts);
}
static void add_cdrom_param_tests(const char **machines)
{
while (*machines) {
char *testname = g_strdup_printf("cdrom/param/%s", *machines);
qtest_add_data_func(testname, *machines, test_cdrom_param);
g_free(testname);
machines++;
}
}
static void test_cdboot(gconstpointer data)
{
QTestState *qts;
qts = qtest_startf("-accel kvm:tcg -no-shutdown %s%s", (const char *)data,
isoimage);
boot_sector_test(qts);
qtest_quit(qts);
}
static void add_x86_tests(void)
{
qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
qtest_add_data_func("cdrom/boot/virtio-scsi",
"-device virtio-scsi -device scsi-cd,drive=cdr "
"-blockdev file,node-name=cdr,filename=", test_cdboot);
qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
"-drive if=ide,media=cdrom,file=", test_cdboot);
qtest_add_data_func("cdrom/boot/am53c974",
"-device am53c974 -device scsi-cd,drive=cd1 "
"-drive if=none,id=cd1,format=raw,file=", test_cdboot);
qtest_add_data_func("cdrom/boot/dc390",
"-device dc390 -device scsi-cd,drive=cd1 "
"-blockdev file,node-name=cd1,filename=", test_cdboot);
qtest_add_data_func("cdrom/boot/lsi53c895a",
"-device lsi53c895a -device scsi-cd,drive=cd1 "
"-blockdev file,node-name=cd1,filename=", test_cdboot);
qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
"-device megasas -device scsi-cd,drive=cd1 "
"-blockdev file,node-name=cd1,filename=", test_cdboot);
qtest_add_data_func("cdrom/boot/megasas-gen2", "-M q35 "
"-device megasas-gen2 -device scsi-cd,drive=cd1 "
"-blockdev file,node-name=cd1,filename=", test_cdboot);
}
static void add_s390x_tests(void)
{
qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
qtest_add_data_func("cdrom/boot/virtio-scsi",
"-device virtio-scsi -device scsi-cd,drive=cdr "
"-blockdev file,node-name=cdr,filename=", test_cdboot);
}
int main(int argc, char **argv)
{
int ret;
const char *arch = qtest_get_arch();
const char *genisocheck[] = { "genisoimage", "-version", NULL };
g_test_init(&argc, &argv, NULL);
if (exec_genisoimg(genisocheck)) {
/* genisoimage not available - so can't run tests */
return 0;
}
ret = prepare_image(arch, isoimage);
if (ret) {
return ret;
}
if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) {
add_x86_tests();
} else if (g_str_equal(arch, "s390x")) {
add_s390x_tests();
} else if (g_str_equal(arch, "ppc64")) {
const char *ppcmachines[] = {
"pseries", "mac99", "g3beige", "40p", "prep", NULL
};
add_cdrom_param_tests(ppcmachines);
} else if (g_str_equal(arch, "sparc")) {
const char *sparcmachines[] = {
"LX", "SPARCClassic", "SPARCbook", "SS-10", "SS-20", "SS-4",
"SS-5", "SS-600MP", "Voyager", "leon3_generic", NULL
};
add_cdrom_param_tests(sparcmachines);
} else if (g_str_equal(arch, "sparc64")) {
const char *sparc64machines[] = {
"niagara", "sun4u", "sun4v", NULL
};
add_cdrom_param_tests(sparc64machines);
} else if (!strncmp(arch, "mips64", 6)) {
const char *mips64machines[] = {
"magnum", "malta", "mips", "pica61", NULL
};
add_cdrom_param_tests(mips64machines);
} else if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
const char *armmachines[] = {
"realview-eb", "realview-eb-mpcore", "realview-pb-a8",
"realview-pbx-a9", "versatileab", "versatilepb", "vexpress-a15",
"vexpress-a9", "virt", NULL
};
add_cdrom_param_tests(armmachines);
} else {
const char *nonemachine[] = { "none", NULL };
add_cdrom_param_tests(nonemachine);
}
ret = g_test_run();
unlink(isoimage);
return ret;
}
+27 -18
View File
@@ -90,6 +90,7 @@ struct AHCICommand {
uint32_t interrupts;
uint64_t xbytes;
uint32_t prd_size;
uint32_t sector_size;
uint64_t buffer;
AHCICommandProp *props;
/* Data to be transferred to the guest */
@@ -477,10 +478,10 @@ void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot)
g_free(d2h);
}
void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
uint8_t slot, size_t buffsize)
void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd)
{
PIOSetupFIS *pio = g_malloc0(0x20);
uint8_t port = cmd->port;
/* We cannot check the Status or E_Status registers, because
* the status may have again changed between the PIO Setup FIS
@@ -488,15 +489,22 @@ void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x20, pio, 0x20);
g_assert_cmphex(pio->fis_type, ==, 0x5f);
/* BUG: PIO Setup FIS as utilized by QEMU tries to fit the entire
* transfer size in a uint16_t field. The maximum transfer size can
* eclipse this; the field is meant to convey the size of data per
* each Data FIS, not the entire operation as a whole. For now,
* we will sanity check the broken case where applicable. */
if (buffsize <= UINT16_MAX) {
g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, buffsize);
/* Data transferred by PIO will either be:
* (1) 12 or 16 bytes for an ATAPI command packet (QEMU always uses 12), or
* (2) Actual data from the drive.
* If we do both, (2) winds up erasing any evidence of (1).
*/
if (cmd->props->atapi && (cmd->xbytes == 0 || cmd->props->dma)) {
g_assert(le16_to_cpu(pio->tx_count) == 12 ||
le16_to_cpu(pio->tx_count) == 16);
} else {
/* The AHCI test suite here does not test any PIO command that specifies
* a DRQ block larger than one sector (like 0xC4), so this should always
* be one sector or less. */
size_t pio_len = ((cmd->xbytes % cmd->sector_size) ?
(cmd->xbytes % cmd->sector_size) : cmd->sector_size);
g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, pio_len);
}
g_free(pio);
}
@@ -796,7 +804,7 @@ static void command_header_init(AHCICommand *cmd)
static void command_table_init(AHCICommand *cmd)
{
RegH2DFIS *fis = &(cmd->fis);
uint16_t sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
uint16_t sect_count = (cmd->xbytes / cmd->sector_size);
fis->fis_type = REG_H2D_FIS;
fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
@@ -819,7 +827,7 @@ static void command_table_init(AHCICommand *cmd)
if (cmd->props->lba28 || cmd->props->lba48) {
fis->device = ATA_DEVICE_LBA;
}
fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE);
fis->count = (cmd->xbytes / cmd->sector_size);
}
fis->icc = 0x00;
fis->control = 0x00;
@@ -831,9 +839,9 @@ void ahci_command_enable_atapi_dma(AHCICommand *cmd)
RegH2DFIS *fis = &(cmd->fis);
g_assert(cmd->props->atapi);
fis->feature_low |= 0x01;
cmd->interrupts &= ~AHCI_PX_IS_PSS;
/* PIO is still used to transfer the ATAPI command */
g_assert(cmd->props->pio);
cmd->props->dma = true;
cmd->props->pio = false;
/* BUG: We expect the DMA Setup interrupt for DMA commands */
/* cmd->interrupts |= AHCI_PX_IS_DSS; */
}
@@ -845,7 +853,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
g_assert(props);
cmd = g_new0(AHCICommand, 1);
g_assert(!(props->dma && props->pio));
g_assert(!(props->dma && props->pio) || props->atapi);
g_assert(!(props->lba28 && props->lba48));
g_assert(!(props->read && props->write));
g_assert(!props->size || props->data);
@@ -857,6 +865,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
cmd->xbytes = props->size;
cmd->prd_size = 4096;
cmd->buffer = 0xabad1dea;
cmd->sector_size = props->atapi ? ATAPI_SECTOR_SIZE : AHCI_SECTOR_SIZE;
if (!cmd->props->ncq) {
cmd->interrupts = AHCI_PX_IS_DHRS;
@@ -1033,7 +1042,7 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes)
{
unsigned char *cbd = cmd->atapi_cmd;
uint64_t nsectors = xbytes / 2048;
uint64_t nsectors = xbytes / ATAPI_SECTOR_SIZE;
uint32_t tmp;
g_assert(cbd);
@@ -1080,7 +1089,7 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
cmd->prd_size = prd_size;
}
cmd->xbytes = xbytes;
sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
sect_count = (cmd->xbytes / cmd->sector_size);
if (cmd->props->ncq) {
NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
@@ -1216,7 +1225,7 @@ void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd)
ahci_port_check_d2h_sanity(ahci, port, slot);
}
if (cmd->props->pio) {
ahci_port_check_pio_sanity(ahci, port, slot, cmd->xbytes);
ahci_port_check_pio_sanity(ahci, cmd);
}
}
+1 -2
View File
@@ -596,8 +596,7 @@ void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
uint32_t intr_mask);
void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot);
void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot);
void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
uint8_t slot, size_t buffsize);
void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd);
void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd);
/* Misc */