diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/tests/libqos | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/tests/libqos')
30 files changed, 0 insertions, 5124 deletions
diff --git a/qemu/tests/libqos/ahci.c b/qemu/tests/libqos/ahci.c deleted file mode 100644 index ac6c155c8..000000000 --- a/qemu/tests/libqos/ahci.c +++ /dev/null @@ -1,1124 +0,0 @@ -/* - * libqos AHCI functions - * - * Copyright (c) 2014 John Snow <jsnow@redhat.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include <glib.h> - -#include "libqtest.h" -#include "libqos/ahci.h" -#include "libqos/pci-pc.h" - -#include "qemu-common.h" -#include "qemu/host-utils.h" - -#include "hw/pci/pci_ids.h" -#include "hw/pci/pci_regs.h" - -typedef struct AHCICommandProp { - uint8_t cmd; /* Command Code */ - bool data; /* Data transfer command? */ - bool pio; - bool dma; - bool lba28; - bool lba48; - bool read; - bool write; - bool atapi; - bool ncq; - uint64_t size; /* Static transfer size, for commands like IDENTIFY. */ - uint32_t interrupts; /* Expected interrupts for this command. */ -} AHCICommandProp; - -AHCICommandProp ahci_command_properties[] = { - { .cmd = CMD_READ_PIO, .data = true, .pio = true, - .lba28 = true, .read = true }, - { .cmd = CMD_WRITE_PIO, .data = true, .pio = true, - .lba28 = true, .write = true }, - { .cmd = CMD_READ_PIO_EXT, .data = true, .pio = true, - .lba48 = true, .read = true }, - { .cmd = CMD_WRITE_PIO_EXT, .data = true, .pio = true, - .lba48 = true, .write = true }, - { .cmd = CMD_READ_DMA, .data = true, .dma = true, - .lba28 = true, .read = true }, - { .cmd = CMD_WRITE_DMA, .data = true, .dma = true, - .lba28 = true, .write = true }, - { .cmd = CMD_READ_DMA_EXT, .data = true, .dma = true, - .lba48 = true, .read = true }, - { .cmd = CMD_WRITE_DMA_EXT, .data = true, .dma = true, - .lba48 = true, .write = true }, - { .cmd = CMD_IDENTIFY, .data = true, .pio = true, - .size = 512, .read = true }, - { .cmd = READ_FPDMA_QUEUED, .data = true, .dma = true, - .lba48 = true, .read = true, .ncq = true }, - { .cmd = WRITE_FPDMA_QUEUED, .data = true, .dma = true, - .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_PACKET, .data = true, .size = 16, - .atapi = true, .pio = true }, - { .cmd = CMD_PACKET_ID, .data = true, .pio = true, - .size = 512, .read = true } -}; - -struct AHCICommand { - /* Test Management Data */ - uint8_t name; - uint8_t port; - uint8_t slot; - uint32_t interrupts; - uint64_t xbytes; - uint32_t prd_size; - uint64_t buffer; - AHCICommandProp *props; - /* Data to be transferred to the guest */ - AHCICommandHeader header; - RegH2DFIS fis; - unsigned char *atapi_cmd; -}; - -/** - * Allocate space in the guest using information in the AHCIQState object. - */ -uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes) -{ - g_assert(ahci); - g_assert(ahci->parent); - return qmalloc(ahci->parent, bytes); -} - -void ahci_free(AHCIQState *ahci, uint64_t addr) -{ - g_assert(ahci); - g_assert(ahci->parent); - 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. - */ -QPCIDevice *get_ahci_device(uint32_t *fingerprint) -{ - QPCIDevice *ahci; - uint32_t ahci_fingerprint; - QPCIBus *pcibus; - - pcibus = qpci_init_pc(); - - /* Find the AHCI PCI device and verify it's the right one. */ - ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); - g_assert(ahci != NULL); - - ahci_fingerprint = qpci_config_readl(ahci, PCI_VENDOR_ID); - - switch (ahci_fingerprint) { - case AHCI_INTEL_ICH9: - break; - default: - /* Unknown device. */ - g_assert_not_reached(); - } - - if (fingerprint) { - *fingerprint = ahci_fingerprint; - } - return ahci; -} - -void free_ahci_device(QPCIDevice *dev) -{ - QPCIBus *pcibus = dev ? dev->bus : NULL; - - /* libqos doesn't have a function for this, so free it manually */ - g_free(dev); - qpci_free_pc(pcibus); -} - -/* Free all memory in-use by the AHCI device. */ -void ahci_clean_mem(AHCIQState *ahci) -{ - uint8_t port, slot; - - for (port = 0; port < 32; ++port) { - if (ahci->port[port].fb) { - ahci_free(ahci, ahci->port[port].fb); - ahci->port[port].fb = 0; - } - if (ahci->port[port].clb) { - for (slot = 0; slot < 32; slot++) { - ahci_destroy_command(ahci, port, slot); - } - ahci_free(ahci, ahci->port[port].clb); - ahci->port[port].clb = 0; - } - } -} - -/*** Logical Device Initialization ***/ - -/** - * Start the PCI device and sanity-check default operation. - */ -void ahci_pci_enable(AHCIQState *ahci) -{ - uint8_t reg; - - start_ahci_device(ahci); - - switch (ahci->fingerprint) { - case AHCI_INTEL_ICH9: - /* ICH9 has a register at PCI 0x92 that - * acts as a master port enabler mask. */ - reg = qpci_config_readb(ahci->dev, 0x92); - reg |= 0x3F; - qpci_config_writeb(ahci->dev, 0x92, reg); - /* 0...0111111b -- bit significant, ports 0-5 enabled. */ - ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F); - break; - } - -} - -/** - * Map BAR5/ABAR, and engage the PCI device. - */ -void start_ahci_device(AHCIQState *ahci) -{ - /* Map AHCI's ABAR (BAR5) */ - ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize); - g_assert(ahci->hba_base); - - /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ - qpci_device_enable(ahci->dev); -} - -/** - * Test and initialize the AHCI's HBA memory areas. - * Initialize and start any ports with devices attached. - * Bring the HBA into the idle state. - */ -void ahci_hba_enable(AHCIQState *ahci) -{ - /* Bits of interest in this section: - * GHC.AE Global Host Control / AHCI Enable - * PxCMD.ST Port Command: Start - * PxCMD.SUD "Spin Up Device" - * PxCMD.POD "Power On Device" - * PxCMD.FRE "FIS Receive Enable" - * PxCMD.FR "FIS Receive Running" - * PxCMD.CR "Command List Running" - */ - uint32_t reg, ports_impl; - uint16_t i; - uint8_t num_cmd_slots; - - g_assert(ahci != NULL); - - /* Set GHC.AE to 1 */ - ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE); - reg = ahci_rreg(ahci, AHCI_GHC); - ASSERT_BIT_SET(reg, AHCI_GHC_AE); - - /* Cache CAP and CAP2. */ - ahci->cap = ahci_rreg(ahci, AHCI_CAP); - ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); - - /* Read CAP.NCS, how many command slots do we have? */ - num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; - g_test_message("Number of Command Slots: %u", num_cmd_slots); - - /* Determine which ports are implemented. */ - ports_impl = ahci_rreg(ahci, AHCI_PI); - - for (i = 0; ports_impl; ports_impl >>= 1, ++i) { - if (!(ports_impl & 0x01)) { - continue; - } - - g_test_message("Initializing port %u", i); - - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR | - AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) { - g_test_message("port is idle"); - } else { - g_test_message("port needs to be idled"); - ahci_px_clr(ahci, i, AHCI_PX_CMD, - (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE)); - /* The port has 500ms to disengage. */ - usleep(500000); - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR); - ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR); - g_test_message("port is now idle"); - /* The spec does allow for possibly needing a PORT RESET - * or HBA reset if we fail to idle the port. */ - } - - /* Allocate Memory for the Command List Buffer & FIS Buffer */ - /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ - ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20); - qmemset(ahci->port[i].clb, 0x00, num_cmd_slots * 0x20); - g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb); - ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb); - g_assert_cmphex(ahci->port[i].clb, ==, - ahci_px_rreg(ahci, i, AHCI_PX_CLB)); - - /* PxFB space ... 0x100, as in 4.2.1 p 35 */ - ahci->port[i].fb = ahci_alloc(ahci, 0x100); - qmemset(ahci->port[i].fb, 0x00, 0x100); - g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb); - ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb); - g_assert_cmphex(ahci->port[i].fb, ==, - ahci_px_rreg(ahci, i, AHCI_PX_FB)); - - /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */ - ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF); - ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF); - ahci_wreg(ahci, AHCI_IS, (1 << i)); - - /* Verify Interrupts Cleared */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); - g_assert_cmphex(reg, ==, 0); - - reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); - g_assert_cmphex(reg, ==, 0); - - reg = ahci_rreg(ahci, AHCI_IS); - ASSERT_BIT_CLEAR(reg, (1 << i)); - - /* Enable All Interrupts: */ - ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF); - reg = ahci_px_rreg(ahci, i, AHCI_PX_IE); - g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED)); - - /* Enable the FIS Receive Engine. */ - ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE); - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR); - - /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates - * physical presence, a device is present and may be started. However, - * PxSERR.DIAG.X /may/ need to be cleared a priori. */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); - if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) { - ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X); - } - - reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); - if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) { - reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS); - if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) { - /* Device Found: set PxCMD.ST := 1 */ - ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST); - ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD), - AHCI_PX_CMD_CR); - g_test_message("Started Device %u", i); - } else if ((reg & AHCI_PX_SSTS_DET)) { - /* Device present, but in some unknown state. */ - g_assert_not_reached(); - } - } - } - - /* Enable GHC.IE */ - ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE); - reg = ahci_rreg(ahci, AHCI_GHC); - ASSERT_BIT_SET(reg, AHCI_GHC_IE); - - /* TODO: The device should now be idling and waiting for commands. - * In the future, a small test-case to inspect the Register D2H FIS - * and clear the initial interrupts might be good. */ -} - -/** - * Pick the first implemented and running port - */ -unsigned ahci_port_select(AHCIQState *ahci) -{ - uint32_t ports, reg; - unsigned i; - - ports = ahci_rreg(ahci, AHCI_PI); - for (i = 0; i < 32; ports >>= 1, ++i) { - if (ports == 0) { - i = 32; - } - - if (!(ports & 0x01)) { - continue; - } - - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - if (BITSET(reg, AHCI_PX_CMD_ST)) { - break; - } - } - g_assert(i < 32); - return i; -} - -/** - * Clear a port's interrupts and status information prior to a test. - */ -void ahci_port_clear(AHCIQState *ahci, uint8_t port) -{ - uint32_t reg; - - /* Clear out this port's interrupts (ignore the init register d2h fis) */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); - ahci_px_wreg(ahci, port, AHCI_PX_IS, reg); - g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); - - /* Wipe the FIS-Receive Buffer */ - qmemset(ahci->port[port].fb, 0x00, 0x100); -} - -/** - * Check a port for errors. - */ -void ahci_port_check_error(AHCIQState *ahci, uint8_t port) -{ - uint32_t reg; - - /* The upper 9 bits of the IS register all indicate errors. */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); - reg >>= 23; - g_assert_cmphex(reg, ==, 0); - - /* The Sata Error Register should be empty. */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR); - g_assert_cmphex(reg, ==, 0); - - /* The TFD also has two error sections. */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); -} - -void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, - uint32_t intr_mask) -{ - uint32_t reg; - - /* Check for expected interrupts */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); - ASSERT_BIT_SET(reg, intr_mask); - - /* Clear expected interrupts and assert all interrupts now cleared. */ - ahci_px_wreg(ahci, port, AHCI_PX_IS, intr_mask); - g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); -} - -void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot) -{ - uint32_t reg; - - /* Assert that the command slot is no longer busy (NCQ) */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT); - ASSERT_BIT_CLEAR(reg, (1 << slot)); - - /* Non-NCQ */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); - ASSERT_BIT_CLEAR(reg, (1 << slot)); - - /* And assert that we are generally not busy. */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_BSY); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_DRQ); -} - -void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot) -{ - RegD2HFIS *d2h = g_malloc0(0x20); - uint32_t reg; - - memread(ahci->port[port].fb + 0x40, d2h, 0x20); - g_assert_cmphex(d2h->fis_type, ==, 0x34); - - reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); - g_assert_cmphex((reg & AHCI_PX_TFD_ERR) >> 8, ==, d2h->error); - g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, d2h->status); - - g_free(d2h); -} - -void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, - uint8_t slot, size_t buffsize) -{ - PIOSetupFIS *pio = g_malloc0(0x20); - - /* We cannot check the Status or E_Status registers, because - * the status may have again changed between the PIO Setup FIS - * and the conclusion of the command with the D2H Register FIS. */ - memread(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); - } - - g_free(pio); -} - -void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd) -{ - AHCICommandHeader cmdh; - - ahci_get_command_header(ahci, cmd->port, cmd->slot, &cmdh); - /* Physical Region Descriptor Byte Count is not required to work for NCQ. */ - if (!cmd->props->ncq) { - g_assert_cmphex(cmd->xbytes, ==, cmdh.prdbc); - } -} - -/* Get the command in #slot of port #port. */ -void ahci_get_command_header(AHCIQState *ahci, uint8_t port, - uint8_t slot, AHCICommandHeader *cmd) -{ - uint64_t ba = ahci->port[port].clb; - ba += slot * sizeof(AHCICommandHeader); - memread(ba, cmd, sizeof(AHCICommandHeader)); - - cmd->flags = le16_to_cpu(cmd->flags); - cmd->prdtl = le16_to_cpu(cmd->prdtl); - cmd->prdbc = le32_to_cpu(cmd->prdbc); - cmd->ctba = le64_to_cpu(cmd->ctba); -} - -/* Set the command in #slot of port #port. */ -void ahci_set_command_header(AHCIQState *ahci, uint8_t port, - uint8_t slot, AHCICommandHeader *cmd) -{ - AHCICommandHeader tmp = { .flags = 0 }; - uint64_t ba = ahci->port[port].clb; - ba += slot * sizeof(AHCICommandHeader); - - tmp.flags = cpu_to_le16(cmd->flags); - tmp.prdtl = cpu_to_le16(cmd->prdtl); - tmp.prdbc = cpu_to_le32(cmd->prdbc); - tmp.ctba = cpu_to_le64(cmd->ctba); - - memwrite(ba, &tmp, sizeof(AHCICommandHeader)); -} - -void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot) -{ - AHCICommandHeader cmd; - - /* Obtain the Nth Command Header */ - ahci_get_command_header(ahci, port, slot, &cmd); - if (cmd.ctba == 0) { - /* No address in it, so just return -- it's empty. */ - goto tidy; - } - - /* Free the Table */ - ahci_free(ahci, cmd.ctba); - - tidy: - /* NULL the header. */ - memset(&cmd, 0x00, sizeof(cmd)); - ahci_set_command_header(ahci, port, slot, &cmd); - ahci->port[port].ctba[slot] = 0; - ahci->port[port].prdtl[slot] = 0; -} - -void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd) -{ - RegH2DFIS tmp = cmd->fis; - uint64_t addr = cmd->header.ctba; - - /* NCQ commands use exclusively 8 bit fields and needs no adjustment. - * Only the count field needs to be adjusted for non-NCQ commands. - * The auxiliary FIS fields are defined per-command and are not currently - * implemented in libqos/ahci.o, but may or may not need to be flipped. */ - if (!cmd->props->ncq) { - tmp.count = cpu_to_le16(tmp.count); - } - - memwrite(addr, &tmp, sizeof(tmp)); -} - -unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port) -{ - unsigned i; - unsigned j; - uint32_t reg; - - reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); - - /* Pick the least recently used command slot that's available */ - for (i = 0; i < 32; ++i) { - j = ((ahci->port[port].next + i) % 32); - if (reg & (1 << j)) { - continue; - } - ahci_destroy_command(ahci, port, j); - ahci->port[port].next = (j + 1) % 32; - return j; - } - - g_test_message("All command slots were busy."); - g_assert_not_reached(); -} - -inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd) -{ - /* Each PRD can describe up to 4MiB */ - g_assert_cmphex(bytes_per_prd, <=, 4096 * 1024); - g_assert_cmphex(bytes_per_prd & 0x01, ==, 0x00); - 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, - size_t bufsize, uint64_t sector) -{ - AHCICommand *cmd; - - cmd = ahci_command_create(ide_cmd); - ahci_command_adjust(cmd, sector, buffer, bufsize, 0); - ahci_command_commit(ahci, cmd, port); - ahci_command_issue_async(ahci, cmd); - qmp_eventwait("STOP"); - - return cmd; -} - -/* Resume a previously failed command and verify/finalize */ -void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd) -{ - /* Complete the command */ - qmp_async("{'execute':'cont' }"); - qmp_eventwait("RESUME"); - ahci_command_wait(ahci, cmd); - ahci_command_verify(ahci, cmd); - ahci_command_free(cmd); -} - -/* Given a guest buffer address, perform an IO operation */ -void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, - uint64_t buffer, size_t bufsize, uint64_t sector) -{ - AHCICommand *cmd; - cmd = ahci_command_create(ide_cmd); - ahci_command_set_buffer(cmd, buffer); - ahci_command_set_size(cmd, bufsize); - if (sector) { - ahci_command_set_offset(cmd, sector); - } - ahci_command_commit(ahci, cmd, port); - ahci_command_issue(ahci, cmd); - ahci_command_verify(ahci, cmd); - ahci_command_free(cmd); -} - -static AHCICommandProp *ahci_command_find(uint8_t command_name) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ahci_command_properties); i++) { - if (ahci_command_properties[i].cmd == command_name) { - return &ahci_command_properties[i]; - } - } - - return NULL; -} - -/* Given a HOST buffer, create a buffer address and perform an IO operation. */ -void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, - void *buffer, size_t bufsize, uint64_t sector) -{ - uint64_t ptr; - AHCICommandProp *props; - - props = ahci_command_find(ide_cmd); - g_assert(props); - ptr = ahci_alloc(ahci, bufsize); - g_assert(!bufsize || ptr); - qmemset(ptr, 0x00, bufsize); - - if (bufsize && props->write) { - bufwrite(ptr, buffer, bufsize); - } - - ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector); - - if (bufsize && props->read) { - bufread(ptr, buffer, bufsize); - } - - ahci_free(ahci, ptr); -} - -/** - * Initializes a basic command header in memory. - * We assume that this is for an ATA command using RegH2DFIS. - */ -static void command_header_init(AHCICommand *cmd) -{ - AHCICommandHeader *hdr = &cmd->header; - AHCICommandProp *props = cmd->props; - - hdr->flags = 5; /* RegH2DFIS is 5 DW long. Must be < 32 */ - hdr->flags |= CMDH_CLR_BSY; /* Clear the BSY bit when done */ - if (props->write) { - hdr->flags |= CMDH_WRITE; - } - if (props->atapi) { - hdr->flags |= CMDH_ATAPI; - } - /* Other flags: PREFETCH, RESET, and BIST */ - hdr->prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); - hdr->prdbc = 0; - hdr->ctba = 0; -} - -static void command_table_init(AHCICommand *cmd) -{ - RegH2DFIS *fis = &(cmd->fis); - uint16_t sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE); - - fis->fis_type = REG_H2D_FIS; - fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */ - fis->command = cmd->name; - - if (cmd->props->ncq) { - NCQFIS *ncqfis = (NCQFIS *)fis; - /* NCQ is weird and re-uses FIS frames for unrelated data. - * See SATA 3.2, 13.6.4.1 READ FPDMA QUEUED for an example. */ - ncqfis->sector_low = sect_count & 0xFF; - ncqfis->sector_hi = (sect_count >> 8) & 0xFF; - ncqfis->device = NCQ_DEVICE_MAGIC; - /* Force Unit Access is bit 7 in the device register */ - ncqfis->tag = 0; /* bits 3-7 are the NCQ tag */ - ncqfis->prio = 0; /* bits 6,7 are a prio tag */ - /* RARC bit is bit 0 of TAG field */ - } else { - fis->feature_low = 0x00; - fis->feature_high = 0x00; - if (cmd->props->lba28 || cmd->props->lba48) { - fis->device = ATA_DEVICE_LBA; - } - fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE); - } - fis->icc = 0x00; - fis->control = 0x00; - 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); - AHCICommand *cmd; - - g_assert(props); - cmd = g_malloc0(sizeof(AHCICommand)); - g_assert(!(props->dma && props->pio)); - g_assert(!(props->lba28 && props->lba48)); - g_assert(!(props->read && props->write)); - g_assert(!props->size || props->data); - g_assert(!props->ncq || props->lba48); - - /* Defaults and book-keeping */ - cmd->props = g_memdup(props, sizeof(AHCICommandProp)); - cmd->name = command_name; - cmd->xbytes = props->size; - cmd->prd_size = 4096; - cmd->buffer = 0xabad1dea; - - if (!cmd->props->ncq) { - cmd->interrupts = AHCI_PX_IS_DHRS; - } - /* BUG: We expect the DPS interrupt for data commands */ - /* cmd->interrupts |= props->data ? AHCI_PX_IS_DPS : 0; */ - /* BUG: We expect the DMA Setup interrupt for DMA commands */ - /* cmd->interrupts |= props->dma ? AHCI_PX_IS_DSS : 0; */ - cmd->interrupts |= props->pio ? AHCI_PX_IS_PSS : 0; - cmd->interrupts |= props->ncq ? AHCI_PX_IS_SDBS : 0; - - command_header_init(cmd); - command_table_init(cmd); - - 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); -} - -void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags) -{ - cmd->header.flags |= cmdh_flags; -} - -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->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); - } else { - /* Can't set offset if we don't know the format. */ - g_assert_not_reached(); - } - - /* LBA28 uses the low nibble of the device/control register for LBA24:27 */ - fis->lba_lo[0] = (lba_sect & 0xFF); - fis->lba_lo[1] = (lba_sect >> 8) & 0xFF; - fis->lba_lo[2] = (lba_sect >> 16) & 0xFF; - if (cmd->props->lba28) { - fis->device = (fis->device & 0xF0) | ((lba_sect >> 24) & 0x0F); - } - fis->lba_hi[0] = (lba_sect >> 24) & 0xFF; - fis->lba_hi[1] = (lba_sect >> 32) & 0xFF; - fis->lba_hi[2] = (lba_sect >> 40) & 0xFF; -} - -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) -{ - uint16_t sect_count; - - /* Each PRD can describe up to 4MiB, and must not be odd. */ - g_assert_cmphex(prd_size, <=, 4096 * 1024); - g_assert_cmphex(prd_size & 0x01, ==, 0x00); - if (prd_size) { - cmd->prd_size = prd_size; - } - cmd->xbytes = xbytes; - sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE); - - if (cmd->props->ncq) { - 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; - } - cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); -} - -void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes) -{ - ahci_command_set_sizes(cmd, xbytes, cmd->prd_size); -} - -void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size) -{ - ahci_command_set_sizes(cmd, cmd->xbytes, prd_size); -} - -void ahci_command_adjust(AHCICommand *cmd, uint64_t offset, uint64_t buffer, - uint64_t xbytes, unsigned prd_size) -{ - ahci_command_set_sizes(cmd, xbytes, prd_size); - ahci_command_set_buffer(cmd, buffer); - ahci_command_set_offset(cmd, offset); -} - -void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port) -{ - uint16_t i, prdtl; - uint64_t table_size, table_ptr, remaining; - PRD prd; - - /* This command is now tied to this port/command slot */ - cmd->port = port; - cmd->slot = ahci_pick_cmd(ahci, port); - - if (cmd->props->ncq) { - NCQFIS *nfis = (NCQFIS *)&cmd->fis; - nfis->tag = (cmd->slot << 3) & 0xFC; - } - - /* Create a buffer for the command table */ - prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); - table_size = CMD_TBL_SIZ(prdtl); - table_ptr = ahci_alloc(ahci, table_size); - g_assert(table_ptr); - /* AHCI 1.3: Must be aligned to 0x80 */ - g_assert((table_ptr & 0x7F) == 0x00); - cmd->header.ctba = table_ptr; - - /* 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); - remaining = cmd->xbytes; - for (i = 0; i < prdtl; ++i) { - prd.dba = cpu_to_le64(cmd->buffer + (cmd->prd_size * i)); - prd.res = 0; - if (remaining > cmd->prd_size) { - /* Note that byte count is 0-based. */ - prd.dbc = cpu_to_le32(cmd->prd_size - 1); - remaining -= cmd->prd_size; - } else { - /* Again, dbc is 0-based. */ - prd.dbc = cpu_to_le32(remaining - 1); - remaining = 0; - } - prd.dbc |= cpu_to_le32(0x80000000); /* Request DPS Interrupt */ - - /* Commit the PRD entry to the Command Table */ - memwrite(table_ptr + 0x80 + (i * sizeof(PRD)), - &prd, sizeof(PRD)); - } - - /* Bookmark the PRDTL and CTBA values */ - ahci->port[port].ctba[cmd->slot] = table_ptr; - ahci->port[port].prdtl[cmd->slot] = prdtl; -} - -void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd) -{ - if (cmd->props->ncq) { - ahci_px_wreg(ahci, cmd->port, AHCI_PX_SACT, (1 << cmd->slot)); - } - - ahci_px_wreg(ahci, cmd->port, AHCI_PX_CI, (1 << cmd->slot)); -} - -void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd) -{ - /* We can't rely on STS_BSY until the command has started processing. - * Therefore, we also use the Command Issue bit as indication of - * a command in-flight. */ - -#define RSET(REG, MASK) (BITSET(ahci_px_rreg(ahci, cmd->port, (REG)), (MASK))) - - while (RSET(AHCI_PX_TFD, AHCI_PX_TFD_STS_BSY) || - RSET(AHCI_PX_CI, 1 << cmd->slot) || - (cmd->props->ncq && RSET(AHCI_PX_SACT, 1 << cmd->slot))) { - usleep(50); - } - -} - -void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd) -{ - ahci_command_issue_async(ahci, cmd); - ahci_command_wait(ahci, cmd); -} - -void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd) -{ - uint8_t slot = cmd->slot; - uint8_t port = cmd->port; - - ahci_port_check_error(ahci, port); - ahci_port_check_interrupts(ahci, port, cmd->interrupts); - ahci_port_check_nonbusy(ahci, port, slot); - ahci_port_check_cmd_sanity(ahci, cmd); - if (cmd->interrupts & AHCI_PX_IS_DHRS) { - ahci_port_check_d2h_sanity(ahci, port, slot); - } - if (cmd->props->pio) { - ahci_port_check_pio_sanity(ahci, port, slot, cmd->xbytes); - } -} - -uint8_t ahci_command_slot(AHCICommand *cmd) -{ - return cmd->slot; -} diff --git a/qemu/tests/libqos/ahci.h b/qemu/tests/libqos/ahci.h deleted file mode 100644 index 71dd7a6e5..000000000 --- a/qemu/tests/libqos/ahci.h +++ /dev/null @@ -1,627 +0,0 @@ -#ifndef __libqos_ahci_h -#define __libqos_ahci_h - -/* - * AHCI qtest library functions and definitions - * - * Copyright (c) 2014 John Snow <jsnow@redhat.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "libqos/libqos.h" -#include "libqos/pci.h" -#include "libqos/malloc-pc.h" - -/*** Supplementary PCI Config Space IDs & Masks ***/ -#define PCI_DEVICE_ID_INTEL_Q35_AHCI (0x2922) -#define PCI_MSI_FLAGS_RESERVED (0xFF00) -#define PCI_PM_CTRL_RESERVED (0xFC) -#define PCI_BCC(REG32) ((REG32) >> 24) -#define PCI_PI(REG32) (((REG32) >> 8) & 0xFF) -#define PCI_SCC(REG32) (((REG32) >> 16) & 0xFF) - -/*** Recognized AHCI Device Types ***/ -#define AHCI_INTEL_ICH9 (PCI_DEVICE_ID_INTEL_Q35_AHCI << 16 | \ - PCI_VENDOR_ID_INTEL) - -/*** AHCI/HBA Register Offsets and Bitmasks ***/ -#define AHCI_CAP (0) -#define AHCI_CAP_NP (0x1F) -#define AHCI_CAP_SXS (0x20) -#define AHCI_CAP_EMS (0x40) -#define AHCI_CAP_CCCS (0x80) -#define AHCI_CAP_NCS (0x1F00) -#define AHCI_CAP_PSC (0x2000) -#define AHCI_CAP_SSC (0x4000) -#define AHCI_CAP_PMD (0x8000) -#define AHCI_CAP_FBSS (0x10000) -#define AHCI_CAP_SPM (0x20000) -#define AHCI_CAP_SAM (0x40000) -#define AHCI_CAP_RESERVED (0x80000) -#define AHCI_CAP_ISS (0xF00000) -#define AHCI_CAP_SCLO (0x1000000) -#define AHCI_CAP_SAL (0x2000000) -#define AHCI_CAP_SALP (0x4000000) -#define AHCI_CAP_SSS (0x8000000) -#define AHCI_CAP_SMPS (0x10000000) -#define AHCI_CAP_SSNTF (0x20000000) -#define AHCI_CAP_SNCQ (0x40000000) -#define AHCI_CAP_S64A (0x80000000) - -#define AHCI_GHC (1) -#define AHCI_GHC_HR (0x01) -#define AHCI_GHC_IE (0x02) -#define AHCI_GHC_MRSM (0x04) -#define AHCI_GHC_RESERVED (0x7FFFFFF8) -#define AHCI_GHC_AE (0x80000000) - -#define AHCI_IS (2) -#define AHCI_PI (3) -#define AHCI_VS (4) - -#define AHCI_CCCCTL (5) -#define AHCI_CCCCTL_EN (0x01) -#define AHCI_CCCCTL_RESERVED (0x06) -#define AHCI_CCCCTL_CC (0xFF00) -#define AHCI_CCCCTL_TV (0xFFFF0000) - -#define AHCI_CCCPORTS (6) -#define AHCI_EMLOC (7) - -#define AHCI_EMCTL (8) -#define AHCI_EMCTL_STSMR (0x01) -#define AHCI_EMCTL_CTLTM (0x100) -#define AHCI_EMCTL_CTLRST (0x200) -#define AHCI_EMCTL_RESERVED (0xF0F0FCFE) - -#define AHCI_CAP2 (9) -#define AHCI_CAP2_BOH (0x01) -#define AHCI_CAP2_NVMP (0x02) -#define AHCI_CAP2_APST (0x04) -#define AHCI_CAP2_RESERVED (0xFFFFFFF8) - -#define AHCI_BOHC (10) -#define AHCI_RESERVED (11) -#define AHCI_NVMHCI (24) -#define AHCI_VENDOR (40) -#define AHCI_PORTS (64) - -/*** Port Memory Offsets & Bitmasks ***/ -#define AHCI_PX_CLB (0) -#define AHCI_PX_CLB_RESERVED (0x1FF) - -#define AHCI_PX_CLBU (1) - -#define AHCI_PX_FB (2) -#define AHCI_PX_FB_RESERVED (0xFF) - -#define AHCI_PX_FBU (3) - -#define AHCI_PX_IS (4) -#define AHCI_PX_IS_DHRS (0x1) -#define AHCI_PX_IS_PSS (0x2) -#define AHCI_PX_IS_DSS (0x4) -#define AHCI_PX_IS_SDBS (0x8) -#define AHCI_PX_IS_UFS (0x10) -#define AHCI_PX_IS_DPS (0x20) -#define AHCI_PX_IS_PCS (0x40) -#define AHCI_PX_IS_DMPS (0x80) -#define AHCI_PX_IS_RESERVED (0x23FFF00) -#define AHCI_PX_IS_PRCS (0x400000) -#define AHCI_PX_IS_IPMS (0x800000) -#define AHCI_PX_IS_OFS (0x1000000) -#define AHCI_PX_IS_INFS (0x4000000) -#define AHCI_PX_IS_IFS (0x8000000) -#define AHCI_PX_IS_HBDS (0x10000000) -#define AHCI_PX_IS_HBFS (0x20000000) -#define AHCI_PX_IS_TFES (0x40000000) -#define AHCI_PX_IS_CPDS (0x80000000) - -#define AHCI_PX_IE (5) -#define AHCI_PX_IE_DHRE (0x1) -#define AHCI_PX_IE_PSE (0x2) -#define AHCI_PX_IE_DSE (0x4) -#define AHCI_PX_IE_SDBE (0x8) -#define AHCI_PX_IE_UFE (0x10) -#define AHCI_PX_IE_DPE (0x20) -#define AHCI_PX_IE_PCE (0x40) -#define AHCI_PX_IE_DMPE (0x80) -#define AHCI_PX_IE_RESERVED (0x23FFF00) -#define AHCI_PX_IE_PRCE (0x400000) -#define AHCI_PX_IE_IPME (0x800000) -#define AHCI_PX_IE_OFE (0x1000000) -#define AHCI_PX_IE_INFE (0x4000000) -#define AHCI_PX_IE_IFE (0x8000000) -#define AHCI_PX_IE_HBDE (0x10000000) -#define AHCI_PX_IE_HBFE (0x20000000) -#define AHCI_PX_IE_TFEE (0x40000000) -#define AHCI_PX_IE_CPDE (0x80000000) - -#define AHCI_PX_CMD (6) -#define AHCI_PX_CMD_ST (0x1) -#define AHCI_PX_CMD_SUD (0x2) -#define AHCI_PX_CMD_POD (0x4) -#define AHCI_PX_CMD_CLO (0x8) -#define AHCI_PX_CMD_FRE (0x10) -#define AHCI_PX_CMD_RESERVED (0xE0) -#define AHCI_PX_CMD_CCS (0x1F00) -#define AHCI_PX_CMD_MPSS (0x2000) -#define AHCI_PX_CMD_FR (0x4000) -#define AHCI_PX_CMD_CR (0x8000) -#define AHCI_PX_CMD_CPS (0x10000) -#define AHCI_PX_CMD_PMA (0x20000) -#define AHCI_PX_CMD_HPCP (0x40000) -#define AHCI_PX_CMD_MPSP (0x80000) -#define AHCI_PX_CMD_CPD (0x100000) -#define AHCI_PX_CMD_ESP (0x200000) -#define AHCI_PX_CMD_FBSCP (0x400000) -#define AHCI_PX_CMD_APSTE (0x800000) -#define AHCI_PX_CMD_ATAPI (0x1000000) -#define AHCI_PX_CMD_DLAE (0x2000000) -#define AHCI_PX_CMD_ALPE (0x4000000) -#define AHCI_PX_CMD_ASP (0x8000000) -#define AHCI_PX_CMD_ICC (0xF0000000) - -#define AHCI_PX_RES1 (7) - -#define AHCI_PX_TFD (8) -#define AHCI_PX_TFD_STS (0xFF) -#define AHCI_PX_TFD_STS_ERR (0x01) -#define AHCI_PX_TFD_STS_CS1 (0x06) -#define AHCI_PX_TFD_STS_DRQ (0x08) -#define AHCI_PX_TFD_STS_CS2 (0x70) -#define AHCI_PX_TFD_STS_BSY (0x80) -#define AHCI_PX_TFD_ERR (0xFF00) -#define AHCI_PX_TFD_RESERVED (0xFFFF0000) - -#define AHCI_PX_SIG (9) -#define AHCI_PX_SIG_SECTOR_COUNT (0xFF) -#define AHCI_PX_SIG_LBA_LOW (0xFF00) -#define AHCI_PX_SIG_LBA_MID (0xFF0000) -#define AHCI_PX_SIG_LBA_HIGH (0xFF000000) - -#define AHCI_PX_SSTS (10) -#define AHCI_PX_SSTS_DET (0x0F) -#define AHCI_PX_SSTS_SPD (0xF0) -#define AHCI_PX_SSTS_IPM (0xF00) -#define AHCI_PX_SSTS_RESERVED (0xFFFFF000) -#define SSTS_DET_NO_DEVICE (0x00) -#define SSTS_DET_PRESENT (0x01) -#define SSTS_DET_ESTABLISHED (0x03) -#define SSTS_DET_OFFLINE (0x04) - -#define AHCI_PX_SCTL (11) - -#define AHCI_PX_SERR (12) -#define AHCI_PX_SERR_ERR (0xFFFF) -#define AHCI_PX_SERR_DIAG (0xFFFF0000) -#define AHCI_PX_SERR_DIAG_X (0x04000000) - -#define AHCI_PX_SACT (13) -#define AHCI_PX_CI (14) -#define AHCI_PX_SNTF (15) - -#define AHCI_PX_FBS (16) -#define AHCI_PX_FBS_EN (0x1) -#define AHCI_PX_FBS_DEC (0x2) -#define AHCI_PX_FBS_SDE (0x4) -#define AHCI_PX_FBS_DEV (0xF00) -#define AHCI_PX_FBS_ADO (0xF000) -#define AHCI_PX_FBS_DWE (0xF0000) -#define AHCI_PX_FBS_RESERVED (0xFFF000F8) - -#define AHCI_PX_RES2 (17) -#define AHCI_PX_VS (28) - -#define HBA_DATA_REGION_SIZE (256) -#define HBA_PORT_DATA_SIZE (128) -#define HBA_PORT_NUM_REG (HBA_PORT_DATA_SIZE/4) - -#define AHCI_VERSION_0_95 (0x00000905) -#define AHCI_VERSION_1_0 (0x00010000) -#define AHCI_VERSION_1_1 (0x00010100) -#define AHCI_VERSION_1_2 (0x00010200) -#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 { - REG_H2D_FIS = 0x27, - REG_D2H_FIS = 0x34, - DMA_ACTIVATE_FIS = 0x39, - DMA_SETUP_FIS = 0x41, - DATA_FIS = 0x46, - BIST_ACTIVATE_FIS = 0x58, - PIO_SETUP_FIS = 0x5F, - SDB_FIS = 0xA1 -}; - -/* FIS flags */ -#define REG_H2D_FIS_CMD 0x80 - -/* ATA Commands */ -enum { - /* DMA */ - CMD_READ_DMA = 0xC8, - CMD_READ_DMA_EXT = 0x25, - CMD_WRITE_DMA = 0xCA, - CMD_WRITE_DMA_EXT = 0x35, - /* PIO */ - CMD_READ_PIO = 0x20, - CMD_READ_PIO_EXT = 0x24, - CMD_WRITE_PIO = 0x30, - CMD_WRITE_PIO_EXT = 0x34, - /* Misc */ - CMD_READ_MAX = 0xF8, - 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) -#define CMDH_WRITE (0x40) -#define CMDH_PREFETCH (0x80) -#define CMDH_RESET (0x100) -#define CMDH_BIST (0x200) -#define CMDH_CLR_BSY (0x400) -#define CMDH_RES (0x800) -#define CMDH_PMP (0xF000) - -/* ATA device register masks */ -#define ATA_DEVICE_MAGIC 0xA0 /* used in ata1-3 */ -#define ATA_DEVICE_LBA 0x40 -#define NCQ_DEVICE_MAGIC 0x40 /* for ncq device registers */ -#define ATA_DEVICE_DRIVE 0x10 -#define ATA_DEVICE_HEAD 0x0F - -/*** Structures ***/ - -typedef struct AHCIPortQState { - uint64_t fb; - uint64_t clb; - uint64_t ctba[32]; - uint16_t prdtl[32]; - uint8_t next; /** Next Command Slot to Use **/ -} AHCIPortQState; - -typedef struct AHCIQState { - QOSState *parent; - QPCIDevice *dev; - void *hba_base; - uint64_t barsize; - uint32_t fingerprint; - uint32_t cap; - uint32_t cap2; - AHCIPortQState port[32]; -} AHCIQState; - -/** - * Generic FIS structure. - */ -typedef struct FIS { - uint8_t fis_type; - uint8_t flags; - char data[0]; -} __attribute__((__packed__)) FIS; - -/** - * Register device-to-host FIS structure. - */ -typedef struct RegD2HFIS { - /* DW0 */ - uint8_t fis_type; - uint8_t flags; - uint8_t status; - uint8_t error; - /* DW1 */ - uint8_t lba_lo[3]; - uint8_t device; - /* DW2 */ - uint8_t lba_hi[3]; - uint8_t res0; - /* DW3 */ - uint16_t count; - uint16_t res1; - /* DW4 */ - uint32_t res2; -} __attribute__((__packed__)) RegD2HFIS; - -/** - * Register device-to-host FIS structure; - * PIO Setup variety. - */ -typedef struct PIOSetupFIS { - /* DW0 */ - uint8_t fis_type; - uint8_t flags; - uint8_t status; - uint8_t error; - /* DW1 */ - uint8_t lba_lo[3]; - uint8_t device; - /* DW2 */ - uint8_t lba_hi[3]; - uint8_t res0; - /* DW3 */ - uint16_t count; - uint8_t res1; - uint8_t e_status; - /* DW4 */ - uint16_t tx_count; - uint16_t res2; -} __attribute__((__packed__)) PIOSetupFIS; - -/** - * Register host-to-device FIS structure. - */ -typedef struct RegH2DFIS { - /* DW0 */ - uint8_t fis_type; - uint8_t flags; - uint8_t command; - uint8_t feature_low; - /* DW1 */ - uint8_t lba_lo[3]; - uint8_t device; - /* DW2 */ - uint8_t lba_hi[3]; - uint8_t feature_high; - /* DW3 */ - uint16_t count; - uint8_t icc; - uint8_t control; - /* DW4 */ - uint8_t aux[4]; -} __attribute__((__packed__)) RegH2DFIS; - -/** - * Register host-to-device FIS structure, for NCQ commands. - * Actually just a RegH2DFIS, but with fields repurposed. - * Repurposed fields are annotated below. - */ -typedef struct NCQFIS { - /* DW0 */ - uint8_t fis_type; - uint8_t flags; - uint8_t command; - uint8_t sector_low; /* H2D: Feature 7:0 */ - /* DW1 */ - uint8_t lba_lo[3]; - uint8_t device; - /* DW2 */ - uint8_t lba_hi[3]; - uint8_t sector_hi; /* H2D: Feature 15:8 */ - /* DW3 */ - uint8_t tag; /* H2D: Count 0:7 */ - uint8_t prio; /* H2D: Count 15:8 */ - uint8_t icc; - uint8_t control; - /* DW4 */ - uint8_t aux[4]; -} __attribute__((__packed__)) NCQFIS; - -/** - * Command List entry structure. - * The command list contains between 1-32 of these structures. - */ -typedef struct AHCICommandHeader { - uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */ - uint16_t prdtl; /* Phys Region Desc. Table Length */ - uint32_t prdbc; /* Phys Region Desc. Byte Count */ - uint64_t ctba; /* Command Table Descriptor Base Address */ - uint32_t res[4]; -} __attribute__((__packed__)) AHCICommandHeader; - -/** - * Physical Region Descriptor; pointed to by the Command List Header, - * struct ahci_command. - */ -typedef struct PRD { - uint64_t dba; /* Data Base Address */ - uint32_t res; /* Reserved */ - uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ -} __attribute__((__packed__)) 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)) -#define BITCLR(data, mask) (((data) & (mask)) == 0) -#define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) -#define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0) - -/* For calculating how big the PRD table needs to be: */ -#define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F) - -/* Helpers for reading/writing AHCI HBA register values */ - -static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset) -{ - return qpci_io_readl(ahci->dev, ahci->hba_base + offset); -} - -static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value) -{ - qpci_io_writel(ahci->dev, ahci->hba_base + offset, value); -} - -static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num) -{ - return ahci_mread(ahci, 4 * reg_num); -} - -static inline void ahci_wreg(AHCIQState *ahci, uint32_t reg_num, uint32_t value) -{ - ahci_mwrite(ahci, 4 * reg_num, value); -} - -static inline void ahci_set(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) -{ - ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) | mask); -} - -static inline void ahci_clr(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) -{ - ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) & ~mask); -} - -static inline size_t ahci_px_offset(uint8_t port, uint32_t reg_num) -{ - return AHCI_PORTS + (HBA_PORT_NUM_REG * port) + reg_num; -} - -static inline uint32_t ahci_px_rreg(AHCIQState *ahci, uint8_t port, - uint32_t reg_num) -{ - return ahci_rreg(ahci, ahci_px_offset(port, reg_num)); -} - -static inline void ahci_px_wreg(AHCIQState *ahci, uint8_t port, - uint32_t reg_num, uint32_t value) -{ - ahci_wreg(ahci, ahci_px_offset(port, reg_num), value); -} - -static inline void ahci_px_set(AHCIQState *ahci, uint8_t port, - uint32_t reg_num, uint32_t mask) -{ - ahci_px_wreg(ahci, port, reg_num, - ahci_px_rreg(ahci, port, reg_num) | mask); -} - -static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port, - uint32_t reg_num, uint32_t mask) -{ - ahci_px_wreg(ahci, port, reg_num, - ahci_px_rreg(ahci, port, reg_num) & ~mask); -} - -/*** 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_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); -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_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd); - -/* 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, - uint64_t gbuffer, size_t size, uint64_t sector); -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: 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); -void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd); -void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd); -void ahci_command_free(AHCICommand *cmd); - -/* 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); -void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer); -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 */ -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 deleted file mode 100644 index 76894d575..000000000 --- a/qemu/tests/libqos/fw_cfg.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * libqos fw_cfg support - * - * Copyright IBM, Corp. 2012-2013 - * Copyright (C) 2013 Red Hat Inc. - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * Markus Armbruster <armbru@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 <glib.h> -#include "libqos/fw_cfg.h" -#include "libqtest.h" -#include "qemu/bswap.h" - -void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key) -{ - fw_cfg->select(fw_cfg, key); -} - -void qfw_cfg_read_data(QFWCFG *fw_cfg, void *data, size_t len) -{ - fw_cfg->read(fw_cfg, data, len); -} - -void qfw_cfg_get(QFWCFG *fw_cfg, uint16_t key, void *data, size_t len) -{ - qfw_cfg_select(fw_cfg, key); - qfw_cfg_read_data(fw_cfg, data, len); -} - -uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key) -{ - uint16_t value; - qfw_cfg_get(fw_cfg, key, &value, sizeof(value)); - return le16_to_cpu(value); -} - -uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key) -{ - uint32_t value; - qfw_cfg_get(fw_cfg, key, &value, sizeof(value)); - return le32_to_cpu(value); -} - -uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key) -{ - uint64_t value; - qfw_cfg_get(fw_cfg, key, &value, sizeof(value)); - return le64_to_cpu(value); -} - -static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) -{ - writew(fw_cfg->base, key); -} - -static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len) -{ - uint8_t *ptr = data; - int i; - - for (i = 0; i < len; i++) { - ptr[i] = readb(fw_cfg->base + 2); - } -} - -QFWCFG *mm_fw_cfg_init(uint64_t base) -{ - QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); - - fw_cfg->base = base; - fw_cfg->select = mm_fw_cfg_select; - fw_cfg->read = mm_fw_cfg_read; - - return fw_cfg; -} - -static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) -{ - outw(fw_cfg->base, key); -} - -static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len) -{ - uint8_t *ptr = data; - int i; - - for (i = 0; i < len; i++) { - ptr[i] = inb(fw_cfg->base + 1); - } -} - -QFWCFG *io_fw_cfg_init(uint16_t base) -{ - QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); - - fw_cfg->base = base; - fw_cfg->select = io_fw_cfg_select; - fw_cfg->read = io_fw_cfg_read; - - return fw_cfg; -} diff --git a/qemu/tests/libqos/fw_cfg.h b/qemu/tests/libqos/fw_cfg.h deleted file mode 100644 index e8371b231..000000000 --- a/qemu/tests/libqos/fw_cfg.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * libqos fw_cfg support - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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. - */ - -#ifndef LIBQOS_FW_CFG_H -#define LIBQOS_FW_CFG_H - - -typedef struct QFWCFG QFWCFG; - -struct QFWCFG -{ - uint64_t base; - void (*select)(QFWCFG *fw_cfg, uint16_t key); - void (*read)(QFWCFG *fw_cfg, void *data, size_t len); -}; - -void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key); -void qfw_cfg_read_data(QFWCFG *fw_cfg, void *data, size_t len); -void qfw_cfg_get(QFWCFG *fw_cfg, uint16_t key, void *data, size_t len); -uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key); -uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key); -uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key); - -QFWCFG *mm_fw_cfg_init(uint64_t base); -QFWCFG *io_fw_cfg_init(uint16_t base); - -static inline QFWCFG *pc_fw_cfg_init(void) -{ - return io_fw_cfg_init(0x510); -} - -#endif diff --git a/qemu/tests/libqos/i2c-imx.c b/qemu/tests/libqos/i2c-imx.c deleted file mode 100644 index 51c3468f9..000000000 --- a/qemu/tests/libqos/i2c-imx.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 deleted file mode 100644 index 2028f2f14..000000000 --- a/qemu/tests/libqos/i2c-omap.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * QTest I2C driver - * - * Copyright (c) 2012 Andreas Färber - * - * 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 "qemu/bswap.h" -#include "libqtest.h" - -enum OMAPI2CRegisters { - OMAP_I2C_REV = 0x00, - OMAP_I2C_STAT = 0x08, - OMAP_I2C_CNT = 0x18, - OMAP_I2C_DATA = 0x1c, - OMAP_I2C_CON = 0x24, - OMAP_I2C_SA = 0x2c, -}; - -enum OMAPI2CSTATBits { - OMAP_I2C_STAT_NACK = 1 << 1, - OMAP_I2C_STAT_ARDY = 1 << 2, - OMAP_I2C_STAT_RRDY = 1 << 3, - OMAP_I2C_STAT_XRDY = 1 << 4, - OMAP_I2C_STAT_ROVR = 1 << 11, - OMAP_I2C_STAT_SBD = 1 << 15, -}; - -enum OMAPI2CCONBits { - OMAP_I2C_CON_STT = 1 << 0, - OMAP_I2C_CON_STP = 1 << 1, - OMAP_I2C_CON_TRX = 1 << 9, - OMAP_I2C_CON_MST = 1 << 10, - OMAP_I2C_CON_BE = 1 << 14, - OMAP_I2C_CON_I2C_EN = 1 << 15, -}; - -typedef struct OMAPI2C { - I2CAdapter parent; - - uint64_t addr; -} OMAPI2C; - - -static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) -{ - uint16_t data = addr; - - writew(s->addr + OMAP_I2C_SA, data); - data = readw(s->addr + OMAP_I2C_SA); - g_assert_cmphex(data, ==, addr); -} - -static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr, - const uint8_t *buf, uint16_t len) -{ - OMAPI2C *s = (OMAPI2C *)i2c; - uint16_t data; - - omap_i2c_set_slave_addr(s, addr); - - data = len; - writew(s->addr + OMAP_I2C_CNT, data); - - data = OMAP_I2C_CON_I2C_EN | - OMAP_I2C_CON_TRX | - OMAP_I2C_CON_MST | - OMAP_I2C_CON_STT | - OMAP_I2C_CON_STP; - writew(s->addr + OMAP_I2C_CON, data); - data = readw(s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) != 0); - - data = readw(s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_NACK) == 0); - - while (len > 1) { - data = readw(s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_XRDY) != 0); - - data = buf[0] | ((uint16_t)buf[1] << 8); - writew(s->addr + OMAP_I2C_DATA, data); - buf = (uint8_t *)buf + 2; - len -= 2; - } - if (len == 1) { - data = readw(s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_XRDY) != 0); - - data = buf[0]; - writew(s->addr + OMAP_I2C_DATA, data); - } - - data = readw(s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) == 0); -} - -static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr, - uint8_t *buf, uint16_t len) -{ - OMAPI2C *s = (OMAPI2C *)i2c; - uint16_t data, stat; - - omap_i2c_set_slave_addr(s, addr); - - data = len; - writew(s->addr + OMAP_I2C_CNT, data); - - data = OMAP_I2C_CON_I2C_EN | - OMAP_I2C_CON_MST | - OMAP_I2C_CON_STT | - OMAP_I2C_CON_STP; - writew(s->addr + OMAP_I2C_CON, data); - data = readw(s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) == 0); - - data = readw(s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_NACK) == 0); - - data = readw(s->addr + OMAP_I2C_CNT); - g_assert_cmpuint(data, ==, len); - - while (len > 0) { - data = readw(s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_RRDY) != 0); - g_assert((data & OMAP_I2C_STAT_ROVR) == 0); - - data = readw(s->addr + OMAP_I2C_DATA); - - stat = readw(s->addr + OMAP_I2C_STAT); - - if (unlikely(len == 1)) { - g_assert((stat & OMAP_I2C_STAT_SBD) != 0); - - buf[0] = data & 0xff; - buf++; - len--; - } else { - buf[0] = data & 0xff; - buf[1] = data >> 8; - buf += 2; - len -= 2; - } - } - - data = readw(s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) == 0); -} - -I2CAdapter *omap_i2c_create(uint64_t addr) -{ - OMAPI2C *s = g_malloc0(sizeof(*s)); - I2CAdapter *i2c = (I2CAdapter *)s; - uint16_t data; - - s->addr = addr; - - i2c->send = omap_i2c_send; - i2c->recv = omap_i2c_recv; - - /* verify the mmio address by looking for a known signature */ - data = readw(addr + OMAP_I2C_REV); - g_assert_cmphex(data, ==, 0x34); - - return i2c; -} diff --git a/qemu/tests/libqos/i2c.c b/qemu/tests/libqos/i2c.c deleted file mode 100644 index 23bc2a3eb..000000000 --- a/qemu/tests/libqos/i2c.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * QTest I2C driver - * - * Copyright (c) 2012 Andreas Färber - * - * 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" - -void i2c_send(I2CAdapter *i2c, uint8_t addr, - const uint8_t *buf, uint16_t len) -{ - i2c->send(i2c, addr, buf, len); -} - -void i2c_recv(I2CAdapter *i2c, uint8_t addr, - uint8_t *buf, uint16_t len) -{ - i2c->recv(i2c, addr, buf, len); -} diff --git a/qemu/tests/libqos/i2c.h b/qemu/tests/libqos/i2c.h deleted file mode 100644 index 6e648f922..000000000 --- a/qemu/tests/libqos/i2c.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * I2C libqos - * - * Copyright (c) 2012 Andreas Färber - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -#ifndef LIBQOS_I2C_H -#define LIBQOS_I2C_H - - -typedef struct I2CAdapter I2CAdapter; -struct I2CAdapter { - void (*send)(I2CAdapter *adapter, uint8_t addr, - const uint8_t *buf, uint16_t len); - void (*recv)(I2CAdapter *adapter, uint8_t addr, - uint8_t *buf, uint16_t len); -}; - -void i2c_send(I2CAdapter *i2c, uint8_t addr, - const uint8_t *buf, uint16_t len); -void i2c_recv(I2CAdapter *i2c, uint8_t addr, - uint8_t *buf, uint16_t len); - -/* 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 deleted file mode 100644 index 72b5e3ba0..000000000 --- a/qemu/tests/libqos/libqos-pc.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "qemu/osdep.h" -#include "libqos/libqos-pc.h" -#include "libqos/malloc-pc.h" - -static QOSOps qos_ops = { - .init_allocator = pc_alloc_init_flags, - .uninit_allocator = pc_alloc_uninit -}; - -QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) -{ - return qtest_vboot(&qos_ops, cmdline_fmt, ap); -} - -QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) -{ - QOSState *qs; - va_list ap; - - va_start(ap, cmdline_fmt); - qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); - va_end(ap); - - return qs; -} - -void qtest_pc_shutdown(QOSState *qs) -{ - return qtest_shutdown(qs); -} diff --git a/qemu/tests/libqos/libqos-pc.h b/qemu/tests/libqos/libqos-pc.h deleted file mode 100644 index b1820c573..000000000 --- a/qemu/tests/libqos/libqos-pc.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __libqos_pc_h -#define __libqos_pc_h - -#include "libqos/libqos.h" - -QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap); -QOSState *qtest_pc_boot(const char *cmdline_fmt, ...); -void qtest_pc_shutdown(QOSState *qs); - -#endif diff --git a/qemu/tests/libqos/libqos.c b/qemu/tests/libqos/libqos.c deleted file mode 100644 index 79b0b29b4..000000000 --- a/qemu/tests/libqos/libqos.c +++ /dev/null @@ -1,254 +0,0 @@ -#include "qemu/osdep.h" -#include <glib.h> -#include <sys/wait.h> - -#include "libqtest.h" -#include "libqos/libqos.h" -#include "libqos/pci.h" - -/*** Test Setup & Teardown ***/ - -/** - * Launch QEMU with the given command line, - * and then set up interrupts and our guest malloc interface. - */ -QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) -{ - char *cmdline; - - struct QOSState *qs = g_malloc(sizeof(QOSState)); - - cmdline = g_strdup_vprintf(cmdline_fmt, ap); - qs->qts = qtest_start(cmdline); - qs->ops = ops; - qtest_irq_intercept_in(global_qtest, "ioapic"); - if (ops && ops->init_allocator) { - qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); - } - - g_free(cmdline); - return qs; -} - -/** - * Launch QEMU with the given command line, - * and then set up interrupts and our guest malloc interface. - */ -QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) -{ - QOSState *qs; - va_list ap; - - va_start(ap, cmdline_fmt); - qs = qtest_vboot(ops, cmdline_fmt, ap); - va_end(ap); - - return qs; -} - -/** - * Tear down the QEMU instance. - */ -void qtest_shutdown(QOSState *qs) -{ - if (qs->alloc && qs->ops && qs->ops->uninit_allocator) { - qs->ops->uninit_allocator(qs->alloc); - qs->alloc = NULL; - } - qtest_quit(qs->qts); - g_free(qs); -} - -void set_context(QOSState *s) -{ - global_qtest = s->qts; -} - -static QDict *qmp_execute(const char *command) -{ - char *fmt; - QDict *rsp; - - fmt = g_strdup_printf("{ 'execute': '%s' }", command); - rsp = qmp(fmt); - g_free(fmt); - - return rsp; -} - -void migrate(QOSState *from, QOSState *to, const char *uri) -{ - const char *st; - char *s; - QDict *rsp, *sub; - bool running; - - set_context(from); - - /* Is the machine currently running? */ - rsp = qmp_execute("query-status"); - g_assert(qdict_haskey(rsp, "return")); - sub = qdict_get_qdict(rsp, "return"); - g_assert(qdict_haskey(sub, "running")); - running = qdict_get_bool(sub, "running"); - QDECREF(rsp); - - /* Issue the migrate command. */ - s = g_strdup_printf("{ 'execute': 'migrate'," - "'arguments': { 'uri': '%s' } }", - uri); - rsp = qmp(s); - g_free(s); - g_assert(qdict_haskey(rsp, "return")); - QDECREF(rsp); - - /* Wait for STOP event, but only if we were running: */ - if (running) { - qmp_eventwait("STOP"); - } - - /* If we were running, we can wait for an event. */ - if (running) { - migrate_allocator(from->alloc, to->alloc); - set_context(to); - qmp_eventwait("RESUME"); - return; - } - - /* Otherwise, we need to wait: poll until migration is completed. */ - while (1) { - rsp = qmp_execute("query-migrate"); - g_assert(qdict_haskey(rsp, "return")); - sub = qdict_get_qdict(rsp, "return"); - g_assert(qdict_haskey(sub, "status")); - st = qdict_get_str(sub, "status"); - - /* "setup", "active", "completed", "failed", "cancelled" */ - if (strcmp(st, "completed") == 0) { - QDECREF(rsp); - break; - } - - if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)) { - QDECREF(rsp); - g_usleep(5000); - continue; - } - - fprintf(stderr, "Migration did not complete, status: %s\n", st); - g_assert_not_reached(); - } - - migrate_allocator(from->alloc, to->alloc); - 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; - bool ret; - int rc; - GError *err = NULL; - char *qemu_img_path; - gchar *out, *out2; - char *qemu_img_abs_path; - - qemu_img_path = getenv("QTEST_QEMU_IMG"); - 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", qemu_img_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(qemu_img_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); -} - -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 deleted file mode 100644 index ca14d2e9f..000000000 --- a/qemu/tests/libqos/libqos.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __libqos_h -#define __libqos_h - -#include "libqtest.h" -#include "libqos/pci.h" -#include "libqos/malloc-pc.h" - -typedef struct QOSOps { - QGuestAllocator *(*init_allocator)(QAllocOpts); - void (*uninit_allocator)(QGuestAllocator *); -} QOSOps; - -typedef struct QOSState { - QTestState *qts; - QGuestAllocator *alloc; - QOSOps *ops; -} 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) -{ - return guest_alloc(q->alloc, bytes); -} - -static inline void qfree(QOSState *q, uint64_t addr) -{ - guest_free(q->alloc, addr); -} - -#endif diff --git a/qemu/tests/libqos/malloc-generic.c b/qemu/tests/libqos/malloc-generic.c deleted file mode 100644 index 6000df2b8..000000000 --- a/qemu/tests/libqos/malloc-generic.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Basic libqos generic malloc support - * - * Copyright (c) 2014 Marc Marí - * - * 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 "libqos/malloc-generic.h" -#include "libqos/malloc.h" - -/* - * Mostly for valgrind happiness, but it does offer - * a chokepoint for debugging guest memory leaks, too. - */ -void generic_alloc_uninit(QGuestAllocator *allocator) -{ - alloc_uninit(allocator); -} - -QGuestAllocator *generic_alloc_init_flags(uint64_t base_addr, uint64_t size, - uint32_t page_size, QAllocOpts flags) -{ - QGuestAllocator *s; - uint64_t start = base_addr + (1 << 20); /* Start at 1MB */ - - s = alloc_init_flags(flags, start, start + size); - alloc_set_page_size(s, page_size); - - return s; -} - -inline QGuestAllocator *generic_alloc_init(uint64_t base_addr, uint64_t size, - uint32_t page_size) -{ - return generic_alloc_init_flags(base_addr, size, page_size, ALLOC_NO_FLAGS); -} diff --git a/qemu/tests/libqos/malloc-generic.h b/qemu/tests/libqos/malloc-generic.h deleted file mode 100644 index 90104ecec..000000000 --- a/qemu/tests/libqos/malloc-generic.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Basic libqos generic malloc support - * - * Copyright (c) 2014 Marc Marí - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef LIBQOS_MALLOC_GENERIC_H -#define LIBQOS_MALLOC_GENERIC_H - -#include "libqos/malloc.h" - -QGuestAllocator *generic_alloc_init(uint64_t base_addr, uint64_t size, - uint32_t page_size); -QGuestAllocator *generic_alloc_init_flags(uint64_t base_addr, uint64_t size, - uint32_t page_size, QAllocOpts flags); -void generic_alloc_uninit(QGuestAllocator *allocator); - -#endif diff --git a/qemu/tests/libqos/malloc-pc.c b/qemu/tests/libqos/malloc-pc.c deleted file mode 100644 index eee706bd6..000000000 --- a/qemu/tests/libqos/malloc-pc.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * libqos malloc support for PC - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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 "libqos/malloc-pc.h" -#include "libqos/fw_cfg.h" - -#include "hw/nvram/fw_cfg_keys.h" - -#include "qemu-common.h" -#include <glib.h> - -#define PAGE_SIZE (4096) - -/* - * Mostly for valgrind happiness, but it does offer - * a chokepoint for debugging guest memory leaks, too. - */ -void pc_alloc_uninit(QGuestAllocator *allocator) -{ - alloc_uninit(allocator); -} - -QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags) -{ - QGuestAllocator *s; - uint64_t ram_size; - QFWCFG *fw_cfg = pc_fw_cfg_init(); - - ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE); - s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000)); - alloc_set_page_size(s, PAGE_SIZE); - - /* clean-up */ - g_free(fw_cfg); - - return s; -} - -inline QGuestAllocator *pc_alloc_init(void) -{ - return pc_alloc_init_flags(ALLOC_NO_FLAGS); -} diff --git a/qemu/tests/libqos/malloc-pc.h b/qemu/tests/libqos/malloc-pc.h deleted file mode 100644 index 86ab9f042..000000000 --- a/qemu/tests/libqos/malloc-pc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * libqos malloc support for PC - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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. - */ - -#ifndef LIBQOS_MALLOC_PC_H -#define LIBQOS_MALLOC_PC_H - -#include "libqos/malloc.h" - -QGuestAllocator *pc_alloc_init(void); -QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags); -void pc_alloc_uninit(QGuestAllocator *allocator); - -#endif diff --git a/qemu/tests/libqos/malloc.c b/qemu/tests/libqos/malloc.c deleted file mode 100644 index c0df52f33..000000000 --- a/qemu/tests/libqos/malloc.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * libqos malloc support - * - * Copyright (c) 2014 - * - * Author: - * John Snow <jsnow@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 "libqos/malloc.h" -#include "qemu-common.h" -#include <glib.h> - -typedef QTAILQ_HEAD(MemList, MemBlock) MemList; - -typedef struct MemBlock { - QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME; - uint64_t size; - uint64_t addr; -} MemBlock; - -struct QGuestAllocator { - QAllocOpts opts; - uint64_t start; - uint64_t end; - uint32_t page_size; - - MemList *used; - MemList *free; -}; - -#define DEFAULT_PAGE_SIZE 4096 - -static void mlist_delete(MemList *list, MemBlock *node) -{ - g_assert(list && node); - QTAILQ_REMOVE(list, node, MLIST_ENTNAME); - g_free(node); -} - -static MemBlock *mlist_find_key(MemList *head, uint64_t addr) -{ - MemBlock *node; - QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { - if (node->addr == addr) { - return node; - } - } - return NULL; -} - -static MemBlock *mlist_find_space(MemList *head, uint64_t size) -{ - MemBlock *node; - - QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { - if (node->size >= size) { - return node; - } - } - return NULL; -} - -static MemBlock *mlist_sort_insert(MemList *head, MemBlock *insr) -{ - MemBlock *node; - g_assert(head && insr); - - QTAILQ_FOREACH(node, head, MLIST_ENTNAME) { - if (insr->addr < node->addr) { - QTAILQ_INSERT_BEFORE(node, insr, MLIST_ENTNAME); - return insr; - } - } - - QTAILQ_INSERT_TAIL(head, insr, MLIST_ENTNAME); - return insr; -} - -static inline uint64_t mlist_boundary(MemBlock *node) -{ - return node->size + node->addr; -} - -static MemBlock *mlist_join(MemList *head, MemBlock *left, MemBlock *right) -{ - g_assert(head && left && right); - - left->size += right->size; - mlist_delete(head, right); - return left; -} - -static void mlist_coalesce(MemList *head, MemBlock *node) -{ - g_assert(node); - MemBlock *left; - MemBlock *right; - char merge; - - do { - merge = 0; - left = QTAILQ_PREV(node, MemList, MLIST_ENTNAME); - right = QTAILQ_NEXT(node, MLIST_ENTNAME); - - /* clowns to the left of me */ - if (left && mlist_boundary(left) == node->addr) { - node = mlist_join(head, left, node); - merge = 1; - } - - /* jokers to the right */ - if (right && mlist_boundary(node) == right->addr) { - node = mlist_join(head, node, right); - merge = 1; - } - - } while (merge); -} - -static MemBlock *mlist_new(uint64_t addr, uint64_t size) -{ - MemBlock *block; - - if (!size) { - return NULL; - } - block = g_malloc0(sizeof(MemBlock)); - - block->addr = addr; - block->size = size; - - return block; -} - -static uint64_t mlist_fulfill(QGuestAllocator *s, MemBlock *freenode, - uint64_t size) -{ - uint64_t addr; - MemBlock *usednode; - - g_assert(freenode); - g_assert_cmpint(freenode->size, >=, size); - - addr = freenode->addr; - if (freenode->size == size) { - /* re-use this freenode as our used node */ - QTAILQ_REMOVE(s->free, freenode, MLIST_ENTNAME); - usednode = freenode; - } else { - /* adjust the free node and create a new used node */ - freenode->addr += size; - freenode->size -= size; - usednode = mlist_new(addr, size); - } - - mlist_sort_insert(s->used, usednode); - return addr; -} - -/* To assert the correctness of the list. - * Used only if ALLOC_PARANOID is set. */ -static void mlist_check(QGuestAllocator *s) -{ - MemBlock *node; - uint64_t addr = s->start > 0 ? s->start - 1 : 0; - uint64_t next = s->start; - - QTAILQ_FOREACH(node, s->free, MLIST_ENTNAME) { - g_assert_cmpint(node->addr, >, addr); - g_assert_cmpint(node->addr, >=, next); - addr = node->addr; - next = node->addr + node->size; - } - - addr = s->start > 0 ? s->start - 1 : 0; - next = s->start; - QTAILQ_FOREACH(node, s->used, MLIST_ENTNAME) { - g_assert_cmpint(node->addr, >, addr); - g_assert_cmpint(node->addr, >=, next); - addr = node->addr; - next = node->addr + node->size; - } -} - -static uint64_t mlist_alloc(QGuestAllocator *s, uint64_t size) -{ - MemBlock *node; - - node = mlist_find_space(s->free, size); - if (!node) { - fprintf(stderr, "Out of guest memory.\n"); - g_assert_not_reached(); - } - return mlist_fulfill(s, node, size); -} - -static void mlist_free(QGuestAllocator *s, uint64_t addr) -{ - MemBlock *node; - - if (addr == 0) { - return; - } - - node = mlist_find_key(s->used, addr); - if (!node) { - fprintf(stderr, "Error: no record found for an allocation at " - "0x%016" PRIx64 ".\n", - addr); - g_assert_not_reached(); - } - - /* Rip it out of the used list and re-insert back into the free list. */ - QTAILQ_REMOVE(s->used, node, MLIST_ENTNAME); - mlist_sort_insert(s->free, node); - mlist_coalesce(s->free, node); -} - -/* - * Mostly for valgrind happiness, but it does offer - * a chokepoint for debugging guest memory leaks, too. - */ -void alloc_uninit(QGuestAllocator *allocator) -{ - MemBlock *node; - MemBlock *tmp; - QAllocOpts mask; - - /* Check for guest leaks, and destroy the list. */ - QTAILQ_FOREACH_SAFE(node, allocator->used, MLIST_ENTNAME, tmp) { - if (allocator->opts & (ALLOC_LEAK_WARN | ALLOC_LEAK_ASSERT)) { - fprintf(stderr, "guest malloc leak @ 0x%016" PRIx64 "; " - "size 0x%016" PRIx64 ".\n", - node->addr, node->size); - } - if (allocator->opts & (ALLOC_LEAK_ASSERT)) { - g_assert_not_reached(); - } - g_free(node); - } - - /* If we have previously asserted that there are no leaks, then there - * should be only one node here with a specific address and size. */ - mask = ALLOC_LEAK_ASSERT | ALLOC_PARANOID; - QTAILQ_FOREACH_SAFE(node, allocator->free, MLIST_ENTNAME, tmp) { - if ((allocator->opts & mask) == mask) { - if ((node->addr != allocator->start) || - (node->size != allocator->end - allocator->start)) { - fprintf(stderr, "Free list is corrupted.\n"); - g_assert_not_reached(); - } - } - - g_free(node); - } - - g_free(allocator->used); - g_free(allocator->free); - g_free(allocator); -} - -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); - g_assert_cmpint(rsize, >=, size); - - naddr = mlist_alloc(allocator, rsize); - if (allocator->opts & ALLOC_PARANOID) { - mlist_check(allocator); - } - - return naddr; -} - -void guest_free(QGuestAllocator *allocator, uint64_t addr) -{ - if (!addr) { - return; - } - mlist_free(allocator, addr); - if (allocator->opts & ALLOC_PARANOID) { - mlist_check(allocator); - } -} - -QGuestAllocator *alloc_init(uint64_t start, uint64_t end) -{ - QGuestAllocator *s = g_malloc0(sizeof(*s)); - MemBlock *node; - - s->start = start; - s->end = end; - - s->used = g_malloc(sizeof(MemList)); - s->free = g_malloc(sizeof(MemList)); - QTAILQ_INIT(s->used); - QTAILQ_INIT(s->free); - - node = mlist_new(s->start, s->end - s->start); - QTAILQ_INSERT_HEAD(s->free, node, MLIST_ENTNAME); - - s->page_size = DEFAULT_PAGE_SIZE; - - return s; -} - -QGuestAllocator *alloc_init_flags(QAllocOpts opts, - uint64_t start, uint64_t end) -{ - QGuestAllocator *s = alloc_init(start, end); - s->opts = opts; - return s; -} - -void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size) -{ - /* Can't alter the page_size for an allocator in-use */ - g_assert(QTAILQ_EMPTY(allocator->used)); - - g_assert(is_power_of_2(page_size)); - allocator->page_size = page_size; -} - -void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts) -{ - allocator->opts |= opts; -} - -void migrate_allocator(QGuestAllocator *src, - QGuestAllocator *dst) -{ - MemBlock *node, *tmp; - MemList *tmpused, *tmpfree; - - /* The general memory layout should be equivalent, - * though opts can differ. */ - g_assert_cmphex(src->start, ==, dst->start); - g_assert_cmphex(src->end, ==, dst->end); - - /* Destroy (silently, regardless of options) the dest-list: */ - QTAILQ_FOREACH_SAFE(node, dst->used, MLIST_ENTNAME, tmp) { - g_free(node); - } - QTAILQ_FOREACH_SAFE(node, dst->free, MLIST_ENTNAME, tmp) { - g_free(node); - } - - tmpused = dst->used; - tmpfree = dst->free; - - /* Inherit the lists of the source allocator: */ - dst->used = src->used; - dst->free = src->free; - - /* Source is now re-initialized, the source memory is 'invalid' now: */ - src->used = tmpused; - src->free = tmpfree; - QTAILQ_INIT(src->used); - QTAILQ_INIT(src->free); - node = mlist_new(src->start, src->end - src->start); - QTAILQ_INSERT_HEAD(src->free, node, MLIST_ENTNAME); - return; -} diff --git a/qemu/tests/libqos/malloc.h b/qemu/tests/libqos/malloc.h deleted file mode 100644 index ae9dac8f6..000000000 --- a/qemu/tests/libqos/malloc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * libqos malloc support - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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. - */ - -#ifndef LIBQOS_MALLOC_H -#define LIBQOS_MALLOC_H - -#include "qemu/queue.h" - -typedef enum { - ALLOC_NO_FLAGS = 0x00, - ALLOC_LEAK_WARN = 0x01, - ALLOC_LEAK_ASSERT = 0x02, - ALLOC_PARANOID = 0x04 -} QAllocOpts; - -typedef struct QGuestAllocator QGuestAllocator; - -void alloc_uninit(QGuestAllocator *allocator); - -/* Always returns page aligned values */ -uint64_t guest_alloc(QGuestAllocator *allocator, size_t size); -void guest_free(QGuestAllocator *allocator, uint64_t addr); -void migrate_allocator(QGuestAllocator *src, QGuestAllocator *dst); - -QGuestAllocator *alloc_init(uint64_t start, uint64_t end); -QGuestAllocator *alloc_init_flags(QAllocOpts flags, - uint64_t start, uint64_t end); -void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size); -void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts); - -#endif diff --git a/qemu/tests/libqos/pci-pc.c b/qemu/tests/libqos/pci-pc.c deleted file mode 100644 index 77f15e5a0..000000000 --- a/qemu/tests/libqos/pci-pc.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * libqos PCI bindings for PC - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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 "libqos/pci-pc.h" - -#include "hw/pci/pci_regs.h" - -#include "qemu-common.h" -#include "qemu/host-utils.h" - -#include <glib.h> - -#define ACPI_PCIHP_ADDR 0xae00 -#define PCI_EJ_BASE 0x0008 - -typedef struct QPCIBusPC -{ - QPCIBus bus; - - uint32_t pci_hole_start; - uint32_t pci_hole_size; - uint32_t pci_hole_alloc; - - uint16_t pci_iohole_start; - uint16_t pci_iohole_size; - uint16_t pci_iohole_alloc; -} QPCIBusPC; - -static uint8_t qpci_pc_io_readb(QPCIBus *bus, void *addr) -{ - uintptr_t port = (uintptr_t)addr; - uint8_t value; - - if (port < 0x10000) { - value = inb(port); - } else { - value = readb(port); - } - - return value; -} - -static uint16_t qpci_pc_io_readw(QPCIBus *bus, void *addr) -{ - uintptr_t port = (uintptr_t)addr; - uint16_t value; - - if (port < 0x10000) { - value = inw(port); - } else { - value = readw(port); - } - - return value; -} - -static uint32_t qpci_pc_io_readl(QPCIBus *bus, void *addr) -{ - uintptr_t port = (uintptr_t)addr; - uint32_t value; - - if (port < 0x10000) { - value = inl(port); - } else { - value = readl(port); - } - - return value; -} - -static void qpci_pc_io_writeb(QPCIBus *bus, void *addr, uint8_t value) -{ - uintptr_t port = (uintptr_t)addr; - - if (port < 0x10000) { - outb(port, value); - } else { - writeb(port, value); - } -} - -static void qpci_pc_io_writew(QPCIBus *bus, void *addr, uint16_t value) -{ - uintptr_t port = (uintptr_t)addr; - - if (port < 0x10000) { - outw(port, value); - } else { - writew(port, value); - } -} - -static void qpci_pc_io_writel(QPCIBus *bus, void *addr, uint32_t value) -{ - uintptr_t port = (uintptr_t)addr; - - if (port < 0x10000) { - outl(port, value); - } else { - writel(port, value); - } -} - -static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) -{ - outl(0xcf8, (1U << 31) | (devfn << 8) | offset); - return inb(0xcfc); -} - -static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset) -{ - outl(0xcf8, (1U << 31) | (devfn << 8) | offset); - return inw(0xcfc); -} - -static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset) -{ - outl(0xcf8, (1U << 31) | (devfn << 8) | offset); - return inl(0xcfc); -} - -static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) -{ - outl(0xcf8, (1U << 31) | (devfn << 8) | offset); - outb(0xcfc, value); -} - -static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) -{ - outl(0xcf8, (1U << 31) | (devfn << 8) | offset); - outw(0xcfc, value); -} - -static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) -{ - outl(0xcf8, (1U << 31) | (devfn << 8) | offset); - outl(0xcfc, value); -} - -static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr) -{ - QPCIBusPC *s = container_of(bus, QPCIBusPC, bus); - static const int bar_reg_map[] = { - PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, - }; - int bar_reg; - uint32_t addr; - uint64_t size; - uint32_t io_type; - - g_assert(barno >= 0 && barno <= 5); - bar_reg = bar_reg_map[barno]; - - qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); - addr = qpci_config_readl(dev, bar_reg); - - io_type = addr & PCI_BASE_ADDRESS_SPACE; - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - addr &= PCI_BASE_ADDRESS_IO_MASK; - } else { - addr &= PCI_BASE_ADDRESS_MEM_MASK; - } - - size = (1ULL << ctzl(addr)); - if (size == 0) { - return NULL; - } - if (sizeptr) { - *sizeptr = size; - } - - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - uint16_t loc; - - 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; - - qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); - - return (void *)(intptr_t)loc; - } else { - uint64_t loc; - - 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; - - qpci_config_writel(dev, bar_reg, loc); - - return (void *)(intptr_t)loc; - } -} - -static void qpci_pc_iounmap(QPCIBus *bus, void *data) -{ - /* FIXME */ -} - -QPCIBus *qpci_init_pc(void) -{ - QPCIBusPC *ret; - - ret = g_malloc(sizeof(*ret)); - - ret->bus.io_readb = qpci_pc_io_readb; - ret->bus.io_readw = qpci_pc_io_readw; - ret->bus.io_readl = qpci_pc_io_readl; - - ret->bus.io_writeb = qpci_pc_io_writeb; - ret->bus.io_writew = qpci_pc_io_writew; - ret->bus.io_writel = qpci_pc_io_writel; - - ret->bus.config_readb = qpci_pc_config_readb; - ret->bus.config_readw = qpci_pc_config_readw; - ret->bus.config_readl = qpci_pc_config_readl; - - ret->bus.config_writeb = qpci_pc_config_writeb; - ret->bus.config_writew = qpci_pc_config_writew; - ret->bus.config_writel = qpci_pc_config_writel; - - ret->bus.iomap = qpci_pc_iomap; - ret->bus.iounmap = qpci_pc_iounmap; - - ret->pci_hole_start = 0xE0000000; - ret->pci_hole_size = 0x20000000; - ret->pci_hole_alloc = 0; - - ret->pci_iohole_start = 0xc000; - ret->pci_iohole_size = 0x4000; - ret->pci_iohole_alloc = 0; - - return &ret->bus; -} - -void qpci_free_pc(QPCIBus *bus) -{ - QPCIBusPC *s = container_of(bus, QPCIBusPC, bus); - - g_free(s); -} - -void qpci_plug_device_test(const char *driver, const char *id, - uint8_t slot, const char *opts) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_add'," - " 'arguments': {" - " 'driver': '%s'," - " 'addr': '%d'," - " %s%s" - " 'id': '%s'" - "}}", driver, slot, - opts ? opts : "", opts ? "," : "", - id); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); -} - -void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_del'," - " 'arguments': {" - " 'id': '%s'" - "}}", id); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); - - outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); - - response = qmp(""); - g_assert(response); - g_assert(qdict_haskey(response, "event")); - g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED")); - QDECREF(response); -} diff --git a/qemu/tests/libqos/pci-pc.h b/qemu/tests/libqos/pci-pc.h deleted file mode 100644 index 26211790c..000000000 --- a/qemu/tests/libqos/pci-pc.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * libqos PCI bindings for PC - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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. - */ - -#ifndef LIBQOS_PCI_PC_H -#define LIBQOS_PCI_PC_H - -#include "libqos/pci.h" - -QPCIBus *qpci_init_pc(void); -void qpci_free_pc(QPCIBus *bus); - -#endif diff --git a/qemu/tests/libqos/pci.c b/qemu/tests/libqos/pci.c deleted file mode 100644 index 0e104e14e..000000000 --- a/qemu/tests/libqos/pci.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * libqos PCI bindings - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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 "libqos/pci.h" - -#include "hw/pci/pci_regs.h" -#include <glib.h> - -void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, - void (*func)(QPCIDevice *dev, int devfn, void *data), - void *data) -{ - int slot; - - for (slot = 0; slot < 32; slot++) { - int fn; - - for (fn = 0; fn < 8; fn++) { - QPCIDevice *dev; - - dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn)); - if (!dev) { - continue; - } - - 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; - } - - func(dev, QPCI_DEVFN(slot, fn), data); - } - } -} - -QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn) -{ - QPCIDevice *dev; - - dev = g_malloc0(sizeof(*dev)); - dev->bus = bus; - dev->devfn = devfn; - - if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) { - g_free(dev); - return NULL; - } - - return dev; -} - -void qpci_device_enable(QPCIDevice *dev) -{ - uint16_t cmd; - - /* FIXME -- does this need to be a bus callout? */ - cmd = qpci_config_readw(dev, PCI_COMMAND); - cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - qpci_config_writew(dev, PCI_COMMAND, cmd); - - /* Verify the bits are now set. */ - cmd = qpci_config_readw(dev, PCI_COMMAND); - g_assert_cmphex(cmd & PCI_COMMAND_IO, ==, PCI_COMMAND_IO); - g_assert_cmphex(cmd & PCI_COMMAND_MEMORY, ==, PCI_COMMAND_MEMORY); - g_assert_cmphex(cmd & PCI_COMMAND_MASTER, ==, PCI_COMMAND_MASTER); -} - -uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id) -{ - uint8_t cap; - uint8_t addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST); - - do { - cap = qpci_config_readb(dev, addr); - if (cap != id) { - addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT); - } - } while (cap != id && addr != 0); - - return addr; -} - -void qpci_msix_enable(QPCIDevice *dev) -{ - uint8_t addr; - uint16_t val; - uint32_t table; - uint8_t bir_table; - uint8_t bir_pba; - void *offset; - - addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX); - g_assert_cmphex(addr, !=, 0); - - val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS); - qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE); - - table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE); - bir_table = table & PCI_MSIX_FLAGS_BIRMASK; - offset = qpci_iomap(dev, bir_table, NULL); - dev->msix_table = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK); - - table = qpci_config_readl(dev, addr + PCI_MSIX_PBA); - bir_pba = table & PCI_MSIX_FLAGS_BIRMASK; - if (bir_pba != bir_table) { - offset = qpci_iomap(dev, bir_pba, NULL); - } - dev->msix_pba = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK); - - g_assert(dev->msix_table != NULL); - g_assert(dev->msix_pba != NULL); - dev->msix_enabled = true; -} - -void qpci_msix_disable(QPCIDevice *dev) -{ - uint8_t addr; - uint16_t val; - - g_assert(dev->msix_enabled); - addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX); - g_assert_cmphex(addr, !=, 0); - val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS); - qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, - val & ~PCI_MSIX_FLAGS_ENABLE); - - qpci_iounmap(dev, dev->msix_table); - qpci_iounmap(dev, dev->msix_pba); - dev->msix_enabled = 0; - dev->msix_table = NULL; - dev->msix_pba = NULL; -} - -bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry) -{ - uint32_t pba_entry; - uint8_t bit_n = entry % 32; - void *addr = dev->msix_pba + (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4; - - g_assert(dev->msix_enabled); - pba_entry = qpci_io_readl(dev, addr); - qpci_io_writel(dev, addr, pba_entry & ~(1 << bit_n)); - return (pba_entry & (1 << bit_n)) != 0; -} - -bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry) -{ - uint8_t addr; - uint16_t val; - void *vector_addr = dev->msix_table + (entry * PCI_MSIX_ENTRY_SIZE); - - g_assert(dev->msix_enabled); - addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX); - g_assert_cmphex(addr, !=, 0); - val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS); - - if (val & PCI_MSIX_FLAGS_MASKALL) { - return true; - } else { - return (qpci_io_readl(dev, vector_addr + PCI_MSIX_ENTRY_VECTOR_CTRL) - & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0; - } -} - -uint16_t qpci_msix_table_size(QPCIDevice *dev) -{ - uint8_t addr; - uint16_t control; - - addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX); - g_assert_cmphex(addr, !=, 0); - - control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS); - return (control & PCI_MSIX_FLAGS_QSIZE) + 1; -} - -uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset) -{ - return dev->bus->config_readb(dev->bus, dev->devfn, offset); -} - -uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset) -{ - return dev->bus->config_readw(dev->bus, dev->devfn, offset); -} - -uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset) -{ - return dev->bus->config_readl(dev->bus, dev->devfn, offset); -} - - -void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value) -{ - dev->bus->config_writeb(dev->bus, dev->devfn, offset, value); -} - -void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value) -{ - dev->bus->config_writew(dev->bus, dev->devfn, offset, value); -} - -void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value) -{ - dev->bus->config_writel(dev->bus, dev->devfn, offset, value); -} - - -uint8_t qpci_io_readb(QPCIDevice *dev, void *data) -{ - return dev->bus->io_readb(dev->bus, data); -} - -uint16_t qpci_io_readw(QPCIDevice *dev, void *data) -{ - return dev->bus->io_readw(dev->bus, data); -} - -uint32_t qpci_io_readl(QPCIDevice *dev, void *data) -{ - return dev->bus->io_readl(dev->bus, data); -} - - -void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value) -{ - dev->bus->io_writeb(dev->bus, data, value); -} - -void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value) -{ - dev->bus->io_writew(dev->bus, data, value); -} - -void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) -{ - dev->bus->io_writel(dev->bus, data, value); -} - -void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) -{ - return dev->bus->iomap(dev->bus, dev, barno, sizeptr); -} - -void qpci_iounmap(QPCIDevice *dev, void *data) -{ - dev->bus->iounmap(dev->bus, data); -} - - diff --git a/qemu/tests/libqos/pci.h b/qemu/tests/libqos/pci.h deleted file mode 100644 index c06add8db..000000000 --- a/qemu/tests/libqos/pci.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libqos PCI bindings - * - * Copyright IBM, Corp. 2012-2013 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.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. - */ - -#ifndef LIBQOS_PCI_H -#define LIBQOS_PCI_H - -#include "libqtest.h" - -#define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) - -typedef struct QPCIDevice QPCIDevice; -typedef struct QPCIBus QPCIBus; - -struct QPCIBus -{ - uint8_t (*io_readb)(QPCIBus *bus, void *addr); - uint16_t (*io_readw)(QPCIBus *bus, void *addr); - uint32_t (*io_readl)(QPCIBus *bus, void *addr); - - void (*io_writeb)(QPCIBus *bus, void *addr, uint8_t value); - void (*io_writew)(QPCIBus *bus, void *addr, uint16_t value); - void (*io_writel)(QPCIBus *bus, void *addr, uint32_t value); - - uint8_t (*config_readb)(QPCIBus *bus, int devfn, uint8_t offset); - uint16_t (*config_readw)(QPCIBus *bus, int devfn, uint8_t offset); - uint32_t (*config_readl)(QPCIBus *bus, int devfn, uint8_t offset); - - void (*config_writeb)(QPCIBus *bus, int devfn, - uint8_t offset, uint8_t value); - void (*config_writew)(QPCIBus *bus, int devfn, - uint8_t offset, uint16_t value); - void (*config_writel)(QPCIBus *bus, int devfn, - uint8_t offset, uint32_t value); - - void *(*iomap)(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr); - void (*iounmap)(QPCIBus *bus, void *data); -}; - -struct QPCIDevice -{ - QPCIBus *bus; - int devfn; - bool msix_enabled; - void *msix_table; - void *msix_pba; -}; - -void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, - void (*func)(QPCIDevice *dev, int devfn, void *data), - void *data); -QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn); - -void qpci_device_enable(QPCIDevice *dev); -uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id); -void qpci_msix_enable(QPCIDevice *dev); -void qpci_msix_disable(QPCIDevice *dev); -bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry); -bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry); -uint16_t qpci_msix_table_size(QPCIDevice *dev); - -uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset); -uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset); -uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset); - -void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value); -void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value); -void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value); - -uint8_t qpci_io_readb(QPCIDevice *dev, void *data); -uint16_t qpci_io_readw(QPCIDevice *dev, void *data); -uint32_t qpci_io_readl(QPCIDevice *dev, void *data); - -void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value); -void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value); -void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value); - -void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); -void qpci_iounmap(QPCIDevice *dev, void *data); - -void qpci_plug_device_test(const char *driver, const char *id, - uint8_t slot, const char *opts); -void qpci_unplug_acpi_device_test(const char *id, uint8_t slot); -#endif diff --git a/qemu/tests/libqos/usb.c b/qemu/tests/libqos/usb.c deleted file mode 100644 index 87efb9078..000000000 --- a/qemu/tests/libqos/usb.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * common code shared by usb tests - * - * Copyright (c) 2014 Red Hat, Inc - * - * Authors: - * Gerd Hoffmann <kraxel@redhat.com> - * John Snow <jsnow@redhat.com> - * Igor Mammedov <imammedo@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 <glib.h> -#include "libqtest.h" -#include "hw/usb/uhci-regs.h" -#include "libqos/usb.h" - -void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, uint32_t devfn, int bar) -{ - hc->dev = qpci_device_find(pcibus, devfn); - g_assert(hc->dev != NULL); - qpci_device_enable(hc->dev); - hc->base = qpci_iomap(hc->dev, bar, NULL); - g_assert(hc->base != NULL); -} - -void uhci_port_test(struct qhc *hc, int port, uint16_t expect) -{ - void *addr = hc->base + 0x10 + 2 * port; - uint16_t value = qpci_io_readw(hc->dev, addr); - uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1); - - g_assert((value & mask) == (expect & mask)); -} - -void usb_test_hotplug(const char *hcd_id, const int port, - void (*port_check)(void)) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_add'," - " 'arguments': {" - " 'driver': 'usb-tablet'," - " 'port': '%d'," - " 'bus': '%s.0'," - " 'id': 'usbdev%d'" - "}}", port, hcd_id, port); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); - - if (port_check) { - port_check(); - } - - cmd = g_strdup_printf("{'execute': 'device_del'," - " 'arguments': {" - " 'id': 'usbdev%d'" - "}}", port); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(qdict_haskey(response, "event")); - g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED")); -} diff --git a/qemu/tests/libqos/usb.h b/qemu/tests/libqos/usb.h deleted file mode 100644 index 8fe56872b..000000000 --- a/qemu/tests/libqos/usb.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef LIBQOS_USB_H -#define LIBQOS_USB_H - -#include "libqos/pci-pc.h" - -struct qhc { - QPCIDevice *dev; - void *base; -}; - -void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, - uint32_t devfn, int bar); -void uhci_port_test(struct qhc *hc, int port, uint16_t expect); - -void usb_test_hotplug(const char *bus_name, const int port, - void (*port_check)(void)); -#endif diff --git a/qemu/tests/libqos/virtio-mmio.c b/qemu/tests/libqos/virtio-mmio.c deleted file mode 100644 index a4382f366..000000000 --- a/qemu/tests/libqos/virtio-mmio.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * libqos virtio MMIO driver - * - * Copyright (c) 2014 Marc Marí - * - * 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 "libqtest.h" -#include "libqos/virtio.h" -#include "libqos/virtio-mmio.h" -#include "libqos/malloc.h" -#include "libqos/malloc-generic.h" - -static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t addr) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readb(dev->addr + addr); -} - -static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t addr) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readw(dev->addr + addr); -} - -static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t addr) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readl(dev->addr + addr); -} - -static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t addr) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readq(dev->addr + addr); -} - -static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - writel(dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0); - return readl(dev->addr + QVIRTIO_MMIO_HOST_FEATURES); -} - -static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t features) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - dev->features = features; - writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0); - writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features); -} - -static uint32_t qvirtio_mmio_get_guest_features(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return dev->features; -} - -static uint8_t qvirtio_mmio_get_status(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return (uint8_t)readl(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS); -} - -static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - writel(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status); -} - -static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - uint32_t isr; - - isr = readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1; - if (isr != 0) { - writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1); - return true; - } - - return false; -} - -static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - uint32_t isr; - - isr = readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2; - if (isr != 0) { - writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2); - return true; - } - - return false; -} - -static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - writel(dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index); - - g_assert_cmphex(readl(dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0); -} - -static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return (uint16_t)readl(dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX); -} - -static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, uint32_t pfn) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - writel(dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn); -} - -static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - QVirtQueue *vq; - uint64_t addr; - - vq = g_malloc0(sizeof(*vq)); - qvirtio_mmio_queue_select(d, index); - writel(dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size); - - vq->index = index; - vq->size = qvirtio_mmio_get_queue_size(d); - vq->free_head = 0; - vq->num_free = vq->size; - vq->align = dev->page_size; - vq->indirect = (dev->features & QVIRTIO_F_RING_INDIRECT_DESC) != 0; - vq->event = (dev->features & QVIRTIO_F_RING_EVENT_IDX) != 0; - - writel(dev->addr + QVIRTIO_MMIO_QUEUE_NUM, vq->size); - - /* Check different than 0 */ - g_assert_cmpint(vq->size, !=, 0); - - /* Check power of 2 */ - g_assert_cmpint(vq->size & (vq->size - 1), ==, 0); - - addr = guest_alloc(alloc, qvring_size(vq->size, dev->page_size)); - qvring_init(alloc, vq, addr); - qvirtio_mmio_set_queue_address(d, vq->desc / dev->page_size); - - return vq; -} - -static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - writel(dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index); -} - -const QVirtioBus qvirtio_mmio = { - .config_readb = qvirtio_mmio_config_readb, - .config_readw = qvirtio_mmio_config_readw, - .config_readl = qvirtio_mmio_config_readl, - .config_readq = qvirtio_mmio_config_readq, - .get_features = qvirtio_mmio_get_features, - .set_features = qvirtio_mmio_set_features, - .get_guest_features = qvirtio_mmio_get_guest_features, - .get_status = qvirtio_mmio_get_status, - .set_status = qvirtio_mmio_set_status, - .get_queue_isr_status = qvirtio_mmio_get_queue_isr_status, - .get_config_isr_status = qvirtio_mmio_get_config_isr_status, - .queue_select = qvirtio_mmio_queue_select, - .get_queue_size = qvirtio_mmio_get_queue_size, - .set_queue_address = qvirtio_mmio_set_queue_address, - .virtqueue_setup = qvirtio_mmio_virtqueue_setup, - .virtqueue_kick = qvirtio_mmio_virtqueue_kick, -}; - -QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size) -{ - QVirtioMMIODevice *dev; - uint32_t magic; - dev = g_malloc0(sizeof(*dev)); - - magic = readl(addr + QVIRTIO_MMIO_MAGIC_VALUE); - g_assert(magic == ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)); - - dev->addr = addr; - dev->page_size = page_size; - dev->vdev.device_type = readl(addr + QVIRTIO_MMIO_DEVICE_ID); - - writel(addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size); - - return dev; -} diff --git a/qemu/tests/libqos/virtio-mmio.h b/qemu/tests/libqos/virtio-mmio.h deleted file mode 100644 index e3e52b9ce..000000000 --- a/qemu/tests/libqos/virtio-mmio.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * libqos virtio MMIO definitions - * - * Copyright (c) 2014 Marc Marí - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef LIBQOS_VIRTIO_MMIO_H -#define LIBQOS_VIRTIO_MMIO_H - -#include "libqos/virtio.h" - -#define QVIRTIO_MMIO_MAGIC_VALUE 0x000 -#define QVIRTIO_MMIO_VERSION 0x004 -#define QVIRTIO_MMIO_DEVICE_ID 0x008 -#define QVIRTIO_MMIO_VENDOR_ID 0x00C -#define QVIRTIO_MMIO_HOST_FEATURES 0x010 -#define QVIRTIO_MMIO_HOST_FEATURES_SEL 0x014 -#define QVIRTIO_MMIO_GUEST_FEATURES 0x020 -#define QVIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 -#define QVIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 -#define QVIRTIO_MMIO_QUEUE_SEL 0x030 -#define QVIRTIO_MMIO_QUEUE_NUM_MAX 0x034 -#define QVIRTIO_MMIO_QUEUE_NUM 0x038 -#define QVIRTIO_MMIO_QUEUE_ALIGN 0x03C -#define QVIRTIO_MMIO_QUEUE_PFN 0x040 -#define QVIRTIO_MMIO_QUEUE_NOTIFY 0x050 -#define QVIRTIO_MMIO_INTERRUPT_STATUS 0x060 -#define QVIRTIO_MMIO_INTERRUPT_ACK 0x064 -#define QVIRTIO_MMIO_DEVICE_STATUS 0x070 -#define QVIRTIO_MMIO_DEVICE_SPECIFIC 0x100 - -typedef struct QVirtioMMIODevice { - QVirtioDevice vdev; - uint64_t addr; - uint32_t page_size; - uint32_t features; /* As it cannot be read later, save it */ -} QVirtioMMIODevice; - -extern const QVirtioBus qvirtio_mmio; - -QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size); - -#endif diff --git a/qemu/tests/libqos/virtio-pci.c b/qemu/tests/libqos/virtio-pci.c deleted file mode 100644 index fde2ff0bc..000000000 --- a/qemu/tests/libqos/virtio-pci.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * libqos virtio PCI driver - * - * Copyright (c) 2014 Marc Marí - * - * 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 "libqtest.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" -#include "libqos/pci.h" -#include "libqos/pci-pc.h" -#include "libqos/malloc.h" -#include "libqos/malloc-pc.h" - -#include "hw/pci/pci_regs.h" - -typedef struct QVirtioPCIForeachData { - void (*func)(QVirtioDevice *d, void *data); - uint16_t device_type; - void *user_data; -} QVirtioPCIForeachData; - -static QVirtioPCIDevice *qpcidevice_to_qvirtiodevice(QPCIDevice *pdev) -{ - QVirtioPCIDevice *vpcidev; - vpcidev = g_malloc0(sizeof(*vpcidev)); - - if (pdev) { - vpcidev->pdev = pdev; - vpcidev->vdev.device_type = - qpci_config_readw(vpcidev->pdev, PCI_SUBSYSTEM_ID); - } - - vpcidev->config_msix_entry = -1; - - return vpcidev; -} - -static void qvirtio_pci_foreach_callback( - QPCIDevice *dev, int devfn, void *data) -{ - QVirtioPCIForeachData *d = data; - QVirtioPCIDevice *vpcidev = qpcidevice_to_qvirtiodevice(dev); - - if (vpcidev->vdev.device_type == d->device_type) { - d->func(&vpcidev->vdev, d->user_data); - } else { - g_free(vpcidev); - } -} - -static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data) -{ - QVirtioPCIDevice **vpcidev = data; - *vpcidev = (QVirtioPCIDevice *)d; -} - -static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr); -} - -static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readw(dev->pdev, (void *)(uintptr_t)addr); -} - -static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readl(dev->pdev, (void *)(uintptr_t)addr); -} - -static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - int i; - uint64_t u64 = 0; - - if (qtest_big_endian()) { - for (i = 0; i < 8; ++i) { - u64 |= (uint64_t)qpci_io_readb(dev->pdev, - (void *)(uintptr_t)addr + i) << (7 - i) * 8; - } - } else { - for (i = 0; i < 8; ++i) { - u64 |= (uint64_t)qpci_io_readb(dev->pdev, - (void *)(uintptr_t)addr + i) << i * 8; - } - } - - return u64; -} - -static uint32_t qvirtio_pci_get_features(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readl(dev->pdev, dev->addr + QVIRTIO_PCI_DEVICE_FEATURES); -} - -static void qvirtio_pci_set_features(QVirtioDevice *d, uint32_t features) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writel(dev->pdev, dev->addr + QVIRTIO_PCI_GUEST_FEATURES, features); -} - -static uint32_t qvirtio_pci_get_guest_features(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readl(dev->pdev, dev->addr + QVIRTIO_PCI_GUEST_FEATURES); -} - -static uint8_t qvirtio_pci_get_status(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_PCI_DEVICE_STATUS); -} - -static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_PCI_DEVICE_STATUS, status); -} - -static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - QVirtQueuePCI *vqpci = (QVirtQueuePCI *)vq; - uint32_t data; - - if (dev->pdev->msix_enabled) { - g_assert_cmpint(vqpci->msix_entry, !=, -1); - if (qpci_msix_masked(dev->pdev, vqpci->msix_entry)) { - /* No ISR checking should be done if masked, but read anyway */ - return qpci_msix_pending(dev->pdev, vqpci->msix_entry); - } else { - data = readl(vqpci->msix_addr); - if (data == vqpci->msix_data) { - writel(vqpci->msix_addr, 0); - return true; - } else { - return false; - } - } - } else { - return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_PCI_ISR_STATUS) & 1; - } -} - -static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - uint32_t data; - - if (dev->pdev->msix_enabled) { - g_assert_cmpint(dev->config_msix_entry, !=, -1); - if (qpci_msix_masked(dev->pdev, dev->config_msix_entry)) { - /* No ISR checking should be done if masked, but read anyway */ - return qpci_msix_pending(dev->pdev, dev->config_msix_entry); - } else { - data = readl(dev->config_msix_addr); - if (data == dev->config_msix_data) { - writel(dev->config_msix_addr, 0); - return true; - } else { - return false; - } - } - } else { - return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_PCI_ISR_STATUS) & 2; - } -} - -static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_SELECT, index); -} - -static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readw(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_SIZE); -} - -static void qvirtio_pci_set_queue_address(QVirtioDevice *d, uint32_t pfn) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writel(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_ADDRESS, pfn); -} - -static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index) -{ - uint32_t feat; - uint64_t addr; - QVirtQueuePCI *vqpci; - - vqpci = g_malloc0(sizeof(*vqpci)); - feat = qvirtio_pci_get_guest_features(d); - - qvirtio_pci_queue_select(d, index); - vqpci->vq.index = index; - vqpci->vq.size = qvirtio_pci_get_queue_size(d); - vqpci->vq.free_head = 0; - vqpci->vq.num_free = vqpci->vq.size; - vqpci->vq.align = QVIRTIO_PCI_ALIGN; - vqpci->vq.indirect = (feat & QVIRTIO_F_RING_INDIRECT_DESC) != 0; - vqpci->vq.event = (feat & QVIRTIO_F_RING_EVENT_IDX) != 0; - - vqpci->msix_entry = -1; - vqpci->msix_addr = 0; - vqpci->msix_data = 0x12345678; - - /* Check different than 0 */ - g_assert_cmpint(vqpci->vq.size, !=, 0); - - /* Check power of 2 */ - g_assert_cmpint(vqpci->vq.size & (vqpci->vq.size - 1), ==, 0); - - addr = guest_alloc(alloc, qvring_size(vqpci->vq.size, QVIRTIO_PCI_ALIGN)); - qvring_init(alloc, &vqpci->vq, addr); - qvirtio_pci_set_queue_address(d, vqpci->vq.desc / QVIRTIO_PCI_ALIGN); - - return &vqpci->vq; -} - -static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writew(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_NOTIFY, vq->index); -} - -const QVirtioBus qvirtio_pci = { - .config_readb = qvirtio_pci_config_readb, - .config_readw = qvirtio_pci_config_readw, - .config_readl = qvirtio_pci_config_readl, - .config_readq = qvirtio_pci_config_readq, - .get_features = qvirtio_pci_get_features, - .set_features = qvirtio_pci_set_features, - .get_guest_features = qvirtio_pci_get_guest_features, - .get_status = qvirtio_pci_get_status, - .set_status = qvirtio_pci_set_status, - .get_queue_isr_status = qvirtio_pci_get_queue_isr_status, - .get_config_isr_status = qvirtio_pci_get_config_isr_status, - .queue_select = qvirtio_pci_queue_select, - .get_queue_size = qvirtio_pci_get_queue_size, - .set_queue_address = qvirtio_pci_set_queue_address, - .virtqueue_setup = qvirtio_pci_virtqueue_setup, - .virtqueue_kick = qvirtio_pci_virtqueue_kick, -}; - -void qvirtio_pci_foreach(QPCIBus *bus, uint16_t device_type, - void (*func)(QVirtioDevice *d, void *data), void *data) -{ - QVirtioPCIForeachData d = { .func = func, - .device_type = device_type, - .user_data = data }; - - qpci_device_foreach(bus, QVIRTIO_VENDOR_ID, -1, - qvirtio_pci_foreach_callback, &d); -} - -QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type) -{ - QVirtioPCIDevice *dev = NULL; - qvirtio_pci_foreach(bus, device_type, qvirtio_pci_assign_device, &dev); - - return dev; -} - -void qvirtio_pci_device_enable(QVirtioPCIDevice *d) -{ - qpci_device_enable(d->pdev); - d->addr = qpci_iomap(d->pdev, 0, NULL); - g_assert(d->addr != NULL); -} - -void qvirtio_pci_device_disable(QVirtioPCIDevice *d) -{ - qpci_iounmap(d->pdev, d->addr); - d->addr = NULL; -} - -void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci, - QGuestAllocator *alloc, uint16_t entry) -{ - uint16_t vector; - uint32_t control; - void *addr; - - g_assert(d->pdev->msix_enabled); - addr = d->pdev->msix_table + (entry * 16); - - g_assert_cmpint(entry, >=, 0); - g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev)); - vqpci->msix_entry = entry; - - vqpci->msix_addr = guest_alloc(alloc, 4); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_LOWER_ADDR, - vqpci->msix_addr & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_UPPER_ADDR, - (vqpci->msix_addr >> 32) & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_DATA, vqpci->msix_data); - - control = qpci_io_readl(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL, - control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); - - qvirtio_pci_queue_select(&d->vdev, vqpci->vq.index); - qpci_io_writew(d->pdev, d->addr + QVIRTIO_PCI_MSIX_QUEUE_VECTOR, entry); - vector = qpci_io_readw(d->pdev, d->addr + QVIRTIO_PCI_MSIX_QUEUE_VECTOR); - g_assert_cmphex(vector, !=, QVIRTIO_MSI_NO_VECTOR); -} - -void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d, - QGuestAllocator *alloc, uint16_t entry) -{ - uint16_t vector; - uint32_t control; - void *addr; - - g_assert(d->pdev->msix_enabled); - addr = d->pdev->msix_table + (entry * 16); - - g_assert_cmpint(entry, >=, 0); - g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev)); - d->config_msix_entry = entry; - - d->config_msix_data = 0x12345678; - d->config_msix_addr = guest_alloc(alloc, 4); - - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_LOWER_ADDR, - d->config_msix_addr & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_UPPER_ADDR, - (d->config_msix_addr >> 32) & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_DATA, d->config_msix_data); - - control = qpci_io_readl(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL, - control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); - - qpci_io_writew(d->pdev, d->addr + QVIRTIO_PCI_MSIX_CONF_VECTOR, entry); - vector = qpci_io_readw(d->pdev, d->addr + QVIRTIO_PCI_MSIX_CONF_VECTOR); - g_assert_cmphex(vector, !=, QVIRTIO_MSI_NO_VECTOR); -} diff --git a/qemu/tests/libqos/virtio-pci.h b/qemu/tests/libqos/virtio-pci.h deleted file mode 100644 index 8f0e52ad4..000000000 --- a/qemu/tests/libqos/virtio-pci.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * libqos virtio PCI definitions - * - * Copyright (c) 2014 Marc Marí - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef LIBQOS_VIRTIO_PCI_H -#define LIBQOS_VIRTIO_PCI_H - -#include "libqos/virtio.h" -#include "libqos/pci.h" - -#define QVIRTIO_PCI_DEVICE_FEATURES 0x00 -#define QVIRTIO_PCI_GUEST_FEATURES 0x04 -#define QVIRTIO_PCI_QUEUE_ADDRESS 0x08 -#define QVIRTIO_PCI_QUEUE_SIZE 0x0C -#define QVIRTIO_PCI_QUEUE_SELECT 0x0E -#define QVIRTIO_PCI_QUEUE_NOTIFY 0x10 -#define QVIRTIO_PCI_DEVICE_STATUS 0x12 -#define QVIRTIO_PCI_ISR_STATUS 0x13 -#define QVIRTIO_PCI_MSIX_CONF_VECTOR 0x14 -#define QVIRTIO_PCI_MSIX_QUEUE_VECTOR 0x16 -#define QVIRTIO_PCI_DEVICE_SPECIFIC_MSIX 0x18 -#define QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX 0x14 - -#define QVIRTIO_PCI_ALIGN 4096 - -#define QVIRTIO_MSI_NO_VECTOR 0xFFFF - -typedef struct QVirtioPCIDevice { - QVirtioDevice vdev; - QPCIDevice *pdev; - void *addr; - uint16_t config_msix_entry; - uint64_t config_msix_addr; - uint32_t config_msix_data; -} QVirtioPCIDevice; - -typedef struct QVirtQueuePCI { - QVirtQueue vq; - uint16_t msix_entry; - uint64_t msix_addr; - uint32_t msix_data; -} QVirtQueuePCI; - -extern const QVirtioBus qvirtio_pci; - -void qvirtio_pci_foreach(QPCIBus *bus, uint16_t device_type, - void (*func)(QVirtioDevice *d, void *data), void *data); -QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type); -void qvirtio_pci_device_enable(QVirtioPCIDevice *d); -void qvirtio_pci_device_disable(QVirtioPCIDevice *d); - -void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d, - QGuestAllocator *alloc, uint16_t entry); -void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci, - QGuestAllocator *alloc, uint16_t entry); -#endif diff --git a/qemu/tests/libqos/virtio.c b/qemu/tests/libqos/virtio.c deleted file mode 100644 index 613decea5..000000000 --- a/qemu/tests/libqos/virtio.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * libqos virtio driver - * - * Copyright (c) 2014 Marc Marí - * - * 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 "libqtest.h" -#include "libqos/virtio.h" - -uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) -{ - return bus->config_readb(d, addr); -} - -uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) -{ - return bus->config_readw(d, addr); -} - -uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) -{ - return bus->config_readl(d, addr); -} - -uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) -{ - return bus->config_readq(d, addr); -} - -uint32_t qvirtio_get_features(const QVirtioBus *bus, QVirtioDevice *d) -{ - return bus->get_features(d); -} - -void qvirtio_set_features(const QVirtioBus *bus, QVirtioDevice *d, - uint32_t features) -{ - bus->set_features(d, features); -} - -QVirtQueue *qvirtqueue_setup(const QVirtioBus *bus, QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index) -{ - return bus->virtqueue_setup(d, alloc, index); -} - -void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d) -{ - bus->set_status(d, QVIRTIO_RESET); - g_assert_cmphex(bus->get_status(d), ==, QVIRTIO_RESET); -} - -void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d) -{ - bus->set_status(d, bus->get_status(d) | QVIRTIO_ACKNOWLEDGE); - g_assert_cmphex(bus->get_status(d), ==, QVIRTIO_ACKNOWLEDGE); -} - -void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d) -{ - bus->set_status(d, bus->get_status(d) | QVIRTIO_DRIVER); - g_assert_cmphex(bus->get_status(d), ==, - QVIRTIO_DRIVER | QVIRTIO_ACKNOWLEDGE); -} - -void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d) -{ - bus->set_status(d, bus->get_status(d) | QVIRTIO_DRIVER_OK); - g_assert_cmphex(bus->get_status(d), ==, - QVIRTIO_DRIVER_OK | QVIRTIO_DRIVER | QVIRTIO_ACKNOWLEDGE); -} - -void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d, - QVirtQueue *vq, gint64 timeout_us) -{ - gint64 start_time = g_get_monotonic_time(); - - for (;;) { - clock_step(100); - if (bus->get_queue_isr_status(d, vq)) { - return; - } - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - } -} - -/* Wait for the status byte at given guest memory address to be set - * - * The virtqueue interrupt must not be raised, making this useful for testing - * event_index functionality. - */ -uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus, - QVirtioDevice *d, - QVirtQueue *vq, - uint64_t addr, - gint64 timeout_us) -{ - gint64 start_time = g_get_monotonic_time(); - uint8_t val; - - while ((val = readb(addr)) == 0xff) { - clock_step(100); - g_assert(!bus->get_queue_isr_status(d, vq)); - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - } - return val; -} - -void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d, - gint64 timeout_us) -{ - gint64 start_time = g_get_monotonic_time(); - - for (;;) { - clock_step(100); - if (bus->get_config_isr_status(d)) { - return; - } - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - } -} - -void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr) -{ - int i; - - vq->desc = addr; - vq->avail = vq->desc + vq->size*sizeof(QVRingDesc); - vq->used = (uint64_t)((vq->avail + sizeof(uint16_t) * (3 + vq->size) - + vq->align - 1) & ~(vq->align - 1)); - - for (i = 0; i < vq->size - 1; i++) { - /* vq->desc[i].addr */ - writew(vq->desc + (16 * i), 0); - /* vq->desc[i].next */ - writew(vq->desc + (16 * i) + 14, i + 1); - } - - /* vq->avail->flags */ - writew(vq->avail, 0); - /* vq->avail->idx */ - writew(vq->avail + 2, 0); - /* vq->avail->used_event */ - writew(vq->avail + 4 + (2 * vq->size), 0); - - /* vq->used->flags */ - writew(vq->used, 0); - /* vq->used->avail_event */ - writew(vq->used+2+(sizeof(struct QVRingUsedElem)*vq->size), 0); -} - -QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t elem) -{ - int i; - QVRingIndirectDesc *indirect = g_malloc(sizeof(*indirect)); - - indirect->index = 0; - indirect->elem = elem; - indirect->desc = guest_alloc(alloc, sizeof(QVRingDesc)*elem); - - for (i = 0; i < elem - 1; ++i) { - /* indirect->desc[i].addr */ - writeq(indirect->desc + (16 * i), 0); - /* indirect->desc[i].flags */ - writew(indirect->desc + (16 * i) + 12, QVRING_DESC_F_NEXT); - /* indirect->desc[i].next */ - writew(indirect->desc + (16 * i) + 14, i + 1); - } - - return indirect; -} - -void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data, - uint32_t len, bool write) -{ - uint16_t flags; - - g_assert_cmpint(indirect->index, <, indirect->elem); - - flags = readw(indirect->desc + (16 * indirect->index) + 12); - - if (write) { - flags |= QVRING_DESC_F_WRITE; - } - - /* indirect->desc[indirect->index].addr */ - writeq(indirect->desc + (16 * indirect->index), data); - /* indirect->desc[indirect->index].len */ - writel(indirect->desc + (16 * indirect->index) + 8, len); - /* indirect->desc[indirect->index].flags */ - writew(indirect->desc + (16 * indirect->index) + 12, flags); - - indirect->index++; -} - -uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, - bool next) -{ - uint16_t flags = 0; - vq->num_free--; - - if (write) { - flags |= QVRING_DESC_F_WRITE; - } - - if (next) { - flags |= QVRING_DESC_F_NEXT; - } - - /* vq->desc[vq->free_head].addr */ - writeq(vq->desc + (16 * vq->free_head), data); - /* vq->desc[vq->free_head].len */ - writel(vq->desc + (16 * vq->free_head) + 8, len); - /* vq->desc[vq->free_head].flags */ - writew(vq->desc + (16 * vq->free_head) + 12, flags); - - return vq->free_head++; /* Return and increase, in this order */ -} - -uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect) -{ - g_assert(vq->indirect); - g_assert_cmpint(vq->size, >=, indirect->elem); - g_assert_cmpint(indirect->index, ==, indirect->elem); - - vq->num_free--; - - /* vq->desc[vq->free_head].addr */ - writeq(vq->desc + (16 * vq->free_head), indirect->desc); - /* vq->desc[vq->free_head].len */ - writel(vq->desc + (16 * vq->free_head) + 8, - sizeof(QVRingDesc) * indirect->elem); - /* vq->desc[vq->free_head].flags */ - writew(vq->desc + (16 * vq->free_head) + 12, QVRING_DESC_F_INDIRECT); - - return vq->free_head++; /* Return and increase, in this order */ -} - -void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq, - uint32_t free_head) -{ - /* vq->avail->idx */ - uint16_t idx = readl(vq->avail + 2); - /* vq->used->flags */ - uint16_t flags; - /* vq->used->avail_event */ - uint16_t avail_event; - - /* vq->avail->ring[idx % vq->size] */ - writel(vq->avail + 4 + (2 * (idx % vq->size)), free_head); - /* vq->avail->idx */ - writel(vq->avail + 2, idx + 1); - - /* Must read after idx is updated */ - flags = readw(vq->avail); - avail_event = readw(vq->used + 4 + - (sizeof(struct QVRingUsedElem) * vq->size)); - - /* < 1 because we add elements to avail queue one by one */ - if ((flags & QVRING_USED_F_NO_NOTIFY) == 0 && - (!vq->event || (uint16_t)(idx-avail_event) < 1)) { - bus->virtqueue_kick(d, vq); - } -} - -void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx) -{ - g_assert(vq->event); - - /* vq->avail->used_event */ - writew(vq->avail + 4 + (2 * vq->size), idx); -} diff --git a/qemu/tests/libqos/virtio.h b/qemu/tests/libqos/virtio.h deleted file mode 100644 index 01012787b..000000000 --- a/qemu/tests/libqos/virtio.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * libqos virtio definitions - * - * Copyright (c) 2014 Marc Marí - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef LIBQOS_VIRTIO_H -#define LIBQOS_VIRTIO_H - -#include "libqos/malloc.h" - -#define QVIRTIO_VENDOR_ID 0x1AF4 - -#define QVIRTIO_RESET 0x0 -#define QVIRTIO_ACKNOWLEDGE 0x1 -#define QVIRTIO_DRIVER 0x2 -#define QVIRTIO_DRIVER_OK 0x4 - -#define QVIRTIO_NET_DEVICE_ID 0x1 -#define QVIRTIO_BLK_DEVICE_ID 0x2 -#define QVIRTIO_CONSOLE_DEVICE_ID 0x3 -#define QVIRTIO_RNG_DEVICE_ID 0x4 -#define QVIRTIO_BALLOON_DEVICE_ID 0x5 -#define QVIRTIO_RPMSG_DEVICE_ID 0x7 -#define QVIRTIO_SCSI_DEVICE_ID 0x8 -#define QVIRTIO_9P_DEVICE_ID 0x9 - -#define QVIRTIO_F_NOTIFY_ON_EMPTY 0x01000000 -#define QVIRTIO_F_ANY_LAYOUT 0x08000000 -#define QVIRTIO_F_RING_INDIRECT_DESC 0x10000000 -#define QVIRTIO_F_RING_EVENT_IDX 0x20000000 -#define QVIRTIO_F_BAD_FEATURE 0x40000000 - -#define QVRING_DESC_F_NEXT 0x1 -#define QVRING_DESC_F_WRITE 0x2 -#define QVRING_DESC_F_INDIRECT 0x4 - -#define QVIRTIO_F_NOTIFY_ON_EMPTY 0x01000000 -#define QVIRTIO_F_ANY_LAYOUT 0x08000000 -#define QVIRTIO_F_RING_INDIRECT_DESC 0x10000000 -#define QVIRTIO_F_RING_EVENT_IDX 0x20000000 -#define QVIRTIO_F_BAD_FEATURE 0x40000000 - -#define QVRING_AVAIL_F_NO_INTERRUPT 1 - -#define QVRING_USED_F_NO_NOTIFY 1 - -typedef struct QVirtioDevice { - /* Device type */ - uint16_t device_type; -} QVirtioDevice; - -typedef struct QVRingDesc { - uint64_t addr; - uint32_t len; - uint16_t flags; - uint16_t next; -} QVRingDesc; - -typedef struct QVRingAvail { - uint16_t flags; - uint16_t idx; - uint16_t ring[0]; /* This is an array of uint16_t */ - uint16_t used_event; -} QVRingAvail; - -typedef struct QVRingUsedElem { - uint32_t id; - uint32_t len; -} QVRingUsedElem; - -typedef struct QVRingUsed { - uint16_t flags; - uint16_t idx; - QVRingUsedElem ring[0]; /* This is an array of QVRingUsedElem structs */ - uint16_t avail_event; -} QVRingUsed; - -typedef struct QVirtQueue { - uint64_t desc; /* This points to an array of QVRingDesc */ - uint64_t avail; /* This points to a QVRingAvail */ - uint64_t used; /* This points to a QVRingDesc */ - uint16_t index; - uint32_t size; - uint32_t free_head; - uint32_t num_free; - uint32_t align; - bool indirect; - bool event; -} QVirtQueue; - -typedef struct QVRingIndirectDesc { - uint64_t desc; /* This points to an array fo QVRingDesc */ - uint16_t index; - uint16_t elem; -} QVRingIndirectDesc; - -typedef struct QVirtioBus { - uint8_t (*config_readb)(QVirtioDevice *d, uint64_t addr); - uint16_t (*config_readw)(QVirtioDevice *d, uint64_t addr); - uint32_t (*config_readl)(QVirtioDevice *d, uint64_t addr); - uint64_t (*config_readq)(QVirtioDevice *d, uint64_t addr); - - /* Get features of the device */ - uint32_t (*get_features)(QVirtioDevice *d); - - /* Set features of the device */ - void (*set_features)(QVirtioDevice *d, uint32_t features); - - /* Get features of the guest */ - uint32_t (*get_guest_features)(QVirtioDevice *d); - - /* Get status of the device */ - uint8_t (*get_status)(QVirtioDevice *d); - - /* Set status of the device */ - void (*set_status)(QVirtioDevice *d, uint8_t status); - - /* Get the queue ISR status of the device */ - bool (*get_queue_isr_status)(QVirtioDevice *d, QVirtQueue *vq); - - /* Get the configuration ISR status of the device */ - bool (*get_config_isr_status)(QVirtioDevice *d); - - /* Select a queue to work on */ - void (*queue_select)(QVirtioDevice *d, uint16_t index); - - /* Get the size of the selected queue */ - uint16_t (*get_queue_size)(QVirtioDevice *d); - - /* Set the address of the selected queue */ - void (*set_queue_address)(QVirtioDevice *d, uint32_t pfn); - - /* Setup the virtqueue specified by index */ - QVirtQueue *(*virtqueue_setup)(QVirtioDevice *d, QGuestAllocator *alloc, - uint16_t index); - - /* Notify changes in virtqueue */ - void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq); -} QVirtioBus; - -static inline uint32_t qvring_size(uint32_t num, uint32_t align) -{ - return ((sizeof(struct QVRingDesc) * num + sizeof(uint16_t) * (3 + num) - + align - 1) & ~(align - 1)) - + sizeof(uint16_t) * 3 + sizeof(struct QVRingUsedElem) * num; -} - -uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint32_t qvirtio_get_features(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_features(const QVirtioBus *bus, QVirtioDevice *d, - uint32_t features); - -void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d); - -void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d, - QVirtQueue *vq, gint64 timeout_us); -uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus, - QVirtioDevice *d, - QVirtQueue *vq, - uint64_t addr, - gint64 timeout_us); -void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d, - gint64 timeout_us); -QVirtQueue *qvirtqueue_setup(const QVirtioBus *bus, QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index); - -void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr); -QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t elem); -void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data, - uint32_t len, bool write); -uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, - bool next); -uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect); -void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq, - uint32_t free_head); - -void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); -#endif |