summaryrefslogtreecommitdiffstats
path: root/qemu/tests/libqos
diff options
context:
space:
mode:
authorDon Dugger <n0ano@n0ano.com>2016-06-03 03:33:22 +0000
committerGerrit Code Review <gerrit@172.30.200.206>2016-06-03 03:33:23 +0000
commitda27230f80795d0028333713f036d44c53cb0e68 (patch)
treeb3d379eaf000adf72b36cb01cdf4d79c3e3f064c /qemu/tests/libqos
parent0e68cb048bb8aadb14675f5d4286d8ab2fc35449 (diff)
parent437fd90c0250dee670290f9b714253671a990160 (diff)
Merge "These changes are the raw update to qemu-2.6."
Diffstat (limited to 'qemu/tests/libqos')
-rw-r--r--qemu/tests/libqos/ahci.c180
-rw-r--r--qemu/tests/libqos/ahci.h69
-rw-r--r--qemu/tests/libqos/fw_cfg.c1
-rw-r--r--qemu/tests/libqos/fw_cfg.h2
-rw-r--r--qemu/tests/libqos/i2c-imx.c208
-rw-r--r--qemu/tests/libqos/i2c-omap.c3
-rw-r--r--qemu/tests/libqos/i2c.c1
-rw-r--r--qemu/tests/libqos/i2c.h4
-rw-r--r--qemu/tests/libqos/libqos-pc.c1
-rw-r--r--qemu/tests/libqos/libqos.c60
-rw-r--r--qemu/tests/libqos/libqos.h2
-rw-r--r--qemu/tests/libqos/malloc-generic.c1
-rw-r--r--qemu/tests/libqos/malloc-pc.c4
-rw-r--r--qemu/tests/libqos/malloc.c7
-rw-r--r--qemu/tests/libqos/malloc.h2
-rw-r--r--qemu/tests/libqos/pci-pc.c9
-rw-r--r--qemu/tests/libqos/pci.c3
-rw-r--r--qemu/tests/libqos/pci.h1
-rw-r--r--qemu/tests/libqos/usb.c3
-rw-r--r--qemu/tests/libqos/virtio-mmio.c2
-rw-r--r--qemu/tests/libqos/virtio-pci.c2
-rw-r--r--qemu/tests/libqos/virtio.c1
22 files changed, 515 insertions, 51 deletions
diff --git a/qemu/tests/libqos/ahci.c b/qemu/tests/libqos/ahci.c
index cf66b3e32..ac6c155c8 100644
--- a/qemu/tests/libqos/ahci.c
+++ b/qemu/tests/libqos/ahci.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
@@ -74,7 +75,11 @@ AHCICommandProp ahci_command_properties[] = {
.lba48 = true, .write = true, .ncq = true },
{ .cmd = CMD_READ_MAX, .lba28 = true },
{ .cmd = CMD_READ_MAX_EXT, .lba48 = true },
- { .cmd = CMD_FLUSH_CACHE, .data = false }
+ { .cmd = CMD_FLUSH_CACHE, .data = false },
+ { .cmd = CMD_PACKET, .data = true, .size = 16,
+ .atapi = true, .pio = true },
+ { .cmd = CMD_PACKET_ID, .data = true, .pio = true,
+ .size = 512, .read = true }
};
struct AHCICommand {
@@ -90,7 +95,7 @@ struct AHCICommand {
/* Data to be transferred to the guest */
AHCICommandHeader header;
RegH2DFIS fis;
- void *atapi_cmd;
+ unsigned char *atapi_cmd;
};
/**
@@ -110,6 +115,11 @@ void ahci_free(AHCIQState *ahci, uint64_t addr)
qfree(ahci->parent, addr);
}
+bool is_atapi(AHCIQState *ahci, uint8_t port)
+{
+ return ahci_px_rreg(ahci, port, AHCI_PX_SIG) == AHCI_SIGNATURE_CDROM;
+}
+
/**
* Locate, verify, and return a handle to the AHCI device.
*/
@@ -592,6 +602,82 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
return (bytes + bytes_per_prd - 1) / bytes_per_prd;
}
+const AHCIOpts default_opts = { .size = 0 };
+
+/**
+ * ahci_exec: execute a given command on a specific
+ * AHCI port.
+ *
+ * @ahci: The device to send the command to
+ * @port: The port number of the SATA device we wish
+ * to have execute this command
+ * @op: The S/ATA command to execute, or if opts.atapi
+ * is true, the SCSI command code.
+ * @opts: Optional arguments to modify execution behavior.
+ */
+void ahci_exec(AHCIQState *ahci, uint8_t port,
+ uint8_t op, const AHCIOpts *opts_in)
+{
+ AHCICommand *cmd;
+ int rc;
+ AHCIOpts *opts;
+
+ opts = g_memdup((opts_in == NULL ? &default_opts : opts_in),
+ sizeof(AHCIOpts));
+
+ /* No guest buffer provided, create one. */
+ if (opts->size && !opts->buffer) {
+ opts->buffer = ahci_alloc(ahci, opts->size);
+ g_assert(opts->buffer);
+ qmemset(opts->buffer, 0x00, opts->size);
+ }
+
+ /* Command creation */
+ if (opts->atapi) {
+ cmd = ahci_atapi_command_create(op);
+ if (opts->atapi_dma) {
+ ahci_command_enable_atapi_dma(cmd);
+ }
+ } else {
+ cmd = ahci_command_create(op);
+ }
+ ahci_command_adjust(cmd, opts->lba, opts->buffer,
+ opts->size, opts->prd_size);
+
+ if (opts->pre_cb) {
+ rc = opts->pre_cb(ahci, cmd, opts);
+ g_assert_cmpint(rc, ==, 0);
+ }
+
+ /* Write command to memory and issue it */
+ ahci_command_commit(ahci, cmd, port);
+ ahci_command_issue_async(ahci, cmd);
+ if (opts->error) {
+ qmp_eventwait("STOP");
+ }
+ if (opts->mid_cb) {
+ rc = opts->mid_cb(ahci, cmd, opts);
+ g_assert_cmpint(rc, ==, 0);
+ }
+ if (opts->error) {
+ qmp_async("{'execute':'cont' }");
+ qmp_eventwait("RESUME");
+ }
+
+ /* Wait for command to complete and verify sanity */
+ ahci_command_wait(ahci, cmd);
+ ahci_command_verify(ahci, cmd);
+ if (opts->post_cb) {
+ rc = opts->post_cb(ahci, cmd, opts);
+ g_assert_cmpint(rc, ==, 0);
+ }
+ ahci_command_free(cmd);
+ if (opts->buffer != opts_in->buffer) {
+ ahci_free(ahci, opts->buffer);
+ }
+ g_free(opts);
+}
+
/* Issue a command, expecting it to fail and STOP the VM */
AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port,
uint8_t ide_cmd, uint64_t buffer,
@@ -659,16 +745,16 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
props = ahci_command_find(ide_cmd);
g_assert(props);
ptr = ahci_alloc(ahci, bufsize);
- g_assert(ptr);
+ g_assert(!bufsize || ptr);
qmemset(ptr, 0x00, bufsize);
- if (props->write) {
+ if (bufsize && props->write) {
bufwrite(ptr, buffer, bufsize);
}
ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector);
- if (props->read) {
+ if (bufsize && props->read) {
bufread(ptr, buffer, bufsize);
}
@@ -731,6 +817,18 @@ static void command_table_init(AHCICommand *cmd)
memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux));
}
+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;
+ cmd->props->dma = true;
+ cmd->props->pio = false;
+ /* BUG: We expect the DMA Setup interrupt for DMA commands */
+ /* cmd->interrupts |= AHCI_PX_IS_DSS; */
+}
+
AHCICommand *ahci_command_create(uint8_t command_name)
{
AHCICommandProp *props = ahci_command_find(command_name);
@@ -742,10 +840,10 @@ AHCICommand *ahci_command_create(uint8_t command_name)
g_assert(!(props->lba28 && props->lba48));
g_assert(!(props->read && props->write));
g_assert(!props->size || props->data);
- g_assert(!props->ncq || (props->ncq && props->lba48));
+ g_assert(!props->ncq || props->lba48);
/* Defaults and book-keeping */
- cmd->props = props;
+ cmd->props = g_memdup(props, sizeof(AHCICommandProp));
cmd->name = command_name;
cmd->xbytes = props->size;
cmd->prd_size = 4096;
@@ -767,8 +865,23 @@ AHCICommand *ahci_command_create(uint8_t command_name)
return cmd;
}
+AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd)
+{
+ AHCICommand *cmd = ahci_command_create(CMD_PACKET);
+ cmd->atapi_cmd = g_malloc0(16);
+ cmd->atapi_cmd[0] = scsi_cmd;
+ /* ATAPI needs a PIO transfer chunk size set inside of the LBA registers.
+ * The block/sector size is a natural default. */
+ cmd->fis.lba_lo[1] = ATAPI_SECTOR_SIZE >> 8 & 0xFF;
+ cmd->fis.lba_lo[2] = ATAPI_SECTOR_SIZE & 0xFF;
+
+ return cmd;
+}
+
void ahci_command_free(AHCICommand *cmd)
{
+ g_free(cmd->atapi_cmd);
+ g_free(cmd->props);
g_free(cmd);
}
@@ -782,10 +895,34 @@ void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags)
cmd->header.flags &= ~cmdh_flags;
}
+static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba)
+{
+ unsigned char *cbd = cmd->atapi_cmd;
+ g_assert(cbd);
+
+ switch (cbd[0]) {
+ case CMD_ATAPI_READ_10:
+ g_assert_cmpuint(lba, <=, UINT32_MAX);
+ stl_be_p(&cbd[2], lba);
+ break;
+ default:
+ /* SCSI doesn't have uniform packet formats,
+ * so you have to add support for it manually. Sorry! */
+ g_assert_not_reached();
+ }
+}
+
void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect)
{
RegH2DFIS *fis = &(cmd->fis);
- if (cmd->props->lba28) {
+
+ if (cmd->props->atapi) {
+ ahci_atapi_command_set_offset(cmd, lba_sect);
+ return;
+ } else if (!cmd->props->data && !lba_sect) {
+ /* Not meaningful, ignore. */
+ return;
+ } else if (cmd->props->lba28) {
g_assert_cmphex(lba_sect, <=, 0xFFFFFFF);
} else if (cmd->props->lba48 || cmd->props->ncq) {
g_assert_cmphex(lba_sect, <=, 0xFFFFFFFFFFFF);
@@ -811,6 +948,24 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
cmd->buffer = buffer;
}
+static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes)
+{
+ unsigned char *cbd = cmd->atapi_cmd;
+ uint64_t nsectors = xbytes / 2048;
+ g_assert(cbd);
+
+ switch (cbd[0]) {
+ case CMD_ATAPI_READ_10:
+ g_assert_cmpuint(nsectors, <=, UINT16_MAX);
+ stw_be_p(&cbd[7], nsectors);
+ break;
+ default:
+ /* SCSI doesn't have uniform packet formats,
+ * so you have to add support for it manually. Sorry! */
+ g_assert_not_reached();
+ }
+}
+
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
unsigned prd_size)
{
@@ -829,6 +984,8 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
nfis->sector_low = sect_count & 0xFF;
nfis->sector_hi = (sect_count >> 8) & 0xFF;
+ } else if (cmd->props->atapi) {
+ ahci_atapi_set_size(cmd, xbytes);
} else {
cmd->fis.count = sect_count;
}
@@ -877,9 +1034,14 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
g_assert((table_ptr & 0x7F) == 0x00);
cmd->header.ctba = table_ptr;
- /* Commit the command header and command FIS */
+ /* Commit the command header (part of the Command List Buffer) */
ahci_set_command_header(ahci, port, cmd->slot, &(cmd->header));
+ /* Now, write the command table (FIS, ACMD, and PRDT) -- FIS first, */
ahci_write_fis(ahci, cmd);
+ /* Then ATAPI CMD, if needed */
+ if (cmd->props->atapi) {
+ memwrite(table_ptr + 0x40, cmd->atapi_cmd, 16);
+ }
/* Construct and write the PRDs to the command table */
g_assert_cmphex(prdtl, ==, cmd->header.prdtl);
diff --git a/qemu/tests/libqos/ahci.h b/qemu/tests/libqos/ahci.h
index cffc2c351..71dd7a6e5 100644
--- a/qemu/tests/libqos/ahci.h
+++ b/qemu/tests/libqos/ahci.h
@@ -25,9 +25,6 @@
* THE SOFTWARE.
*/
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
#include "libqos/libqos.h"
#include "libqos/pci.h"
#include "libqos/malloc-pc.h"
@@ -244,6 +241,10 @@
#define AHCI_VERSION_1_3 (0x00010300)
#define AHCI_SECTOR_SIZE (512)
+#define ATAPI_SECTOR_SIZE (2048)
+
+#define AHCI_SIGNATURE_CDROM (0xeb140101)
+#define AHCI_SIGNATURE_DISK (0x00000101)
/* FIS types */
enum {
@@ -277,11 +278,18 @@ enum {
CMD_READ_MAX_EXT = 0x27,
CMD_FLUSH_CACHE = 0xE7,
CMD_IDENTIFY = 0xEC,
+ CMD_PACKET = 0xA0,
+ CMD_PACKET_ID = 0xA1,
/* NCQ */
READ_FPDMA_QUEUED = 0x60,
WRITE_FPDMA_QUEUED = 0x61,
};
+/* ATAPI Commands */
+enum {
+ CMD_ATAPI_READ_10 = 0x28,
+};
+
/* AHCI Command Header Flags & Masks*/
#define CMDH_CFL (0x1F)
#define CMDH_ATAPI (0x20)
@@ -451,6 +459,21 @@ typedef struct PRD {
/* Opaque, defined within ahci.c */
typedef struct AHCICommand AHCICommand;
+/* Options to ahci_exec */
+typedef struct AHCIOpts {
+ size_t size;
+ unsigned prd_size;
+ uint64_t lba;
+ uint64_t buffer;
+ bool atapi;
+ bool atapi_dma;
+ bool error;
+ int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
+ int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
+ int (*post_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *);
+ void *opaque;
+} AHCIOpts;
+
/*** Macro Utilities ***/
#define BITANY(data, mask) (((data) & (mask)) != 0)
#define BITSET(data, mask) (((data) & (mask)) == (mask))
@@ -527,14 +550,28 @@ static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port,
/*** Prototypes ***/
uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes);
void ahci_free(AHCIQState *ahci, uint64_t addr);
+void ahci_clean_mem(AHCIQState *ahci);
+
+/* Device management */
QPCIDevice *get_ahci_device(uint32_t *fingerprint);
void free_ahci_device(QPCIDevice *dev);
-void ahci_clean_mem(AHCIQState *ahci);
void ahci_pci_enable(AHCIQState *ahci);
void start_ahci_device(AHCIQState *ahci);
void ahci_hba_enable(AHCIQState *ahci);
+
+/* Port Management */
unsigned ahci_port_select(AHCIQState *ahci);
void ahci_port_clear(AHCIQState *ahci, uint8_t port);
+
+/* Command header / table management */
+unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
+void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
+ uint8_t slot, AHCICommandHeader *cmd);
+void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
+ uint8_t slot, AHCICommandHeader *cmd);
+void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
+
+/* AHCI sanity check routines */
void ahci_port_check_error(AHCIQState *ahci, uint8_t port);
void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
uint32_t intr_mask);
@@ -543,14 +580,12 @@ 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_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd);
-void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
- uint8_t slot, AHCICommandHeader *cmd);
-void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
- uint8_t slot, AHCICommandHeader *cmd);
-void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
-void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd);
-unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
+
+/* Misc */
+bool is_atapi(AHCIQState *ahci, uint8_t port);
unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
+
+/* Command: Macro level execution */
void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
uint64_t gbuffer, size_t size, uint64_t sector);
AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
@@ -558,9 +593,12 @@ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd);
void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
void *buffer, size_t bufsize, uint64_t sector);
+void ahci_exec(AHCIQState *ahci, uint8_t port,
+ uint8_t op, const AHCIOpts *opts);
-/* Command Lifecycle */
+/* Command: Fine-grained lifecycle */
AHCICommand *ahci_command_create(uint8_t command_name);
+AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd);
void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
@@ -568,7 +606,7 @@ void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_free(AHCICommand *cmd);
-/* Command adjustments */
+/* Command: adjustments */
void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags);
void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags);
void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect);
@@ -577,10 +615,13 @@ void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes);
void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size);
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
unsigned prd_size);
+void ahci_command_set_acmd(AHCICommand *cmd, void *acmd);
+void ahci_command_enable_atapi_dma(AHCICommand *cmd);
void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer,
uint64_t xbytes, unsigned prd_size);
-/* Command Misc */
+/* Command: Misc */
uint8_t ahci_command_slot(AHCICommand *cmd);
+void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd);
#endif
diff --git a/qemu/tests/libqos/fw_cfg.c b/qemu/tests/libqos/fw_cfg.c
index ef00fedf1..76894d575 100644
--- a/qemu/tests/libqos/fw_cfg.c
+++ b/qemu/tests/libqos/fw_cfg.c
@@ -12,6 +12,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqos/fw_cfg.h"
#include "libqtest.h"
diff --git a/qemu/tests/libqos/fw_cfg.h b/qemu/tests/libqos/fw_cfg.h
index 61b1548b4..e8371b231 100644
--- a/qemu/tests/libqos/fw_cfg.h
+++ b/qemu/tests/libqos/fw_cfg.h
@@ -13,8 +13,6 @@
#ifndef LIBQOS_FW_CFG_H
#define LIBQOS_FW_CFG_H
-#include <stdint.h>
-#include <sys/types.h>
typedef struct QFWCFG QFWCFG;
diff --git a/qemu/tests/libqos/i2c-imx.c b/qemu/tests/libqos/i2c-imx.c
new file mode 100644
index 000000000..51c3468f9
--- /dev/null
+++ b/qemu/tests/libqos/i2c-imx.c
@@ -0,0 +1,208 @@
+/*
+ * QTest i.MX I2C driver
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "libqos/i2c.h"
+
+#include <glib.h>
+
+#include "libqtest.h"
+
+#include "hw/i2c/imx_i2c.h"
+
+enum IMXI2CDirection {
+ IMX_I2C_READ,
+ IMX_I2C_WRITE,
+};
+
+typedef struct IMXI2C {
+ I2CAdapter parent;
+
+ uint64_t addr;
+} IMXI2C;
+
+
+static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
+ enum IMXI2CDirection direction)
+{
+ writeb(s->addr + I2DR_ADDR, (addr << 1) |
+ (direction == IMX_I2C_READ ? 1 : 0));
+}
+
+static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
+ const uint8_t *buf, uint16_t len)
+{
+ IMXI2C *s = (IMXI2C *)i2c;
+ uint8_t data;
+ uint8_t status;
+ uint16_t size = 0;
+
+ if (!len) {
+ return;
+ }
+
+ /* set the bus for write */
+ data = I2CR_IEN |
+ I2CR_IIEN |
+ I2CR_MSTA |
+ I2CR_MTX |
+ I2CR_TXAK;
+
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* set the slave address */
+ imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+ g_assert((status & I2SR_RXAK) == 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ while (size < len) {
+ /* check we are still busy */
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* write the data */
+ writeb(s->addr + I2DR_ADDR, buf[size]);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+ g_assert((status & I2SR_RXAK) == 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ size++;
+ }
+
+ /* release the bus */
+ data &= ~(I2CR_MSTA | I2CR_MTX);
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) == 0);
+}
+
+static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+ uint8_t *buf, uint16_t len)
+{
+ IMXI2C *s = (IMXI2C *)i2c;
+ uint8_t data;
+ uint8_t status;
+ uint16_t size = 0;
+
+ if (!len) {
+ return;
+ }
+
+ /* set the bus for write */
+ data = I2CR_IEN |
+ I2CR_IIEN |
+ I2CR_MSTA |
+ I2CR_MTX |
+ I2CR_TXAK;
+
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* set the slave address */
+ imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+ g_assert((status & I2SR_RXAK) == 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ /* set the bus for read */
+ data &= ~I2CR_MTX;
+ /* if only one byte don't ack */
+ if (len != 1) {
+ data &= ~I2CR_TXAK;
+ }
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* dummy read */
+ readb(s->addr + I2DR_ADDR);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ while (size < len) {
+ /* check we are still busy */
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ if (size == (len - 1)) {
+ /* stop the read transaction */
+ data &= ~(I2CR_MSTA | I2CR_MTX);
+ } else {
+ /* ack the data read */
+ data |= I2CR_TXAK;
+ }
+ writeb(s->addr + I2CR_ADDR, data);
+
+ /* read the data */
+ buf[size] = readb(s->addr + I2DR_ADDR);
+
+ if (size != (len - 1)) {
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ }
+
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ size++;
+ }
+
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) == 0);
+}
+
+I2CAdapter *imx_i2c_create(uint64_t addr)
+{
+ IMXI2C *s = g_malloc0(sizeof(*s));
+ I2CAdapter *i2c = (I2CAdapter *)s;
+
+ s->addr = addr;
+
+ i2c->send = imx_i2c_send;
+ i2c->recv = imx_i2c_recv;
+
+ return i2c;
+}
diff --git a/qemu/tests/libqos/i2c-omap.c b/qemu/tests/libqos/i2c-omap.c
index 3d4d45d84..2028f2f14 100644
--- a/qemu/tests/libqos/i2c-omap.c
+++ b/qemu/tests/libqos/i2c-omap.c
@@ -6,12 +6,11 @@
* 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 "libqos/i2c.h"
#include <glib.h>
-#include <string.h>
-#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "libqtest.h"
diff --git a/qemu/tests/libqos/i2c.c b/qemu/tests/libqos/i2c.c
index da7592f71..23bc2a3eb 100644
--- a/qemu/tests/libqos/i2c.c
+++ b/qemu/tests/libqos/i2c.c
@@ -6,6 +6,7 @@
* 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 "libqos/i2c.h"
#include "libqtest.h"
diff --git a/qemu/tests/libqos/i2c.h b/qemu/tests/libqos/i2c.h
index 1ce9af405..6e648f922 100644
--- a/qemu/tests/libqos/i2c.h
+++ b/qemu/tests/libqos/i2c.h
@@ -9,7 +9,6 @@
#ifndef LIBQOS_I2C_H
#define LIBQOS_I2C_H
-#include <stdint.h>
typedef struct I2CAdapter I2CAdapter;
struct I2CAdapter {
@@ -27,4 +26,7 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr,
/* libi2c-omap.c */
I2CAdapter *omap_i2c_create(uint64_t addr);
+/* libi2c-imx.c */
+I2CAdapter *imx_i2c_create(uint64_t addr);
+
#endif
diff --git a/qemu/tests/libqos/libqos-pc.c b/qemu/tests/libqos/libqos-pc.c
index 140369937..72b5e3ba0 100644
--- a/qemu/tests/libqos/libqos-pc.c
+++ b/qemu/tests/libqos/libqos-pc.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include "libqos/libqos-pc.h"
#include "libqos/malloc-pc.h"
diff --git a/qemu/tests/libqos/libqos.c b/qemu/tests/libqos/libqos.c
index fce625b18..79b0b29b4 100644
--- a/qemu/tests/libqos/libqos.c
+++ b/qemu/tests/libqos/libqos.c
@@ -1,9 +1,5 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "qemu/osdep.h"
#include <glib.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <sys/wait.h>
#include "libqtest.h"
@@ -147,6 +143,23 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
set_context(to);
}
+bool have_qemu_img(void)
+{
+ char *rpath;
+ const char *path = getenv("QTEST_QEMU_IMG");
+ if (!path) {
+ return false;
+ }
+
+ rpath = realpath(path, NULL);
+ if (!rpath) {
+ return false;
+ } else {
+ free(rpath);
+ return true;
+ }
+}
+
void mkimg(const char *file, const char *fmt, unsigned size_mb)
{
gchar *cli;
@@ -155,13 +168,14 @@ void mkimg(const char *file, const char *fmt, unsigned size_mb)
GError *err = NULL;
char *qemu_img_path;
gchar *out, *out2;
- char *abs_path;
+ char *qemu_img_abs_path;
qemu_img_path = getenv("QTEST_QEMU_IMG");
- abs_path = realpath(qemu_img_path, NULL);
- assert(qemu_img_path);
+ g_assert(qemu_img_path);
+ qemu_img_abs_path = realpath(qemu_img_path, NULL);
+ g_assert(qemu_img_abs_path);
- cli = g_strdup_printf("%s create -f %s %s %uM", abs_path,
+ cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path,
fmt, file, size_mb);
ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err);
if (err) {
@@ -183,7 +197,7 @@ void mkimg(const char *file, const char *fmt, unsigned size_mb)
g_free(out);
g_free(out2);
g_free(cli);
- free(abs_path);
+ free(qemu_img_abs_path);
}
void mkqcow2(const char *file, unsigned size_mb)
@@ -212,3 +226,29 @@ void prepare_blkdebug_script(const char *debug_fn, const char *event)
ret = fclose(debug_file);
g_assert(ret == 0);
}
+
+void generate_pattern(void *buffer, size_t len, size_t cycle_len)
+{
+ int i, j;
+ unsigned char *tx = (unsigned char *)buffer;
+ unsigned char p;
+ size_t *sx;
+
+ /* Write an indicative pattern that varies and is unique per-cycle */
+ p = rand() % 256;
+ for (i = 0; i < len; i++) {
+ tx[i] = p++ % 256;
+ if (i % cycle_len == 0) {
+ p = rand() % 256;
+ }
+ }
+
+ /* force uniqueness by writing an id per-cycle */
+ for (i = 0; i < len / cycle_len; i++) {
+ j = i * cycle_len;
+ if (j + sizeof(*sx) <= len) {
+ sx = (size_t *)&tx[j];
+ *sx = i;
+ }
+ }
+}
diff --git a/qemu/tests/libqos/libqos.h b/qemu/tests/libqos/libqos.h
index e1f14ea6f..ca14d2e9f 100644
--- a/qemu/tests/libqos/libqos.h
+++ b/qemu/tests/libqos/libqos.h
@@ -19,11 +19,13 @@ typedef struct QOSState {
QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap);
QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...);
void qtest_shutdown(QOSState *qs);
+bool have_qemu_img(void);
void mkimg(const char *file, const char *fmt, unsigned size_mb);
void mkqcow2(const char *file, unsigned size_mb);
void set_context(QOSState *s);
void migrate(QOSState *from, QOSState *to, const char *uri);
void prepare_blkdebug_script(const char *debug_fn, const char *event);
+void generate_pattern(void *buffer, size_t len, size_t cycle_len);
static inline uint64_t qmalloc(QOSState *q, size_t bytes)
{
diff --git a/qemu/tests/libqos/malloc-generic.c b/qemu/tests/libqos/malloc-generic.c
index d30a2f424..6000df2b8 100644
--- a/qemu/tests/libqos/malloc-generic.c
+++ b/qemu/tests/libqos/malloc-generic.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqos/malloc-generic.h"
#include "libqos/malloc.h"
diff --git a/qemu/tests/libqos/malloc-pc.c b/qemu/tests/libqos/malloc-pc.c
index 6e253b687..eee706bd6 100644
--- a/qemu/tests/libqos/malloc-pc.c
+++ b/qemu/tests/libqos/malloc-pc.c
@@ -10,11 +10,11 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/malloc-pc.h"
#include "libqos/fw_cfg.h"
-#define NO_QEMU_PROTOS
-#include "hw/nvram/fw_cfg.h"
+#include "hw/nvram/fw_cfg_keys.h"
#include "qemu-common.h"
#include <glib.h>
diff --git a/qemu/tests/libqos/malloc.c b/qemu/tests/libqos/malloc.c
index 82b9df537..c0df52f33 100644
--- a/qemu/tests/libqos/malloc.c
+++ b/qemu/tests/libqos/malloc.c
@@ -10,10 +10,9 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/malloc.h"
#include "qemu-common.h"
-#include <stdio.h>
-#include <inttypes.h>
#include <glib.h>
typedef QTAILQ_HEAD(MemList, MemBlock) MemList;
@@ -270,6 +269,10 @@ uint64_t guest_alloc(QGuestAllocator *allocator, size_t size)
uint64_t rsize = size;
uint64_t naddr;
+ if (!size) {
+ return 0;
+ }
+
rsize += (allocator->page_size - 1);
rsize &= -allocator->page_size;
g_assert_cmpint((allocator->start + rsize), <=, allocator->end);
diff --git a/qemu/tests/libqos/malloc.h b/qemu/tests/libqos/malloc.h
index 0c6c9b7f3..ae9dac8f6 100644
--- a/qemu/tests/libqos/malloc.h
+++ b/qemu/tests/libqos/malloc.h
@@ -13,8 +13,6 @@
#ifndef LIBQOS_MALLOC_H
#define LIBQOS_MALLOC_H
-#include <stdint.h>
-#include <sys/types.h>
#include "qemu/queue.h"
typedef enum {
diff --git a/qemu/tests/libqos/pci-pc.c b/qemu/tests/libqos/pci-pc.c
index 6dba0db00..77f15e5a0 100644
--- a/qemu/tests/libqos/pci-pc.c
+++ b/qemu/tests/libqos/pci-pc.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqtest.h"
#include "libqos/pci-pc.h"
@@ -183,7 +184,9 @@ static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *s
if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
uint16_t loc;
- g_assert((s->pci_iohole_alloc + size) <= s->pci_iohole_size);
+ g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size
+ <= s->pci_iohole_size);
+ s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size);
loc = s->pci_iohole_start + s->pci_iohole_alloc;
s->pci_iohole_alloc += size;
@@ -193,7 +196,9 @@ static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *s
} else {
uint64_t loc;
- g_assert((s->pci_hole_alloc + size) <= s->pci_hole_size);
+ g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size
+ <= s->pci_hole_size);
+ s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size);
loc = s->pci_hole_start + s->pci_hole_alloc;
s->pci_hole_alloc += size;
diff --git a/qemu/tests/libqos/pci.c b/qemu/tests/libqos/pci.c
index 4e630c250..0e104e14e 100644
--- a/qemu/tests/libqos/pci.c
+++ b/qemu/tests/libqos/pci.c
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include "libqos/pci.h"
#include "hw/pci/pci_regs.h"
@@ -34,11 +35,13 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
if (vendor_id != -1 &&
qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
+ g_free(dev);
continue;
}
if (device_id != -1 &&
qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
+ g_free(dev);
continue;
}
diff --git a/qemu/tests/libqos/pci.h b/qemu/tests/libqos/pci.h
index dfaee9ec3..c06add8db 100644
--- a/qemu/tests/libqos/pci.h
+++ b/qemu/tests/libqos/pci.h
@@ -13,7 +13,6 @@
#ifndef LIBQOS_PCI_H
#define LIBQOS_PCI_H
-#include <stdint.h>
#include "libqtest.h"
#define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn))
diff --git a/qemu/tests/libqos/usb.c b/qemu/tests/libqos/usb.c
index 41d89b848..87efb9078 100644
--- a/qemu/tests/libqos/usb.c
+++ b/qemu/tests/libqos/usb.c
@@ -11,10 +11,9 @@
* 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 <glib.h>
-#include <string.h>
#include "libqtest.h"
-#include "qemu/osdep.h"
#include "hw/usb/uhci-regs.h"
#include "libqos/usb.h"
diff --git a/qemu/tests/libqos/virtio-mmio.c b/qemu/tests/libqos/virtio-mmio.c
index b3e62e77d..a4382f366 100644
--- a/qemu/tests/libqos/virtio-mmio.c
+++ b/qemu/tests/libqos/virtio-mmio.c
@@ -7,8 +7,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
#include "libqtest.h"
#include "libqos/virtio.h"
#include "libqos/virtio-mmio.h"
diff --git a/qemu/tests/libqos/virtio-pci.c b/qemu/tests/libqos/virtio-pci.c
index f9fb924b8..fde2ff0bc 100644
--- a/qemu/tests/libqos/virtio-pci.c
+++ b/qemu/tests/libqos/virtio-pci.c
@@ -7,8 +7,8 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
-#include <stdio.h>
#include "libqtest.h"
#include "libqos/virtio.h"
#include "libqos/virtio-pci.h"
diff --git a/qemu/tests/libqos/virtio.c b/qemu/tests/libqos/virtio.c
index 3205b88d9..613decea5 100644
--- a/qemu/tests/libqos/virtio.c
+++ b/qemu/tests/libqos/virtio.c
@@ -7,6 +7,7 @@
* See the COPYING file in the top-level directory.
*/
+#include "qemu/osdep.h"
#include <glib.h>
#include "libqtest.h"
#include "libqos/virtio.h"