diff options
author | Thomas Huth <thuth@redhat.com> | 2019-09-10 16:41:20 +0200 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2020-01-12 11:42:41 +0100 |
commit | 1cf4323ecd03235984e43a416a42f10c975cf785 (patch) | |
tree | 57ad5475a4cbbbe0088aecf86b682d8e11150b9f /tests/libqos | |
parent | 833884f37adc9f125fa2f345704d7019b8651619 (diff) | |
download | qemu-1cf4323ecd03235984e43a416a42f10c975cf785.zip |
tests/libqos: Move the libqos files under tests/qtest/
The qos stuff belongs to qtest, so move it into that directory, too.
Message-Id: <20191218103059.11729-8-thuth@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'tests/libqos')
70 files changed, 0 insertions, 11220 deletions
diff --git a/tests/libqos/aarch64-xlnx-zcu102-machine.c b/tests/libqos/aarch64-xlnx-zcu102-machine.c deleted file mode 100644 index 1d5de5af00..0000000000 --- a/tests/libqos/aarch64-xlnx-zcu102-machine.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "sdhci.h" - -typedef struct QXlnxZCU102Machine QXlnxZCU102Machine; - -struct QXlnxZCU102Machine { - QOSGraphObject obj; - QGuestAllocator alloc; - QSDHCI_MemoryMapped sdhci; -}; - -#define ARM_PAGE_SIZE 4096 -#define XLNX_ZCU102_RAM_ADDR 0 -#define XLNX_ZCU102_RAM_SIZE 0x20000000 - -static void *xlnx_zcu102_get_driver(void *object, const char *interface) -{ - QXlnxZCU102Machine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in aarch64/xlnx-zcu102\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *xlnx_zcu102_get_device(void *obj, const char *device) -{ - QXlnxZCU102Machine *machine = obj; - if (!g_strcmp0(device, "generic-sdhci")) { - return &machine->sdhci.obj; - } - - fprintf(stderr, "%s not present in aarch64/xlnx-zcu102\n", device); - g_assert_not_reached(); -} - -static void xlnx_zcu102_destructor(QOSGraphObject *obj) -{ - QXlnxZCU102Machine *machine = (QXlnxZCU102Machine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_aarch64_xlnx_zcu102(QTestState *qts) -{ - QXlnxZCU102Machine *machine = g_new0(QXlnxZCU102Machine, 1); - - alloc_init(&machine->alloc, 0, - XLNX_ZCU102_RAM_ADDR + (1 << 20), - XLNX_ZCU102_RAM_ADDR + XLNX_ZCU102_RAM_SIZE, - ARM_PAGE_SIZE); - - machine->obj.get_device = xlnx_zcu102_get_device; - machine->obj.get_driver = xlnx_zcu102_get_driver; - machine->obj.destructor = xlnx_zcu102_destructor; - /* Datasheet: UG1085 (v1.7) */ - qos_init_sdhci_mm(&machine->sdhci, qts, 0xff160000, &(QSDHCIProperties) { - .version = 3, - .baseclock = 0, - .capab.sdma = true, - .capab.reg = 0x280737ec6481 - }); - return &machine->obj; -} - -static void xlnx_zcu102_register_nodes(void) -{ - qos_node_create_machine("aarch64/xlnx-zcu102", - qos_create_machine_aarch64_xlnx_zcu102); - qos_node_contains("aarch64/xlnx-zcu102", "generic-sdhci", NULL); -} - -libqos_init(xlnx_zcu102_register_nodes); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c deleted file mode 100644 index cc1b08eabe..0000000000 --- a/tests/libqos/ahci.c +++ /dev/null @@ -1,1242 +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 "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; - uint8_t errors; - uint32_t interrupts; - uint64_t xbytes; - uint32_t prd_size; - uint32_t sector_size; - uint64_t buffer; - AHCICommandProp *props; - /* Data to be transferred to the guest */ - 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(QTestState *qts, uint32_t *fingerprint) -{ - QPCIDevice *ahci; - uint32_t ahci_fingerprint; - QPCIBus *pcibus; - - pcibus = qpci_new_pc(qts, NULL); - - /* 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_bar = qpci_iomap(ahci->dev, 5, &ahci->barsize); - - /* 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); - qtest_memset(ahci->parent->qts, 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); - qtest_memset(ahci->parent->qts, 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); - - ahci->enabled = true; - /* 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 */ - qtest_memset(ahci->parent->qts, ahci->port[port].fb, 0x00, 0x100); -} - -/** - * Check a port for errors. - */ -void ahci_port_check_error(AHCIQState *ahci, uint8_t port, - uint32_t imask, uint8_t emask) -{ - uint32_t reg; - - /* The upper 9 bits of the IS register all indicate errors. */ - reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); - reg &= ~imask; - 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); - if (!emask) { - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); - } else { - ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_ERR); - } - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR & (~emask << 8)); - ASSERT_BIT_SET(reg, AHCI_PX_TFD_ERR & (emask << 8)); -} - -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; - - qtest_memread(ahci->parent->qts, 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, AHCICommand *cmd) -{ - PIOSetupFIS *pio = g_malloc0(0x20); - uint8_t port = cmd->port; - - /* We cannot check the Status or E_Status registers, because - * the status may have again changed between the PIO Setup FIS - * and the conclusion of the command with the D2H Register FIS. */ - qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x20, pio, 0x20); - g_assert_cmphex(pio->fis_type, ==, 0x5f); - - /* Data transferred by PIO will either be: - * (1) 12 or 16 bytes for an ATAPI command packet (QEMU always uses 12), or - * (2) Actual data from the drive. - * If we do both, (2) winds up erasing any evidence of (1). - */ - if (cmd->props->atapi && (cmd->xbytes == 0 || cmd->props->dma)) { - g_assert(le16_to_cpu(pio->tx_count) == 12 || - le16_to_cpu(pio->tx_count) == 16); - } else { - /* The AHCI test suite here does not test any PIO command that specifies - * a DRQ block larger than one sector (like 0xC4), so this should always - * be one sector or less. */ - size_t pio_len = ((cmd->xbytes % cmd->sector_size) ? - (cmd->xbytes % cmd->sector_size) : cmd->sector_size); - g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, pio_len); - } - g_free(pio); -} - -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); - qtest_memread(ahci->parent->qts, 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); - - qtest_memwrite(ahci->parent->qts, 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); - } - - qtest_memwrite(ahci->parent->qts, 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); - qtest_memset(ahci->parent->qts, opts->buffer, 0x00, opts->size); - } - - /* Command creation */ - if (opts->atapi) { - uint16_t bcl = opts->set_bcl ? opts->bcl : ATAPI_SECTOR_SIZE; - cmd = ahci_atapi_command_create(op, bcl, opts->atapi_dma); - } 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) { - qtest_qmp_eventwait(ahci->parent->qts, "STOP"); - } - if (opts->mid_cb) { - rc = opts->mid_cb(ahci, cmd, opts); - g_assert_cmpint(rc, ==, 0); - } - if (opts->error) { - qtest_qmp_send(ahci->parent->qts, "{'execute':'cont' }"); - qtest_qmp_eventwait(ahci->parent->qts, "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); - qtest_qmp_eventwait(ahci->parent->qts, "STOP"); - - return cmd; -} - -/* Resume a previously failed command and verify/finalize */ -void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd) -{ - /* Complete the command */ - qtest_qmp_send(ahci->parent->qts, "{'execute':'cont' }"); - qtest_qmp_eventwait(ahci->parent->qts, "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); - qtest_memset(ahci->parent->qts, ptr, 0x00, bufsize); - - if (bufsize && props->write) { - qtest_bufwrite(ahci->parent->qts, ptr, buffer, bufsize); - } - - ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector); - - if (bufsize && props->read) { - qtest_bufread(ahci->parent->qts, 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 / cmd->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 / cmd->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; - /* PIO is still used to transfer the ATAPI command */ - g_assert(cmd->props->pio); - cmd->props->dma = true; - /* 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_new0(AHCICommand, 1); - g_assert(!(props->dma && props->pio) || props->atapi); - g_assert(!(props->lba28 && props->lba48)); - g_assert(!(props->read && props->write)); - g_assert(!props->size || props->data); - 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; - cmd->sector_size = props->atapi ? ATAPI_SECTOR_SIZE : AHCI_SECTOR_SIZE; - - 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->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, uint16_t bcl, bool dma) -{ - AHCICommand *cmd = ahci_command_create(CMD_PACKET); - cmd->atapi_cmd = g_malloc0(16); - cmd->atapi_cmd[0] = scsi_cmd; - stw_le_p(&cmd->fis.lba_lo[1], bcl); - if (dma) { - ahci_command_enable_atapi_dma(cmd); - } else { - cmd->interrupts |= bcl ? AHCI_PX_IS_PSS : 0; - } - return cmd; -} - -void ahci_atapi_test_ready(AHCIQState *ahci, uint8_t port, - bool ready, uint8_t expected_sense) -{ - AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_TEST_UNIT_READY, 0, false); - ahci_command_set_size(cmd, 0); - if (!ready) { - cmd->interrupts |= AHCI_PX_IS_TFES; - cmd->errors |= expected_sense << 4; - } - ahci_command_commit(ahci, cmd, port); - ahci_command_issue(ahci, cmd); - ahci_command_verify(ahci, cmd); - ahci_command_free(cmd); -} - -static int copy_buffer(AHCIQState *ahci, AHCICommand *cmd, - const AHCIOpts *opts) -{ - unsigned char *rx = opts->opaque; - qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size); - return 0; -} - -void ahci_atapi_get_sense(AHCIQState *ahci, uint8_t port, - uint8_t *sense, uint8_t *asc) -{ - unsigned char *rx; - AHCIOpts opts = { - .size = 18, - .atapi = true, - .post_cb = copy_buffer, - }; - rx = g_malloc(18); - opts.opaque = rx; - - ahci_exec(ahci, port, CMD_ATAPI_REQUEST_SENSE, &opts); - - *sense = rx[2]; - *asc = rx[12]; - - g_free(rx); -} - -void ahci_atapi_eject(AHCIQState *ahci, uint8_t port) -{ - AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_START_STOP_UNIT, 0, false); - ahci_command_set_size(cmd, 0); - - cmd->atapi_cmd[4] = 0x02; /* loej = true */ - ahci_command_commit(ahci, cmd, port); - ahci_command_issue(ahci, cmd); - ahci_command_verify(ahci, cmd); - ahci_command_free(cmd); -} - -void ahci_atapi_load(AHCIQState *ahci, uint8_t port) -{ - AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_START_STOP_UNIT, 0, false); - ahci_command_set_size(cmd, 0); - - cmd->atapi_cmd[4] = 0x03; /* loej,start = true */ - ahci_command_commit(ahci, cmd, port); - ahci_command_issue(ahci, cmd); - ahci_command_verify(ahci, cmd); - ahci_command_free(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: - case CMD_ATAPI_READ_CD: - g_assert_cmpuint(lba, <=, UINT32_MAX); - stl_be_p(&cbd[2], lba); - break; - case CMD_ATAPI_REQUEST_SENSE: - case CMD_ATAPI_TEST_UNIT_READY: - case CMD_ATAPI_START_STOP_UNIT: - g_assert_cmpuint(lba, ==, 0x00); - break; - default: - /* SCSI doesn't have uniform packet formats, - * so you have to add support for it manually. Sorry! */ - fprintf(stderr, "The Libqos AHCI driver does not support the " - "set_offset operation for ATAPI command 0x%02x, " - "please add support.\n", - cbd[0]); - 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 / ATAPI_SECTOR_SIZE; - uint32_t tmp; - g_assert(cbd); - - switch (cbd[0]) { - case CMD_ATAPI_READ_10: - g_assert_cmpuint(nsectors, <=, UINT16_MAX); - stw_be_p(&cbd[7], nsectors); - break; - case CMD_ATAPI_READ_CD: - /* 24bit BE store */ - g_assert_cmpuint(nsectors, <, 1ULL << 24); - tmp = nsectors; - cbd[6] = (tmp & 0xFF0000) >> 16; - cbd[7] = (tmp & 0xFF00) >> 8; - cbd[8] = (tmp & 0xFF); - break; - case CMD_ATAPI_REQUEST_SENSE: - g_assert_cmpuint(xbytes, <=, UINT8_MAX); - cbd[4] = (uint8_t)xbytes; - break; - case CMD_ATAPI_TEST_UNIT_READY: - case CMD_ATAPI_START_STOP_UNIT: - g_assert_cmpuint(xbytes, ==, 0); - break; - default: - /* SCSI doesn't have uniform packet formats, - * so you have to add support for it manually. Sorry! */ - fprintf(stderr, "The Libqos AHCI driver does not support the set_size " - "operation for ATAPI command 0x%02x, please add support.\n", - cbd[0]); - 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 / cmd->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 { - /* For writes, the PIO Setup FIS interrupt only comes from DRQs - * after the first. - */ - if (cmd->props->pio && sect_count > (cmd->props->read ? 0 : 1)) { - cmd->interrupts |= AHCI_PX_IS_PSS; - } - 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) { - qtest_memwrite(ahci->parent->qts, 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 */ - qtest_memwrite(ahci->parent->qts, 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, cmd->interrupts, cmd->errors); - 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, cmd); - } -} - -uint8_t ahci_command_slot(AHCICommand *cmd) -{ - return cmd->slot; -} diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h deleted file mode 100644 index f05b3e5fce..0000000000 --- a/tests/libqos/ahci.h +++ /dev/null @@ -1,651 +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_TEST_UNIT_READY = 0x00, - CMD_ATAPI_REQUEST_SENSE = 0x03, - CMD_ATAPI_START_STOP_UNIT = 0x1b, - CMD_ATAPI_READ_10 = 0x28, - CMD_ATAPI_READ_CD = 0xbe, -}; - -enum { - SENSE_NO_SENSE = 0x00, - SENSE_NOT_READY = 0x02, - SENSE_UNIT_ATTENTION = 0x06, -}; - -enum { - ASC_MEDIUM_MAY_HAVE_CHANGED = 0x28, - ASC_MEDIUM_NOT_PRESENT = 0x3a, -}; - -/* 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; - QPCIBar hba_bar; - uint64_t barsize; - uint32_t fingerprint; - uint32_t cap; - uint32_t cap2; - AHCIPortQState port[32]; - bool enabled; -} 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; /* Size of transfer */ - unsigned prd_size; /* Size per-each PRD */ - bool set_bcl; /* Override the default BCL of ATAPI_SECTOR_SIZE */ - unsigned bcl; /* Byte Count Limit, for ATAPI PIO */ - uint64_t lba; /* Starting LBA offset */ - uint64_t buffer; /* Pointer to source or destination guest buffer */ - bool atapi; /* ATAPI command? */ - bool atapi_dma; /* Use DMA for ATAPI? */ - 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_bar, offset); -} - -static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value) -{ - qpci_io_writel(ahci->dev, ahci->hba_bar, 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(QTestState *qts, 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, - uint32_t imask, uint8_t emask); -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, AHCICommand *cmd); -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); -void ahci_atapi_test_ready(AHCIQState *ahci, uint8_t port, bool ready, - uint8_t expected_sense); -void ahci_atapi_get_sense(AHCIQState *ahci, uint8_t port, - uint8_t *sense, uint8_t *asc); -void ahci_atapi_eject(AHCIQState *ahci, uint8_t port); -void ahci_atapi_load(AHCIQState *ahci, uint8_t port); - -/* Command: Fine-grained lifecycle */ -AHCICommand *ahci_command_create(uint8_t command_name); -AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl, bool dma); -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/tests/libqos/arm-imx25-pdk-machine.c b/tests/libqos/arm-imx25-pdk-machine.c deleted file mode 100644 index 25066fb8a9..0000000000 --- a/tests/libqos/arm-imx25-pdk-machine.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2019 Red Hat, Inc. - * - * Author: Paolo Bonzini <pbonzini@redhat.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "libqos/i2c.h" - -#define ARM_PAGE_SIZE 4096 -#define IMX25_PDK_RAM_START 0x80000000 -#define IMX25_PDK_RAM_END 0x88000000 - -typedef struct QIMX25PDKMachine QIMX25PDKMachine; - -struct QIMX25PDKMachine { - QOSGraphObject obj; - QGuestAllocator alloc; - IMXI2C i2c_1; -}; - -static void *imx25_pdk_get_driver(void *object, const char *interface) -{ - QIMX25PDKMachine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/imx25_pdk\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *imx25_pdk_get_device(void *obj, const char *device) -{ - QIMX25PDKMachine *machine = obj; - if (!g_strcmp0(device, "imx.i2c")) { - return &machine->i2c_1.obj; - } - - fprintf(stderr, "%s not present in arm/imx25_pdk\n", device); - g_assert_not_reached(); -} - -static void imx25_pdk_destructor(QOSGraphObject *obj) -{ - QIMX25PDKMachine *machine = (QIMX25PDKMachine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_arm_imx25_pdk(QTestState *qts) -{ - QIMX25PDKMachine *machine = g_new0(QIMX25PDKMachine, 1); - - alloc_init(&machine->alloc, 0, - IMX25_PDK_RAM_START, - IMX25_PDK_RAM_END, - ARM_PAGE_SIZE); - machine->obj.get_device = imx25_pdk_get_device; - machine->obj.get_driver = imx25_pdk_get_driver; - machine->obj.destructor = imx25_pdk_destructor; - - imx_i2c_init(&machine->i2c_1, qts, 0x43f80000); - return &machine->obj; -} - -static void imx25_pdk_register_nodes(void) -{ - QOSGraphEdgeOptions edge = { - .extra_device_opts = "bus=i2c-bus.0" - }; - qos_node_create_machine("arm/imx25-pdk", qos_create_machine_arm_imx25_pdk); - qos_node_contains("arm/imx25-pdk", "imx.i2c", &edge, NULL); -} - -libqos_init(imx25_pdk_register_nodes); diff --git a/tests/libqos/arm-n800-machine.c b/tests/libqos/arm-n800-machine.c deleted file mode 100644 index 87279bdb26..0000000000 --- a/tests/libqos/arm-n800-machine.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2019 Red Hat, Inc. - * - * Author: Paolo Bonzini <pbonzini@redhat.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "libqos/i2c.h" - -#define ARM_PAGE_SIZE 4096 -#define N800_RAM_START 0x80000000 -#define N800_RAM_END 0x88000000 - -typedef struct QN800Machine QN800Machine; - -struct QN800Machine { - QOSGraphObject obj; - QGuestAllocator alloc; - OMAPI2C i2c_1; -}; - -static void *n800_get_driver(void *object, const char *interface) -{ - QN800Machine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/n800\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *n800_get_device(void *obj, const char *device) -{ - QN800Machine *machine = obj; - if (!g_strcmp0(device, "omap_i2c")) { - return &machine->i2c_1.obj; - } - - fprintf(stderr, "%s not present in arm/n800\n", device); - g_assert_not_reached(); -} - -static void n800_destructor(QOSGraphObject *obj) -{ - QN800Machine *machine = (QN800Machine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_arm_n800(QTestState *qts) -{ - QN800Machine *machine = g_new0(QN800Machine, 1); - - alloc_init(&machine->alloc, 0, - N800_RAM_START, - N800_RAM_END, - ARM_PAGE_SIZE); - machine->obj.get_device = n800_get_device; - machine->obj.get_driver = n800_get_driver; - machine->obj.destructor = n800_destructor; - - omap_i2c_init(&machine->i2c_1, qts, 0x48070000); - return &machine->obj; -} - -static void n800_register_nodes(void) -{ - QOSGraphEdgeOptions edge = { - .extra_device_opts = "bus=i2c-bus.0" - }; - qos_node_create_machine("arm/n800", qos_create_machine_arm_n800); - qos_node_contains("arm/n800", "omap_i2c", &edge, NULL); -} - -libqos_init(n800_register_nodes); diff --git a/tests/libqos/arm-raspi2-machine.c b/tests/libqos/arm-raspi2-machine.c deleted file mode 100644 index 12a7cb7e4b..0000000000 --- a/tests/libqos/arm-raspi2-machine.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "sdhci.h" - -#define ARM_PAGE_SIZE 4096 -#define RASPI2_RAM_ADDR 0 -#define RASPI2_RAM_SIZE 0x20000000 - -typedef struct QRaspi2Machine QRaspi2Machine; - -struct QRaspi2Machine { - QOSGraphObject obj; - QGuestAllocator alloc; - QSDHCI_MemoryMapped sdhci; -}; - -static void *raspi2_get_driver(void *object, const char *interface) -{ - QRaspi2Machine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/raspi2\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *raspi2_get_device(void *obj, const char *device) -{ - QRaspi2Machine *machine = obj; - if (!g_strcmp0(device, "generic-sdhci")) { - return &machine->sdhci.obj; - } - - fprintf(stderr, "%s not present in arm/raspi2\n", device); - g_assert_not_reached(); -} - -static void raspi2_destructor(QOSGraphObject *obj) -{ - QRaspi2Machine *machine = (QRaspi2Machine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_arm_raspi2(QTestState *qts) -{ - QRaspi2Machine *machine = g_new0(QRaspi2Machine, 1); - - alloc_init(&machine->alloc, 0, - RASPI2_RAM_ADDR + (1 << 20), - RASPI2_RAM_ADDR + RASPI2_RAM_SIZE, - ARM_PAGE_SIZE); - machine->obj.get_device = raspi2_get_device; - machine->obj.get_driver = raspi2_get_driver; - machine->obj.destructor = raspi2_destructor; - qos_init_sdhci_mm(&machine->sdhci, qts, 0x3f300000, &(QSDHCIProperties) { - .version = 3, - .baseclock = 52, - .capab.sdma = false, - .capab.reg = 0x052134b4 - }); - return &machine->obj; -} - -static void raspi2_register_nodes(void) -{ - qos_node_create_machine("arm/raspi2", qos_create_machine_arm_raspi2); - qos_node_contains("arm/raspi2", "generic-sdhci", NULL); -} - -libqos_init(raspi2_register_nodes); diff --git a/tests/libqos/arm-sabrelite-machine.c b/tests/libqos/arm-sabrelite-machine.c deleted file mode 100644 index e6df43795a..0000000000 --- a/tests/libqos/arm-sabrelite-machine.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "sdhci.h" - -#define ARM_PAGE_SIZE 4096 -#define SABRELITE_RAM_START 0x10000000 -#define SABRELITE_RAM_END 0x30000000 - -typedef struct QSabreliteMachine QSabreliteMachine; - -struct QSabreliteMachine { - QOSGraphObject obj; - QGuestAllocator alloc; - QSDHCI_MemoryMapped sdhci; -}; - -static void *sabrelite_get_driver(void *object, const char *interface) -{ - QSabreliteMachine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/sabrelite\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *sabrelite_get_device(void *obj, const char *device) -{ - QSabreliteMachine *machine = obj; - if (!g_strcmp0(device, "generic-sdhci")) { - return &machine->sdhci.obj; - } - - fprintf(stderr, "%s not present in arm/sabrelite\n", device); - g_assert_not_reached(); -} - -static void sabrelite_destructor(QOSGraphObject *obj) -{ - QSabreliteMachine *machine = (QSabreliteMachine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_arm_sabrelite(QTestState *qts) -{ - QSabreliteMachine *machine = g_new0(QSabreliteMachine, 1); - - alloc_init(&machine->alloc, 0, - SABRELITE_RAM_START, - SABRELITE_RAM_END, - ARM_PAGE_SIZE); - machine->obj.get_device = sabrelite_get_device; - machine->obj.get_driver = sabrelite_get_driver; - machine->obj.destructor = sabrelite_destructor; - qos_init_sdhci_mm(&machine->sdhci, qts, 0x02190000, &(QSDHCIProperties) { - .version = 3, - .baseclock = 0, - .capab.sdma = true, - .capab.reg = 0x057834b4, - }); - return &machine->obj; -} - -static void sabrelite_register_nodes(void) -{ - qos_node_create_machine("arm/sabrelite", qos_create_machine_arm_sabrelite); - qos_node_contains("arm/sabrelite", "generic-sdhci", NULL); -} - -libqos_init(sabrelite_register_nodes); diff --git a/tests/libqos/arm-smdkc210-machine.c b/tests/libqos/arm-smdkc210-machine.c deleted file mode 100644 index 215b628a7d..0000000000 --- a/tests/libqos/arm-smdkc210-machine.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "sdhci.h" - -#define ARM_PAGE_SIZE 4096 -#define SMDKC210_RAM_ADDR 0x40000000ull -#define SMDKC210_RAM_SIZE 0x40000000ull - -typedef struct QSmdkc210Machine QSmdkc210Machine; - -struct QSmdkc210Machine { - QOSGraphObject obj; - QGuestAllocator alloc; - QSDHCI_MemoryMapped sdhci; -}; - -static void *smdkc210_get_driver(void *object, const char *interface) -{ - QSmdkc210Machine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/smdkc210\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *smdkc210_get_device(void *obj, const char *device) -{ - QSmdkc210Machine *machine = obj; - if (!g_strcmp0(device, "generic-sdhci")) { - return &machine->sdhci.obj; - } - - fprintf(stderr, "%s not present in arm/smdkc210\n", device); - g_assert_not_reached(); -} - -static void smdkc210_destructor(QOSGraphObject *obj) -{ - QSmdkc210Machine *machine = (QSmdkc210Machine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_arm_smdkc210(QTestState *qts) -{ - QSmdkc210Machine *machine = g_new0(QSmdkc210Machine, 1); - - alloc_init(&machine->alloc, 0, - SMDKC210_RAM_ADDR, - SMDKC210_RAM_ADDR + SMDKC210_RAM_SIZE, - ARM_PAGE_SIZE); - machine->obj.get_device = smdkc210_get_device; - machine->obj.get_driver = smdkc210_get_driver; - machine->obj.destructor = smdkc210_destructor; - qos_init_sdhci_mm(&machine->sdhci, qts, 0x12510000, &(QSDHCIProperties) { - .version = 2, - .baseclock = 0, - .capab.sdma = true, - .capab.reg = 0x5e80080, - }); - return &machine->obj; -} - -static void smdkc210_register_nodes(void) -{ - qos_node_create_machine("arm/smdkc210", qos_create_machine_arm_smdkc210); - qos_node_contains("arm/smdkc210", "generic-sdhci", NULL); -} - -libqos_init(smdkc210_register_nodes); diff --git a/tests/libqos/arm-virt-machine.c b/tests/libqos/arm-virt-machine.c deleted file mode 100644 index 96ffe3ee5c..0000000000 --- a/tests/libqos/arm-virt-machine.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-mmio.h" - -#define ARM_PAGE_SIZE 4096 -#define VIRTIO_MMIO_BASE_ADDR 0x0A003E00 -#define ARM_VIRT_RAM_ADDR 0x40000000 -#define ARM_VIRT_RAM_SIZE 0x20000000 -#define VIRTIO_MMIO_SIZE 0x00000200 - -typedef struct QVirtMachine QVirtMachine; - -struct QVirtMachine { - QOSGraphObject obj; - QGuestAllocator alloc; - QVirtioMMIODevice virtio_mmio; -}; - -static void virt_destructor(QOSGraphObject *obj) -{ - QVirtMachine *machine = (QVirtMachine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *virt_get_driver(void *object, const char *interface) -{ - QVirtMachine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/virtio\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *virt_get_device(void *obj, const char *device) -{ - QVirtMachine *machine = obj; - if (!g_strcmp0(device, "virtio-mmio")) { - return &machine->virtio_mmio.obj; - } - - fprintf(stderr, "%s not present in arm/virtio\n", device); - g_assert_not_reached(); -} - -static void *qos_create_machine_arm_virt(QTestState *qts) -{ - QVirtMachine *machine = g_new0(QVirtMachine, 1); - - alloc_init(&machine->alloc, 0, - ARM_VIRT_RAM_ADDR, - ARM_VIRT_RAM_ADDR + ARM_VIRT_RAM_SIZE, - ARM_PAGE_SIZE); - qvirtio_mmio_init_device(&machine->virtio_mmio, qts, VIRTIO_MMIO_BASE_ADDR, - VIRTIO_MMIO_SIZE); - - machine->obj.get_device = virt_get_device; - machine->obj.get_driver = virt_get_driver; - machine->obj.destructor = virt_destructor; - return machine; -} - -static void virtio_mmio_register_nodes(void) -{ - qos_node_create_machine("arm/virt", qos_create_machine_arm_virt); - qos_node_contains("arm/virt", "virtio-mmio", NULL); -} - -libqos_init(virtio_mmio_register_nodes); diff --git a/tests/libqos/arm-xilinx-zynq-a9-machine.c b/tests/libqos/arm-xilinx-zynq-a9-machine.c deleted file mode 100644 index 5bc95f2e73..0000000000 --- a/tests/libqos/arm-xilinx-zynq-a9-machine.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "sdhci.h" - -typedef struct QXilinxZynqA9Machine QXilinxZynqA9Machine; - -struct QXilinxZynqA9Machine { - QOSGraphObject obj; - QGuestAllocator alloc; - QSDHCI_MemoryMapped sdhci; -}; - -#define ARM_PAGE_SIZE 4096 -#define XILINX_ZYNQ_A9_RAM_ADDR 0 -#define XILINX_ZYNQ_A9_RAM_SIZE 0x20000000 - -static void *xilinx_zynq_a9_get_driver(void *object, const char *interface) -{ - QXilinxZynqA9Machine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in arm/xilinx-zynq-a9\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *xilinx_zynq_a9_get_device(void *obj, const char *device) -{ - QXilinxZynqA9Machine *machine = obj; - if (!g_strcmp0(device, "generic-sdhci")) { - return &machine->sdhci.obj; - } - - fprintf(stderr, "%s not present in arm/xilinx-zynq-a9\n", device); - g_assert_not_reached(); -} - -static void xilinx_zynq_a9_destructor(QOSGraphObject *obj) -{ - QXilinxZynqA9Machine *machine = (QXilinxZynqA9Machine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *qos_create_machine_arm_xilinx_zynq_a9(QTestState *qts) -{ - QXilinxZynqA9Machine *machine = g_new0(QXilinxZynqA9Machine, 1); - - alloc_init(&machine->alloc, 0, - XILINX_ZYNQ_A9_RAM_ADDR + (1 << 20), - XILINX_ZYNQ_A9_RAM_ADDR + XILINX_ZYNQ_A9_RAM_SIZE, - ARM_PAGE_SIZE); - - machine->obj.get_device = xilinx_zynq_a9_get_device; - machine->obj.get_driver = xilinx_zynq_a9_get_driver; - machine->obj.destructor = xilinx_zynq_a9_destructor; - /* Datasheet: UG585 (v1.12.1) */ - qos_init_sdhci_mm(&machine->sdhci, qts, 0xe0100000, &(QSDHCIProperties) { - .version = 2, - .baseclock = 0, - .capab.sdma = true, - .capab.reg = 0x69ec0080, - }); - return &machine->obj; -} - -static void xilinx_zynq_a9_register_nodes(void) -{ - qos_node_create_machine("arm/xilinx-zynq-a9", - qos_create_machine_arm_xilinx_zynq_a9); - qos_node_contains("arm/xilinx-zynq-a9", "generic-sdhci", NULL); -} - -libqos_init(xilinx_zynq_a9_register_nodes); diff --git a/tests/libqos/e1000e.c b/tests/libqos/e1000e.c deleted file mode 100644 index 560e7a2bb2..0000000000 --- a/tests/libqos/e1000e.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "libqos/pci-pc.h" -#include "qemu/sockets.h" -#include "qemu/iov.h" -#include "qemu/module.h" -#include "qemu/bitops.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "e1000e.h" - -#define E1000E_IMS (0x00d0) - -#define E1000E_STATUS (0x0008) -#define E1000E_STATUS_LU BIT(1) -#define E1000E_STATUS_ASDV1000 BIT(9) - -#define E1000E_CTRL (0x0000) -#define E1000E_CTRL_RESET BIT(26) - -#define E1000E_RCTL (0x0100) -#define E1000E_RCTL_EN BIT(1) -#define E1000E_RCTL_UPE BIT(3) -#define E1000E_RCTL_MPE BIT(4) - -#define E1000E_RFCTL (0x5008) -#define E1000E_RFCTL_EXTEN BIT(15) - -#define E1000E_TCTL (0x0400) -#define E1000E_TCTL_EN BIT(1) - -#define E1000E_CTRL_EXT (0x0018) -#define E1000E_CTRL_EXT_DRV_LOAD BIT(28) -#define E1000E_CTRL_EXT_TXLSFLOW BIT(22) - -#define E1000E_IVAR (0x00E4) -#define E1000E_IVAR_TEST_CFG ((E1000E_RX0_MSG_ID << 0) | BIT(3) | \ - (E1000E_TX0_MSG_ID << 8) | BIT(11) | \ - (E1000E_OTHER_MSG_ID << 16) | BIT(19) | \ - BIT(31)) - -#define E1000E_RING_LEN (0x1000) - -#define E1000E_TDBAL (0x3800) - -#define E1000E_TDBAH (0x3804) -#define E1000E_TDH (0x3810) - -#define E1000E_RDBAL (0x2800) -#define E1000E_RDBAH (0x2804) -#define E1000E_RDH (0x2810) - -#define E1000E_TXD_LEN (16) -#define E1000E_RXD_LEN (16) - -static void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val) -{ - QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val); -} - -static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg) -{ - QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg); -} - -void e1000e_tx_ring_push(QE1000E *d, void *descr) -{ - QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - uint32_t tail = e1000e_macreg_read(d, E1000E_TDT); - uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000E_TXD_LEN; - - qtest_memwrite(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN, - descr, E1000E_TXD_LEN); - e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len); - - /* Read WB data for the packet transmitted */ - qtest_memread(d_pci->pci_dev.bus->qts, d->tx_ring + tail * E1000E_TXD_LEN, - descr, E1000E_TXD_LEN); -} - -void e1000e_rx_ring_push(QE1000E *d, void *descr) -{ - QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - uint32_t tail = e1000e_macreg_read(d, E1000E_RDT); - uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000E_RXD_LEN; - - qtest_memwrite(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN, - descr, E1000E_RXD_LEN); - e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len); - - /* Read WB data for the packet received */ - qtest_memread(d_pci->pci_dev.bus->qts, d->rx_ring + tail * E1000E_RXD_LEN, - descr, E1000E_RXD_LEN); -} - -static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data) -{ - QPCIDevice *res = data; - memcpy(res, dev, sizeof(QPCIDevice)); - g_free(dev); -} - -void e1000e_wait_isr(QE1000E *d, uint16_t msg_id) -{ - QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e); - guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; - - do { - if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) { - return; - } - qtest_clock_step(d_pci->pci_dev.bus->qts, 10000); - } while (g_get_monotonic_time() < end_time); - - g_error("Timeout expired"); -} - -static void e1000e_pci_destructor(QOSGraphObject *obj) -{ - QE1000E_PCI *epci = (QE1000E_PCI *) obj; - qpci_iounmap(&epci->pci_dev, epci->mac_regs); - qpci_msix_disable(&epci->pci_dev); -} - -static void e1000e_pci_start_hw(QOSGraphObject *obj) -{ - QE1000E_PCI *d = (QE1000E_PCI *) obj; - uint32_t val; - - /* Enable the device */ - qpci_device_enable(&d->pci_dev); - - /* Reset the device */ - val = e1000e_macreg_read(&d->e1000e, E1000E_CTRL); - e1000e_macreg_write(&d->e1000e, E1000E_CTRL, val | E1000E_CTRL_RESET); - - /* Enable and configure MSI-X */ - qpci_msix_enable(&d->pci_dev); - e1000e_macreg_write(&d->e1000e, E1000E_IVAR, E1000E_IVAR_TEST_CFG); - - /* Check the device status - link and speed */ - val = e1000e_macreg_read(&d->e1000e, E1000E_STATUS); - g_assert_cmphex(val & (E1000E_STATUS_LU | E1000E_STATUS_ASDV1000), - ==, E1000E_STATUS_LU | E1000E_STATUS_ASDV1000); - - /* Initialize TX/RX logic */ - e1000e_macreg_write(&d->e1000e, E1000E_RCTL, 0); - e1000e_macreg_write(&d->e1000e, E1000E_TCTL, 0); - - /* Notify the device that the driver is ready */ - val = e1000e_macreg_read(&d->e1000e, E1000E_CTRL_EXT); - e1000e_macreg_write(&d->e1000e, E1000E_CTRL_EXT, - val | E1000E_CTRL_EXT_DRV_LOAD | E1000E_CTRL_EXT_TXLSFLOW); - - e1000e_macreg_write(&d->e1000e, E1000E_TDBAL, - (uint32_t) d->e1000e.tx_ring); - e1000e_macreg_write(&d->e1000e, E1000E_TDBAH, - (uint32_t) (d->e1000e.tx_ring >> 32)); - e1000e_macreg_write(&d->e1000e, E1000E_TDLEN, E1000E_RING_LEN); - e1000e_macreg_write(&d->e1000e, E1000E_TDT, 0); - e1000e_macreg_write(&d->e1000e, E1000E_TDH, 0); - - /* Enable transmit */ - e1000e_macreg_write(&d->e1000e, E1000E_TCTL, E1000E_TCTL_EN); - e1000e_macreg_write(&d->e1000e, E1000E_RDBAL, - (uint32_t)d->e1000e.rx_ring); - e1000e_macreg_write(&d->e1000e, E1000E_RDBAH, - (uint32_t)(d->e1000e.rx_ring >> 32)); - e1000e_macreg_write(&d->e1000e, E1000E_RDLEN, E1000E_RING_LEN); - e1000e_macreg_write(&d->e1000e, E1000E_RDT, 0); - e1000e_macreg_write(&d->e1000e, E1000E_RDH, 0); - - /* Enable receive */ - e1000e_macreg_write(&d->e1000e, E1000E_RFCTL, E1000E_RFCTL_EXTEN); - e1000e_macreg_write(&d->e1000e, E1000E_RCTL, E1000E_RCTL_EN | - E1000E_RCTL_UPE | - E1000E_RCTL_MPE); - - /* Enable all interrupts */ - e1000e_macreg_write(&d->e1000e, E1000E_IMS, 0xFFFFFFFF); - -} - -static void *e1000e_pci_get_driver(void *obj, const char *interface) -{ - QE1000E_PCI *epci = obj; - if (!g_strcmp0(interface, "e1000e-if")) { - return &epci->e1000e; - } - - /* implicit contains */ - if (!g_strcmp0(interface, "pci-device")) { - return &epci->pci_dev; - } - - fprintf(stderr, "%s not present in e1000e\n", interface); - g_assert_not_reached(); -} - -static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc, - void *addr) -{ - QE1000E_PCI *d = g_new0(QE1000E_PCI, 1); - QPCIBus *bus = pci_bus; - QPCIAddress *address = addr; - - qpci_device_foreach(bus, address->vendor_id, address->device_id, - e1000e_foreach_callback, &d->pci_dev); - - /* Map BAR0 (mac registers) */ - d->mac_regs = qpci_iomap(&d->pci_dev, 0, NULL); - - /* Allocate and setup TX ring */ - d->e1000e.tx_ring = guest_alloc(alloc, E1000E_RING_LEN); - g_assert(d->e1000e.tx_ring != 0); - - /* Allocate and setup RX ring */ - d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN); - g_assert(d->e1000e.rx_ring != 0); - - d->obj.get_driver = e1000e_pci_get_driver; - d->obj.start_hw = e1000e_pci_start_hw; - d->obj.destructor = e1000e_pci_destructor; - - return &d->obj; -} - -static void e1000e_register_nodes(void) -{ - QPCIAddress addr = { - .vendor_id = 0x8086, - .device_id = 0x10D3, - }; - - /* FIXME: every test using this node needs to setup a -netdev socket,id=hs0 - * otherwise QEMU is not going to start */ - QOSGraphEdgeOptions opts = { - .extra_device_opts = "netdev=hs0", - }; - add_qpci_address(&opts, &addr); - - qos_node_create_driver("e1000e", e1000e_pci_create); - qos_node_consumes("e1000e", "pci-bus", &opts); -} - -libqos_init(e1000e_register_nodes); diff --git a/tests/libqos/e1000e.h b/tests/libqos/e1000e.h deleted file mode 100644 index dc4ab10f58..0000000000 --- a/tests/libqos/e1000e.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef QGRAPH_E1000E_H -#define QGRAPH_E1000E_H - -#include "libqos/qgraph.h" -#include "pci.h" - -#define E1000E_RX0_MSG_ID (0) -#define E1000E_TX0_MSG_ID (1) -#define E1000E_OTHER_MSG_ID (2) - -#define E1000E_TDLEN (0x3808) -#define E1000E_TDT (0x3818) -#define E1000E_RDLEN (0x2808) -#define E1000E_RDT (0x2818) - -typedef struct QE1000E QE1000E; -typedef struct QE1000E_PCI QE1000E_PCI; - -struct QE1000E { - uint64_t tx_ring; - uint64_t rx_ring; -}; - -struct QE1000E_PCI { - QOSGraphObject obj; - QPCIDevice pci_dev; - QPCIBar mac_regs; - QE1000E e1000e; -}; - -void e1000e_wait_isr(QE1000E *d, uint16_t msg_id); -void e1000e_tx_ring_push(QE1000E *d, void *descr); -void e1000e_rx_ring_push(QE1000E *d, void *descr); - -#endif diff --git a/tests/libqos/fw_cfg.c b/tests/libqos/fw_cfg.c deleted file mode 100644 index 1f46258f96..0000000000 --- a/tests/libqos/fw_cfg.c +++ /dev/null @@ -1,164 +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 "libqos/fw_cfg.h" -#include "libqtest.h" -#include "qemu/bswap.h" -#include "hw/nvram/fw_cfg.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) -{ - qtest_writew(fw_cfg->qts, fw_cfg->base, key); -} - -/* - * The caller need check the return value. When the return value is - * nonzero, it means that some bytes have been transferred. - * - * If the fw_cfg file in question is smaller than the allocated & passed-in - * buffer, then the buffer has been populated only in part. - * - * If the fw_cfg file in question is larger than the passed-in - * buffer, then the return value explains how much room would have been - * necessary in total. And, while the caller's buffer has been fully - * populated, it has received only a starting slice of the fw_cfg file. - */ -size_t qfw_cfg_get_file(QFWCFG *fw_cfg, const char *filename, - void *data, size_t buflen) -{ - uint32_t count; - uint32_t i; - unsigned char *filesbuf = NULL; - size_t dsize; - FWCfgFile *pdir_entry; - size_t filesize = 0; - - qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, &count, sizeof(count)); - count = be32_to_cpu(count); - dsize = sizeof(uint32_t) + count * sizeof(struct fw_cfg_file); - filesbuf = g_malloc(dsize); - qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, filesbuf, dsize); - pdir_entry = (FWCfgFile *)(filesbuf + sizeof(uint32_t)); - for (i = 0; i < count; ++i, ++pdir_entry) { - if (!strcmp(pdir_entry->name, filename)) { - uint32_t len = be32_to_cpu(pdir_entry->size); - uint16_t sel = be16_to_cpu(pdir_entry->select); - filesize = len; - if (len > buflen) { - len = buflen; - } - qfw_cfg_get(fw_cfg, sel, data, len); - break; - } - } - g_free(filesbuf); - return filesize; -} - -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] = qtest_readb(fw_cfg->qts, fw_cfg->base + 2); - } -} - -QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base) -{ - QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); - - fw_cfg->base = base; - fw_cfg->qts = qts; - fw_cfg->select = mm_fw_cfg_select; - fw_cfg->read = mm_fw_cfg_read; - - return fw_cfg; -} - -void mm_fw_cfg_uninit(QFWCFG *fw_cfg) -{ - g_free(fw_cfg); -} - -static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) -{ - qtest_outw(fw_cfg->qts, 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] = qtest_inb(fw_cfg->qts, fw_cfg->base + 1); - } -} - -QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base) -{ - QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); - - fw_cfg->base = base; - fw_cfg->qts = qts; - fw_cfg->select = io_fw_cfg_select; - fw_cfg->read = io_fw_cfg_read; - - return fw_cfg; -} - -void io_fw_cfg_uninit(QFWCFG *fw_cfg) -{ - g_free(fw_cfg); -} diff --git a/tests/libqos/fw_cfg.h b/tests/libqos/fw_cfg.h deleted file mode 100644 index 13325cc4ff..0000000000 --- a/tests/libqos/fw_cfg.h +++ /dev/null @@ -1,52 +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 - -#include "libqtest.h" - -typedef struct QFWCFG QFWCFG; - -struct QFWCFG -{ - uint64_t base; - QTestState *qts; - 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); -size_t qfw_cfg_get_file(QFWCFG *fw_cfg, const char *filename, - void *data, size_t buflen); - -QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base); -void mm_fw_cfg_uninit(QFWCFG *fw_cfg); -QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base); -void io_fw_cfg_uninit(QFWCFG *fw_cfg); - -static inline QFWCFG *pc_fw_cfg_init(QTestState *qts) -{ - return io_fw_cfg_init(qts, 0x510); -} - -static inline void pc_fw_cfg_uninit(QFWCFG *fw_cfg) -{ - io_fw_cfg_uninit(fw_cfg); -} - -#endif diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c deleted file mode 100644 index f33ece55a3..0000000000 --- a/tests/libqos/i2c-imx.c +++ /dev/null @@ -1,216 +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 "libqtest.h" - -#include "hw/i2c/imx_i2c.h" - -enum IMXI2CDirection { - IMX_I2C_READ, - IMX_I2C_WRITE, -}; - -static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr, - enum IMXI2CDirection direction) -{ - qtest_writeb(s->parent.qts, 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 = container_of(i2c, IMXI2C, parent); - 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; - - qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); - status = qtest_readb(i2c->qts, 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 = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) != 0); - g_assert((status & I2SR_RXAK) == 0); - - /* ack the interrupt */ - qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) == 0); - - while (size < len) { - /* check we are still busy */ - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IBB) != 0); - - /* write the data */ - qtest_writeb(i2c->qts, s->addr + I2DR_ADDR, buf[size]); - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) != 0); - g_assert((status & I2SR_RXAK) == 0); - - /* ack the interrupt */ - qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) == 0); - - size++; - } - - /* release the bus */ - data &= ~(I2CR_MSTA | I2CR_MTX); - qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); - status = qtest_readb(i2c->qts, 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 = container_of(i2c, IMXI2C, parent); - 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; - - qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); - status = qtest_readb(i2c->qts, 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 = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) != 0); - g_assert((status & I2SR_RXAK) == 0); - - /* ack the interrupt */ - qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); - status = qtest_readb(i2c->qts, 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; - } - qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IBB) != 0); - - /* dummy read */ - qtest_readb(i2c->qts, s->addr + I2DR_ADDR); - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) != 0); - - /* ack the interrupt */ - qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) == 0); - - while (size < len) { - /* check we are still busy */ - status = qtest_readb(i2c->qts, 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; - } - qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); - - /* read the data */ - buf[size] = qtest_readb(i2c->qts, s->addr + I2DR_ADDR); - - if (size != (len - 1)) { - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) != 0); - - /* ack the interrupt */ - qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); - } - - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IIF) == 0); - - size++; - } - - status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); - g_assert((status & I2SR_IBB) == 0); -} - -static void *imx_i2c_get_driver(void *obj, const char *interface) -{ - IMXI2C *s = obj; - if (!g_strcmp0(interface, "i2c-bus")) { - return &s->parent; - } - fprintf(stderr, "%s not present in imx-i2c\n", interface); - g_assert_not_reached(); -} - -void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr) -{ - s->addr = addr; - - s->obj.get_driver = imx_i2c_get_driver; - - s->parent.send = imx_i2c_send; - s->parent.recv = imx_i2c_recv; - s->parent.qts = qts; -} - -static void imx_i2c_register_nodes(void) -{ - qos_node_create_driver("imx.i2c", NULL); - qos_node_produces("imx.i2c", "i2c-bus"); -} - -libqos_init(imx_i2c_register_nodes); diff --git a/tests/libqos/i2c-omap.c b/tests/libqos/i2c-omap.c deleted file mode 100644 index 9ae8214fa8..0000000000 --- a/tests/libqos/i2c-omap.c +++ /dev/null @@ -1,196 +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 "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, -}; - - -static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) -{ - uint16_t data = addr; - - qtest_writew(s->parent.qts, s->addr + OMAP_I2C_SA, data); - data = qtest_readw(s->parent.qts, 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 = container_of(i2c, OMAPI2C, parent); - uint16_t data; - - omap_i2c_set_slave_addr(s, addr); - - data = len; - qtest_writew(i2c->qts, 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; - qtest_writew(i2c->qts, s->addr + OMAP_I2C_CON, data); - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) != 0); - - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_NACK) == 0); - - while (len > 1) { - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_XRDY) != 0); - - data = buf[0] | ((uint16_t)buf[1] << 8); - qtest_writew(i2c->qts, s->addr + OMAP_I2C_DATA, data); - buf = (uint8_t *)buf + 2; - len -= 2; - } - if (len == 1) { - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_XRDY) != 0); - - data = buf[0]; - qtest_writew(i2c->qts, s->addr + OMAP_I2C_DATA, data); - } - - data = qtest_readw(i2c->qts, 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 = container_of(i2c, OMAPI2C, parent); - uint16_t data, stat; - uint16_t orig_len = len; - - omap_i2c_set_slave_addr(s, addr); - - data = len; - qtest_writew(i2c->qts, s->addr + OMAP_I2C_CNT, data); - - data = OMAP_I2C_CON_I2C_EN | - OMAP_I2C_CON_MST | - OMAP_I2C_CON_STT | - OMAP_I2C_CON_STP; - qtest_writew(i2c->qts, s->addr + OMAP_I2C_CON, data); - - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_NACK) == 0); - - while (len > 0) { - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON); - if (len <= 4) { - g_assert((data & OMAP_I2C_CON_STP) == 0); - - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CNT); - g_assert_cmpuint(data, ==, orig_len); - } else { - g_assert((data & OMAP_I2C_CON_STP) != 0); - - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CNT); - g_assert_cmpuint(data, ==, len - 4); - } - - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); - g_assert((data & OMAP_I2C_STAT_RRDY) != 0); - g_assert((data & OMAP_I2C_STAT_ROVR) == 0); - - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_DATA); - - stat = qtest_readw(i2c->qts, 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 = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) == 0); -} - -static void *omap_i2c_get_driver(void *obj, const char *interface) -{ - OMAPI2C *s = obj; - if (!g_strcmp0(interface, "i2c-bus")) { - return &s->parent; - } - fprintf(stderr, "%s not present in omap_i2c\n", interface); - g_assert_not_reached(); -} - -static void omap_i2c_start_hw(QOSGraphObject *object) -{ - OMAPI2C *s = (OMAPI2C *) object; - uint16_t data; - - /* verify the mmio address by looking for a known signature */ - data = qtest_readw(s->parent.qts, s->addr + OMAP_I2C_REV); - g_assert_cmphex(data, ==, 0x34); -} - -void omap_i2c_init(OMAPI2C *s, QTestState *qts, uint64_t addr) -{ - s->addr = addr; - - s->obj.get_driver = omap_i2c_get_driver; - s->obj.start_hw = omap_i2c_start_hw; - - s->parent.send = omap_i2c_send; - s->parent.recv = omap_i2c_recv; - s->parent.qts = qts; -} - -static void omap_i2c_register_nodes(void) -{ - qos_node_create_driver("omap_i2c", NULL); - qos_node_produces("omap_i2c", "i2c-bus"); -} - -libqos_init(omap_i2c_register_nodes); diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c deleted file mode 100644 index 156114e745..0000000000 --- a/tests/libqos/i2c.c +++ /dev/null @@ -1,85 +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(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len) -{ - i2cdev->bus->send(i2cdev->bus, i2cdev->addr, buf, len); -} - -void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len) -{ - i2cdev->bus->recv(i2cdev->bus, i2cdev->addr, buf, len); -} - -void i2c_read_block(QI2CDevice *i2cdev, uint8_t reg, - uint8_t *buf, uint16_t len) -{ - i2c_send(i2cdev, ®, 1); - i2c_recv(i2cdev, buf, len); -} - -void i2c_write_block(QI2CDevice *i2cdev, uint8_t reg, - const uint8_t *buf, uint16_t len) -{ - uint8_t *cmd = g_malloc(len + 1); - cmd[0] = reg; - memcpy(&cmd[1], buf, len); - i2c_send(i2cdev, cmd, len + 1); - g_free(cmd); -} - -uint8_t i2c_get8(QI2CDevice *i2cdev, uint8_t reg) -{ - uint8_t resp[1]; - i2c_read_block(i2cdev, reg, resp, sizeof(resp)); - return resp[0]; -} - -uint16_t i2c_get16(QI2CDevice *i2cdev, uint8_t reg) -{ - uint8_t resp[2]; - i2c_read_block(i2cdev, reg, resp, sizeof(resp)); - return (resp[0] << 8) | resp[1]; -} - -void i2c_set8(QI2CDevice *i2cdev, uint8_t reg, uint8_t value) -{ - i2c_write_block(i2cdev, reg, &value, 1); -} - -void i2c_set16(QI2CDevice *i2cdev, uint8_t reg, uint16_t value) -{ - uint8_t data[2]; - - data[0] = value >> 8; - data[1] = value & 255; - i2c_write_block(i2cdev, reg, data, sizeof(data)); -} - -void *i2c_device_create(void *i2c_bus, QGuestAllocator *alloc, void *addr) -{ - QI2CDevice *i2cdev = g_new0(QI2CDevice, 1); - - i2cdev->bus = i2c_bus; - if (addr) { - i2cdev->addr = ((QI2CAddress *)addr)->addr; - } - return &i2cdev->obj; -} - -void add_qi2c_address(QOSGraphEdgeOptions *opts, QI2CAddress *addr) -{ - g_assert(addr); - - opts->arg = addr; - opts->size_arg = sizeof(QI2CAddress); -} diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h deleted file mode 100644 index 945b65b34c..0000000000 --- a/tests/libqos/i2c.h +++ /dev/null @@ -1,82 +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 - -#include "libqtest.h" -#include "libqos/qgraph.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); - - QTestState *qts; -}; - -typedef struct QI2CAddress QI2CAddress; -struct QI2CAddress { - uint8_t addr; -}; - -typedef struct QI2CDevice QI2CDevice; -struct QI2CDevice { - /* - * For now, all devices are simple enough that there is no need for - * them to define their own constructor and get_driver functions. - * Therefore, QOSGraphObject is included directly in QI2CDevice; - * the tests expect to get a QI2CDevice rather than doing something - * like obj->get_driver("i2c-device"). - * - * In fact there is no i2c-device interface even, because there are - * no generic I2C tests). - */ - QOSGraphObject obj; - I2CAdapter *bus; - uint8_t addr; -}; - -void *i2c_device_create(void *i2c_bus, QGuestAllocator *alloc, void *addr); -void add_qi2c_address(QOSGraphEdgeOptions *opts, QI2CAddress *addr); - -void i2c_send(QI2CDevice *dev, const uint8_t *buf, uint16_t len); -void i2c_recv(QI2CDevice *dev, uint8_t *buf, uint16_t len); - -void i2c_read_block(QI2CDevice *dev, uint8_t reg, - uint8_t *buf, uint16_t len); -void i2c_write_block(QI2CDevice *dev, uint8_t reg, - const uint8_t *buf, uint16_t len); -uint8_t i2c_get8(QI2CDevice *dev, uint8_t reg); -uint16_t i2c_get16(QI2CDevice *dev, uint8_t reg); -void i2c_set8(QI2CDevice *dev, uint8_t reg, uint8_t value); -void i2c_set16(QI2CDevice *dev, uint8_t reg, uint16_t value); - -/* i2c-omap.c */ -typedef struct OMAPI2C { - QOSGraphObject obj; - I2CAdapter parent; - - uint64_t addr; -} OMAPI2C; - -void omap_i2c_init(OMAPI2C *s, QTestState *qts, uint64_t addr); - -/* i2c-imx.c */ -typedef struct IMXI2C { - QOSGraphObject obj; - I2CAdapter parent; - - uint64_t addr; -} IMXI2C; - -void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr); - -#endif diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c deleted file mode 100644 index d04abc548b..0000000000 --- a/tests/libqos/libqos-pc.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "qemu/osdep.h" -#include "libqos/libqos-pc.h" -#include "libqos/malloc-pc.h" -#include "libqos/pci-pc.h" - -static QOSOps qos_ops = { - .alloc_init = pc_alloc_init, - .qpci_new = qpci_new_pc, - .qpci_free = qpci_free_pc, - .shutdown = qtest_pc_shutdown, -}; - -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); - - qtest_irq_intercept_in(qs->qts, "ioapic"); - - return qs; -} - -void qtest_pc_shutdown(QOSState *qs) -{ - return qtest_common_shutdown(qs); -} diff --git a/tests/libqos/libqos-pc.h b/tests/libqos/libqos-pc.h deleted file mode 100644 index a0e4c45516..0000000000 --- a/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/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c deleted file mode 100644 index 8766d543ce..0000000000 --- a/tests/libqos/libqos-spapr.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "qemu/osdep.h" -#include "libqos/libqos-spapr.h" -#include "libqos/malloc-spapr.h" -#include "libqos/pci-spapr.h" - -static QOSOps qos_ops = { - .alloc_init = spapr_alloc_init, - .qpci_new = qpci_new_spapr, - .qpci_free = qpci_free_spapr, - .shutdown = qtest_spapr_shutdown, -}; - -QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) -{ - return qtest_vboot(&qos_ops, cmdline_fmt, ap); -} - -QOSState *qtest_spapr_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_spapr_shutdown(QOSState *qs) -{ - return qtest_common_shutdown(qs); -} diff --git a/tests/libqos/libqos-spapr.h b/tests/libqos/libqos-spapr.h deleted file mode 100644 index dcb5c43ad3..0000000000 --- a/tests/libqos/libqos-spapr.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef LIBQOS_SPAPR_H -#define LIBQOS_SPAPR_H - -#include "libqos/libqos.h" - -QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap); -QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...); -void qtest_spapr_shutdown(QOSState *qs); - -#endif diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c deleted file mode 100644 index f229eb2cb8..0000000000 --- a/tests/libqos/libqos.c +++ /dev/null @@ -1,240 +0,0 @@ -#include "qemu/osdep.h" -#include <sys/wait.h> - -#include "libqtest.h" -#include "libqos/libqos.h" -#include "libqos/pci.h" -#include "qapi/qmp/qdict.h" - -/*** Test Setup & Teardown ***/ - -/** - * Launch QEMU with the given command line, - * and then set up interrupts and our guest malloc interface. - * Never returns NULL: - * Terminates the application in case an error is encountered. - */ -QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) -{ - char *cmdline; - - QOSState *qs = g_new0(QOSState, 1); - - cmdline = g_strdup_vprintf(cmdline_fmt, ap); - qs->qts = qtest_init(cmdline); - qs->ops = ops; - if (ops) { - ops->alloc_init(&qs->alloc, qs->qts, ALLOC_NO_FLAGS); - qs->pcibus = ops->qpci_new(qs->qts, &qs->alloc); - } - - 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_common_shutdown(QOSState *qs) -{ - if (qs->ops) { - if (qs->pcibus && qs->ops->qpci_free) { - qs->ops->qpci_free(qs->pcibus); - qs->pcibus = NULL; - } - } - alloc_destroy(&qs->alloc); - qtest_quit(qs->qts); - g_free(qs); -} - -void qtest_shutdown(QOSState *qs) -{ - if (qs->ops && qs->ops->shutdown) { - qs->ops->shutdown(qs); - } else { - qtest_common_shutdown(qs); - } -} - -static QDict *qmp_execute(QTestState *qts, const char *command) -{ - return qtest_qmp(qts, "{ 'execute': %s }", command); -} - -void migrate(QOSState *from, QOSState *to, const char *uri) -{ - const char *st; - QDict *rsp, *sub; - bool running; - - /* Is the machine currently running? */ - rsp = qmp_execute(from->qts, "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"); - qobject_unref(rsp); - - /* Issue the migrate command. */ - rsp = qtest_qmp(from->qts, - "{ 'execute': 'migrate', 'arguments': { 'uri': %s }}", - uri); - g_assert(qdict_haskey(rsp, "return")); - qobject_unref(rsp); - - /* Wait for STOP event, but only if we were running: */ - if (running) { - qtest_qmp_eventwait(from->qts, "STOP"); - } - - /* If we were running, we can wait for an event. */ - if (running) { - migrate_allocator(&from->alloc, &to->alloc); - qtest_qmp_eventwait(to->qts, "RESUME"); - return; - } - - /* Otherwise, we need to wait: poll until migration is completed. */ - while (1) { - rsp = qmp_execute(from->qts, "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) { - qobject_unref(rsp); - break; - } - - if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0) - || (strcmp(st, "wait-unplug") == 0)) { - qobject_unref(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); -} - -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 || !g_spawn_check_exit_status(rc, &err)) { - fprintf(stderr, "%s\n", err->message); - g_error_free(err); - } - g_assert(ret && !err); - - 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/tests/libqos/libqos.h b/tests/libqos/libqos.h deleted file mode 100644 index 8e971c25a3..0000000000 --- a/tests/libqos/libqos.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef LIBQOS_H -#define LIBQOS_H - -#include "libqtest.h" -#include "libqos/pci.h" -#include "libqos/malloc.h" - -typedef struct QOSState QOSState; - -typedef struct QOSOps { - void (*alloc_init)(QGuestAllocator *, QTestState *, QAllocOpts); - QPCIBus *(*qpci_new)(QTestState *qts, QGuestAllocator *alloc); - void (*qpci_free)(QPCIBus *bus); - void (*shutdown)(QOSState *); -} QOSOps; - -struct QOSState { - QTestState *qts; - QGuestAllocator alloc; - QPCIBus *pcibus; - QOSOps *ops; -}; - -QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); -QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); -void qtest_common_shutdown(QOSState *qs); -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 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/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c deleted file mode 100644 index 6f92ce4135..0000000000 --- a/tests/libqos/malloc-pc.c +++ /dev/null @@ -1,33 +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 "standard-headers/linux/qemu_fw_cfg.h" - -#include "qemu-common.h" - -#define PAGE_SIZE (4096) - -void pc_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags) -{ - uint64_t ram_size; - QFWCFG *fw_cfg = pc_fw_cfg_init(qts); - - ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE); - alloc_init(s, flags, 1 << 20, MIN(ram_size, 0xE0000000), PAGE_SIZE); - - /* clean-up */ - pc_fw_cfg_uninit(fw_cfg); -} diff --git a/tests/libqos/malloc-pc.h b/tests/libqos/malloc-pc.h deleted file mode 100644 index 21e75ae004..0000000000 --- a/tests/libqos/malloc-pc.h +++ /dev/null @@ -1,20 +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" - -void pc_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags); - -#endif diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c deleted file mode 100644 index 2a6b7e3776..0000000000 --- a/tests/libqos/malloc-spapr.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * libqos malloc support for SPAPR - * - * 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-spapr.h" - -#include "qemu-common.h" - -#define PAGE_SIZE 4096 - -/* Memory must be a multiple of 256 MB, - * so we have at least 256MB - */ -#define SPAPR_MIN_SIZE 0x10000000 - -void spapr_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags) -{ - alloc_init(s, flags, 1 << 20, SPAPR_MIN_SIZE, PAGE_SIZE); -} diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h deleted file mode 100644 index e5fe9bfc4b..0000000000 --- a/tests/libqos/malloc-spapr.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * libqos malloc support for SPAPR - * - * 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_SPAPR_H -#define LIBQOS_MALLOC_SPAPR_H - -#include "libqos/malloc.h" - -void spapr_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags); - -#endif diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c deleted file mode 100644 index 615422a5c4..0000000000 --- a/tests/libqos/malloc.c +++ /dev/null @@ -1,347 +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 "qemu/host-utils.h" - -typedef struct MemBlock { - QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME; - uint64_t size; - uint64_t addr; -} MemBlock; - -#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, 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_new0(MemBlock, 1); - - 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_destroy(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); -} - -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); - } -} - -void alloc_init(QGuestAllocator *s, QAllocOpts opts, - uint64_t start, uint64_t end, - size_t page_size) -{ - MemBlock *node; - - s->opts = opts; - s->start = start; - s->end = end; - - s->used = g_new(MemList, 1); - s->free = g_new(MemList, 1); - 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 = 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/tests/libqos/malloc.h b/tests/libqos/malloc.h deleted file mode 100644 index 4d1a2e2bef..0000000000 --- a/tests/libqos/malloc.h +++ /dev/null @@ -1,50 +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" -#include "libqtest.h" - -typedef enum { - ALLOC_NO_FLAGS = 0x00, - ALLOC_LEAK_WARN = 0x01, - ALLOC_LEAK_ASSERT = 0x02, - ALLOC_PARANOID = 0x04 -} QAllocOpts; - -typedef QTAILQ_HEAD(MemList, MemBlock) MemList; - -typedef struct QGuestAllocator { - QAllocOpts opts; - uint64_t start; - uint64_t end; - uint32_t page_size; - - MemList *used; - MemList *free; -} QGuestAllocator; - -/* 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); - -void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts); - -void alloc_init(QGuestAllocator *alloc, QAllocOpts flags, - uint64_t start, uint64_t end, - size_t page_size); -void alloc_destroy(QGuestAllocator *allocator); - -#endif diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c deleted file mode 100644 index 0bc591d1da..0000000000 --- a/tests/libqos/pci-pc.c +++ /dev/null @@ -1,200 +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 "qapi/qmp/qdict.h" -#include "hw/pci/pci_regs.h" - -#include "qemu/module.h" - -#define ACPI_PCIHP_ADDR 0xae00 -#define PCI_EJ_BASE 0x0008 - -static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) -{ - return qtest_inb(bus->qts, addr); -} - -static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) -{ - qtest_outb(bus->qts, addr, val); -} - -static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) -{ - return qtest_inw(bus->qts, addr); -} - -static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) -{ - qtest_outw(bus->qts, addr, val); -} - -static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) -{ - return qtest_inl(bus->qts, addr); -} - -static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) -{ - qtest_outl(bus->qts, addr, val); -} - -static uint64_t qpci_pc_pio_readq(QPCIBus *bus, uint32_t addr) -{ - return (uint64_t)qtest_inl(bus->qts, addr) + - ((uint64_t)qtest_inl(bus->qts, addr + 4) << 32); -} - -static void qpci_pc_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) -{ - qtest_outl(bus->qts, addr, val & 0xffffffff); - qtest_outl(bus->qts, addr + 4, val >> 32); -} - -static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) -{ - qtest_memread(bus->qts, addr, buf, len); -} - -static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr, - const void *buf, size_t len) -{ - qtest_memwrite(bus->qts, addr, buf, len); -} - -static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) -{ - qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); - return qtest_inb(bus->qts, 0xcfc); -} - -static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset) -{ - qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); - return qtest_inw(bus->qts, 0xcfc); -} - -static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset) -{ - qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); - return qtest_inl(bus->qts, 0xcfc); -} - -static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) -{ - qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); - qtest_outb(bus->qts, 0xcfc, value); -} - -static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) -{ - qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); - qtest_outw(bus->qts, 0xcfc, value); -} - -static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) -{ - qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); - qtest_outl(bus->qts, 0xcfc, value); -} - -static void *qpci_pc_get_driver(void *obj, const char *interface) -{ - QPCIBusPC *qpci = obj; - if (!g_strcmp0(interface, "pci-bus")) { - return &qpci->bus; - } - fprintf(stderr, "%s not present in pci-bus-pc\n", interface); - g_assert_not_reached(); -} - -void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc) -{ - assert(qts); - - /* tests can use pci-bus */ - qpci->bus.has_buggy_msi = false; - - qpci->bus.pio_readb = qpci_pc_pio_readb; - qpci->bus.pio_readw = qpci_pc_pio_readw; - qpci->bus.pio_readl = qpci_pc_pio_readl; - qpci->bus.pio_readq = qpci_pc_pio_readq; - - qpci->bus.pio_writeb = qpci_pc_pio_writeb; - qpci->bus.pio_writew = qpci_pc_pio_writew; - qpci->bus.pio_writel = qpci_pc_pio_writel; - qpci->bus.pio_writeq = qpci_pc_pio_writeq; - - qpci->bus.memread = qpci_pc_memread; - qpci->bus.memwrite = qpci_pc_memwrite; - - qpci->bus.config_readb = qpci_pc_config_readb; - qpci->bus.config_readw = qpci_pc_config_readw; - qpci->bus.config_readl = qpci_pc_config_readl; - - qpci->bus.config_writeb = qpci_pc_config_writeb; - qpci->bus.config_writew = qpci_pc_config_writew; - qpci->bus.config_writel = qpci_pc_config_writel; - - qpci->bus.qts = qts; - qpci->bus.pio_alloc_ptr = 0xc000; - qpci->bus.mmio_alloc_ptr = 0xE0000000; - qpci->bus.mmio_limit = 0x100000000ULL; - - qpci->obj.get_driver = qpci_pc_get_driver; -} - -QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc) -{ - QPCIBusPC *qpci = g_new0(QPCIBusPC, 1); - qpci_init_pc(qpci, qts, alloc); - - return &qpci->bus; -} - -void qpci_free_pc(QPCIBus *bus) -{ - QPCIBusPC *s; - - if (!bus) { - return; - } - s = container_of(bus, QPCIBusPC, bus); - - g_free(s); -} - -void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot) -{ - QDict *response; - - response = qtest_qmp(qts, "{'execute': 'device_del'," - " 'arguments': {'id': %s}}", id); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - qobject_unref(response); - - qtest_outb(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); - - qtest_qmp_eventwait(qts, "DEVICE_DELETED"); -} - -static void qpci_pc_register_nodes(void) -{ - qos_node_create_driver("pci-bus-pc", NULL); - qos_node_produces("pci-bus-pc", "pci-bus"); -} - -libqos_init(qpci_pc_register_nodes); diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h deleted file mode 100644 index 4690005232..0000000000 --- a/tests/libqos/pci-pc.h +++ /dev/null @@ -1,49 +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" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" - -typedef struct QPCIBusPC { - QOSGraphObject obj; - QPCIBus bus; -} QPCIBusPC; - -/* qpci_init_pc(): - * @ret: A valid QPCIBusPC * pointer - * @qts: The %QTestState for this PC machine - * @alloc: A previously initialized @alloc providing memory for @qts - * - * This function initializes an already allocated - * QPCIBusPC object. - */ -void qpci_init_pc(QPCIBusPC *ret, QTestState *qts, QGuestAllocator *alloc); - -/* qpci_pc_new(): - * @qts: The %QTestState for this PC machine - * @alloc: A previously initialized @alloc providing memory for @qts - * - * This function creates a new QPCIBusPC object, - * and properly initialize its fields. - * - * Returns the QPCIBus *bus field of a newly - * allocated QPCIBusPC. - */ -QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc); - -void qpci_free_pc(QPCIBus *bus); - -#endif diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c deleted file mode 100644 index d6f8c01cb7..0000000000 --- a/tests/libqos/pci-spapr.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * libqos PCI bindings for SPAPR - * - * 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-spapr.h" -#include "libqos/rtas.h" -#include "libqos/qgraph.h" - -#include "hw/pci/pci_regs.h" - -#include "qemu/host-utils.h" -#include "qemu/module.h" - -/* - * PCI devices are always little-endian - * SPAPR by default is big-endian - * so PCI accessors need to swap data endianness - */ - -static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return qtest_readb(bus->qts, s->pio_cpu_base + addr); -} - -static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - qtest_writeb(bus->qts, s->pio_cpu_base + addr, val); -} - -static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return bswap16(qtest_readw(bus->qts, s->pio_cpu_base + addr)); -} - -static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - qtest_writew(bus->qts, s->pio_cpu_base + addr, bswap16(val)); -} - -static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return bswap32(qtest_readl(bus->qts, s->pio_cpu_base + addr)); -} - -static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - qtest_writel(bus->qts, s->pio_cpu_base + addr, bswap32(val)); -} - -static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return bswap64(qtest_readq(bus->qts, s->pio_cpu_base + addr)); -} - -static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - qtest_writeq(bus->qts, s->pio_cpu_base + addr, bswap64(val)); -} - -static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, - void *buf, size_t len) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - qtest_memread(bus->qts, s->mmio32_cpu_base + addr, buf, len); -} - -static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr, - const void *buf, size_t len) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - qtest_memwrite(bus->qts, s->mmio32_cpu_base + addr, buf, len); -} - -static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, - config_addr, 1); -} - -static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, - config_addr, 2); -} - -static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid, - config_addr, 4); -} - -static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, - uint8_t value) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, - config_addr, 1, value); -} - -static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, - uint16_t value) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, - config_addr, 2, value); -} - -static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, - uint32_t value) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid, - config_addr, 4, value); -} - -#define SPAPR_PCI_BASE (1ULL << 45) - -#define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ -#define SPAPR_PCI_IO_WIN_SIZE 0x10000 - -static void *qpci_spapr_get_driver(void *obj, const char *interface) -{ - QPCIBusSPAPR *qpci = obj; - if (!g_strcmp0(interface, "pci-bus")) { - return &qpci->bus; - } - fprintf(stderr, "%s not present in pci-bus-spapr", interface); - g_assert_not_reached(); -} - -void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts, - QGuestAllocator *alloc) -{ - assert(qts); - - /* tests cannot use spapr, needs to be fixed first */ - qpci->bus.has_buggy_msi = true; - - qpci->alloc = alloc; - - qpci->bus.pio_readb = qpci_spapr_pio_readb; - qpci->bus.pio_readw = qpci_spapr_pio_readw; - qpci->bus.pio_readl = qpci_spapr_pio_readl; - qpci->bus.pio_readq = qpci_spapr_pio_readq; - - qpci->bus.pio_writeb = qpci_spapr_pio_writeb; - qpci->bus.pio_writew = qpci_spapr_pio_writew; - qpci->bus.pio_writel = qpci_spapr_pio_writel; - qpci->bus.pio_writeq = qpci_spapr_pio_writeq; - - qpci->bus.memread = qpci_spapr_memread; - qpci->bus.memwrite = qpci_spapr_memwrite; - - qpci->bus.config_readb = qpci_spapr_config_readb; - qpci->bus.config_readw = qpci_spapr_config_readw; - qpci->bus.config_readl = qpci_spapr_config_readl; - - qpci->bus.config_writeb = qpci_spapr_config_writeb; - qpci->bus.config_writew = qpci_spapr_config_writew; - qpci->bus.config_writel = qpci_spapr_config_writel; - - /* FIXME: We assume the default location of the PHB for now. - * Ideally we'd parse the device tree deposited in the guest to - * get the window locations */ - qpci->buid = 0x800000020000000ULL; - - qpci->pio_cpu_base = SPAPR_PCI_BASE; - qpci->pio.pci_base = 0; - qpci->pio.size = SPAPR_PCI_IO_WIN_SIZE; - - /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ - qpci->mmio32_cpu_base = SPAPR_PCI_BASE; - qpci->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE; - qpci->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; - - qpci->bus.qts = qts; - qpci->bus.pio_alloc_ptr = 0xc000; - qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base; - qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size; - - qpci->obj.get_driver = qpci_spapr_get_driver; -} - -QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc) -{ - QPCIBusSPAPR *qpci = g_new0(QPCIBusSPAPR, 1); - qpci_init_spapr(qpci, qts, alloc); - - return &qpci->bus; -} - -void qpci_free_spapr(QPCIBus *bus) -{ - QPCIBusSPAPR *s; - - if (!bus) { - return; - } - s = container_of(bus, QPCIBusSPAPR, bus); - - g_free(s); -} - -static void qpci_spapr_register_nodes(void) -{ - qos_node_create_driver("pci-bus-spapr", NULL); - qos_node_produces("pci-bus-spapr", "pci-bus"); -} - -libqos_init(qpci_spapr_register_nodes); diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h deleted file mode 100644 index d9e25631c6..0000000000 --- a/tests/libqos/pci-spapr.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * libqos PCI bindings for SPAPR - * - * 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_SPAPR_H -#define LIBQOS_PCI_SPAPR_H - -#include "libqos/malloc.h" -#include "libqos/pci.h" -#include "libqos/qgraph.h" - -/* From include/hw/pci-host/spapr.h */ - -typedef struct QPCIWindow { - uint64_t pci_base; /* window address in PCI space */ - uint64_t size; /* window size */ -} QPCIWindow; - -typedef struct QPCIBusSPAPR { - QOSGraphObject obj; - QPCIBus bus; - QGuestAllocator *alloc; - - uint64_t buid; - - uint64_t pio_cpu_base; - QPCIWindow pio; - - uint64_t mmio32_cpu_base; - QPCIWindow mmio32; -} QPCIBusSPAPR; - -void qpci_init_spapr(QPCIBusSPAPR *ret, QTestState *qts, - QGuestAllocator *alloc); -QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc); -void qpci_free_spapr(QPCIBus *bus); - -#endif diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c deleted file mode 100644 index 2309a724e4..0000000000 --- a/tests/libqos/pci.c +++ /dev/null @@ -1,457 +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 "qemu/host-utils.h" -#include "libqos/qgraph.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); - } - } -} - -bool qpci_has_buggy_msi(QPCIDevice *dev) -{ - return dev->bus->has_buggy_msi; -} - -bool qpci_check_buggy_msi(QPCIDevice *dev) -{ - if (qpci_has_buggy_msi(dev)) { - g_test_skip("Skipping due to incomplete support for MSI"); - return true; - } - return false; -} - -static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn) -{ - g_assert(dev); - - dev->bus = bus; - dev->devfn = devfn; -} - -QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn) -{ - QPCIDevice *dev; - - dev = g_malloc0(sizeof(*dev)); - qpci_device_set(dev, bus, devfn); - - if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) { - g_free(dev); - return NULL; - } - - return dev; -} - -void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr) -{ - uint16_t vendor_id, device_id; - - qpci_device_set(dev, bus, addr->devfn); - vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID); - device_id = qpci_config_readw(dev, PCI_DEVICE_ID); - g_assert(!addr->vendor_id || vendor_id == addr->vendor_id); - g_assert(!addr->device_id || device_id == addr->device_id); -} - -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); -} - -/** - * qpci_find_capability: - * @dev: the PCI device - * @id: the PCI Capability ID (PCI_CAP_ID_*) - * @start_addr: 0 to begin iteration or the last return value to continue - * iteration - * - * Iterate over the PCI Capabilities List. - * - * Returns: PCI Configuration Space offset of the capabililty structure or - * 0 if no further matching capability is found - */ -uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id, uint8_t start_addr) -{ - uint8_t cap; - uint8_t addr; - - if (start_addr) { - addr = qpci_config_readb(dev, start_addr + PCI_CAP_LIST_NEXT); - } else { - 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; - - addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0); - 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; - dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL); - dev->msix_table_off = 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) { - dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL); - } else { - dev->msix_pba_bar = dev->msix_table_bar; - } - dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK; - - 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, 0); - 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); - - if (dev->msix_pba_bar.addr != dev->msix_table_bar.addr) { - qpci_iounmap(dev, dev->msix_pba_bar); - } - qpci_iounmap(dev, dev->msix_table_bar); - - dev->msix_enabled = 0; - dev->msix_table_off = 0; - dev->msix_pba_off = 0; -} - -bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry) -{ - uint32_t pba_entry; - uint8_t bit_n = entry % 32; - uint64_t off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4; - - g_assert(dev->msix_enabled); - pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off); - qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off, - 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; - uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE; - - g_assert(dev->msix_enabled); - addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0); - 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, dev->msix_table_bar, - vector_off + 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, 0); - 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, QPCIBar token, uint64_t off) -{ - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readb(dev->bus, token.addr + off); - } else { - uint8_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); - return val; - } -} - -uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off) -{ - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readw(dev->bus, token.addr + off); - } else { - uint16_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); - return le16_to_cpu(val); - } -} - -uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off) -{ - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readl(dev->bus, token.addr + off); - } else { - uint32_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); - return le32_to_cpu(val); - } -} - -uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off) -{ - if (token.addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readq(dev->bus, token.addr + off); - } else { - uint64_t val; - dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); - return le64_to_cpu(val); - } -} - -void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint8_t value) -{ - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeb(dev->bus, token.addr + off, value); - } else { - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); - } -} - -void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint16_t value) -{ - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writew(dev->bus, token.addr + off, value); - } else { - value = cpu_to_le16(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); - } -} - -void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint32_t value) -{ - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writel(dev->bus, token.addr + off, value); - } else { - value = cpu_to_le32(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); - } -} - -void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint64_t value) -{ - if (token.addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeq(dev->bus, token.addr + off, value); - } else { - value = cpu_to_le64(value); - dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); - } -} - -void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off, - void *buf, size_t len) -{ - g_assert(token.addr >= QPCI_PIO_LIMIT); - dev->bus->memread(dev->bus, token.addr + off, buf, len); -} - -void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off, - const void *buf, size_t len) -{ - g_assert(token.addr >= QPCI_PIO_LIMIT); - dev->bus->memwrite(dev->bus, token.addr + off, buf, len); -} - -QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) -{ - QPCIBus *bus = dev->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, - }; - QPCIBar bar; - int bar_reg; - uint32_t addr, size; - uint32_t io_type; - uint64_t loc; - - 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; - } - - g_assert(addr); /* Must have *some* size bits */ - - size = 1U << ctz32(addr); - if (sizeptr) { - *sizeptr = size; - } - - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size); - - g_assert(loc >= bus->pio_alloc_ptr); - g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */ - - bus->pio_alloc_ptr = loc + size; - - qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); - } else { - loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size); - - /* Check for space */ - g_assert(loc >= bus->mmio_alloc_ptr); - g_assert(loc + size <= bus->mmio_limit); - - bus->mmio_alloc_ptr = loc + size; - - qpci_config_writel(dev, bar_reg, loc); - } - - bar.addr = loc; - return bar; -} - -void qpci_iounmap(QPCIDevice *dev, QPCIBar bar) -{ - /* FIXME */ -} - -QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr) -{ - QPCIBar bar = { .addr = addr }; - return bar; -} - -void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr) -{ - g_assert(addr); - g_assert(opts); - - opts->arg = addr; - opts->size_arg = sizeof(QPCIAddress); -} diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h deleted file mode 100644 index 590c175190..0000000000 --- a/tests/libqos/pci.h +++ /dev/null @@ -1,129 +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" -#include "libqos/qgraph.h" - -#define QPCI_PIO_LIMIT 0x10000 - -#define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) - -typedef struct QPCIDevice QPCIDevice; -typedef struct QPCIBus QPCIBus; -typedef struct QPCIBar QPCIBar; -typedef struct QPCIAddress QPCIAddress; - -struct QPCIBus { - uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr); - uint16_t (*pio_readw)(QPCIBus *bus, uint32_t addr); - uint32_t (*pio_readl)(QPCIBus *bus, uint32_t addr); - uint64_t (*pio_readq)(QPCIBus *bus, uint32_t addr); - - void (*pio_writeb)(QPCIBus *bus, uint32_t addr, uint8_t value); - void (*pio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); - void (*pio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); - void (*pio_writeq)(QPCIBus *bus, uint32_t addr, uint64_t value); - - void (*memread)(QPCIBus *bus, uint32_t addr, void *buf, size_t len); - void (*memwrite)(QPCIBus *bus, uint32_t addr, const void *buf, size_t len); - - 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); - - QTestState *qts; - uint16_t pio_alloc_ptr; - uint64_t mmio_alloc_ptr, mmio_limit; - bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */ - -}; - -struct QPCIBar { - uint64_t addr; -}; - -struct QPCIDevice -{ - QPCIBus *bus; - int devfn; - bool msix_enabled; - QPCIBar msix_table_bar, msix_pba_bar; - uint64_t msix_table_off, msix_pba_off; -}; - -struct QPCIAddress { - uint32_t devfn; - uint16_t vendor_id; - uint16_t device_id; -}; - -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_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr); - -bool qpci_has_buggy_msi(QPCIDevice *dev); -bool qpci_check_buggy_msi(QPCIDevice *dev); - -void qpci_device_enable(QPCIDevice *dev); -uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id, uint8_t start_addr); -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, QPCIBar token, uint64_t off); -uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off); -uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off); -uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off); - -void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint8_t value); -void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint16_t value); -void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint32_t value); -void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off, - uint64_t value); - -void qpci_memread(QPCIDevice *bus, QPCIBar token, uint64_t off, - void *buf, size_t len); -void qpci_memwrite(QPCIDevice *bus, QPCIBar token, uint64_t off, - const void *buf, size_t len); -QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); -void qpci_iounmap(QPCIDevice *dev, QPCIBar addr); -QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr); - -void qpci_unplug_acpi_device_test(QTestState *qs, const char *id, uint8_t slot); - -void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr); -#endif diff --git a/tests/libqos/ppc64_pseries-machine.c b/tests/libqos/ppc64_pseries-machine.c deleted file mode 100644 index 867f27a3c8..0000000000 --- a/tests/libqos/ppc64_pseries-machine.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "libqos/qgraph.h" -#include "pci-spapr.h" -#include "qemu/module.h" -#include "libqos/malloc-spapr.h" - -typedef struct QSPAPR_pci_host QSPAPR_pci_host; -typedef struct Qppc64_pseriesMachine Qppc64_pseriesMachine; - -struct QSPAPR_pci_host { - QOSGraphObject obj; - QPCIBusSPAPR pci; -}; - -struct Qppc64_pseriesMachine { - QOSGraphObject obj; - QGuestAllocator alloc; - QSPAPR_pci_host bridge; -}; - -/* QSPAPR_pci_host */ - -static QOSGraphObject *QSPAPR_host_get_device(void *obj, const char *device) -{ - QSPAPR_pci_host *host = obj; - if (!g_strcmp0(device, "pci-bus-spapr")) { - return &host->pci.obj; - } - fprintf(stderr, "%s not present in QSPAPR_pci_host\n", device); - g_assert_not_reached(); -} - -static void qos_create_QSPAPR_host(QSPAPR_pci_host *host, - QTestState *qts, - QGuestAllocator *alloc) -{ - host->obj.get_device = QSPAPR_host_get_device; - qpci_init_spapr(&host->pci, qts, alloc); -} - -/* ppc64/pseries machine */ - -static void spapr_destructor(QOSGraphObject *obj) -{ - Qppc64_pseriesMachine *machine = (Qppc64_pseriesMachine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *spapr_get_driver(void *object, const char *interface) -{ - Qppc64_pseriesMachine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in ppc64/pseries\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *spapr_get_device(void *obj, const char *device) -{ - Qppc64_pseriesMachine *machine = obj; - if (!g_strcmp0(device, "spapr-pci-host-bridge")) { - return &machine->bridge.obj; - } - - fprintf(stderr, "%s not present in ppc64/pseries\n", device); - g_assert_not_reached(); -} - -static void *qos_create_machine_spapr(QTestState *qts) -{ - Qppc64_pseriesMachine *machine = g_new0(Qppc64_pseriesMachine, 1); - machine->obj.get_device = spapr_get_device; - machine->obj.get_driver = spapr_get_driver; - machine->obj.destructor = spapr_destructor; - spapr_alloc_init(&machine->alloc, qts, ALLOC_NO_FLAGS); - - qos_create_QSPAPR_host(&machine->bridge, qts, &machine->alloc); - - return &machine->obj; -} - -static void spapr_machine_register_nodes(void) -{ - qos_node_create_machine("ppc64/pseries", qos_create_machine_spapr); - qos_node_create_driver("spapr-pci-host-bridge", NULL); - qos_node_contains("ppc64/pseries", "spapr-pci-host-bridge", NULL); - qos_node_contains("spapr-pci-host-bridge", "pci-bus-spapr", NULL); -} - -libqos_init(spapr_machine_register_nodes); - diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c deleted file mode 100644 index 7a7ae2a19e..0000000000 --- a/tests/libqos/qgraph.c +++ /dev/null @@ -1,759 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/queue.h" -#include "libqos/qgraph_internal.h" -#include "libqos/qgraph.h" - -#define QGRAPH_PRINT_DEBUG 0 -#define QOS_ROOT "" -typedef struct QOSStackElement QOSStackElement; - -/* Graph Edge.*/ -struct QOSGraphEdge { - QOSEdgeType type; - char *dest; - void *arg; /* just for QEDGE_CONTAINS - * and QEDGE_CONSUMED_BY */ - char *extra_device_opts; /* added to -device option, "," is - * automatically added - */ - char *before_cmd_line; /* added before node cmd_line */ - char *after_cmd_line; /* added after -device options */ - char *edge_name; /* used by QEDGE_CONTAINS */ - QSLIST_ENTRY(QOSGraphEdge) edge_list; -}; - -typedef QSLIST_HEAD(, QOSGraphEdge) QOSGraphEdgeList; - -/** - * Stack used to keep track of the discovered path when using - * the DFS algorithm - */ -struct QOSStackElement { - QOSGraphNode *node; - QOSStackElement *parent; - QOSGraphEdge *parent_edge; - int length; -}; - -/* Each enty in these hash table will consist of <string, node/edge> pair. */ -static GHashTable *edge_table; -static GHashTable *node_table; - -/* stack used by the DFS algorithm to store the path from machine to test */ -static QOSStackElement qos_node_stack[QOS_PATH_MAX_ELEMENT_SIZE]; -static int qos_node_tos; - -/** - * add_edge(): creates an edge of type @type - * from @source to @dest node, and inserts it in the - * edges hash table - * - * Nodes @source and @dest do not necessarily need to exist. - * Possibility to add also options (see #QOSGraphEdgeOptions) - * edge->edge_name is used as identifier for get_device relationships, - * so by default is equal to @dest. - */ -static void add_edge(const char *source, const char *dest, - QOSEdgeType type, QOSGraphEdgeOptions *opts) -{ - char *key; - QOSGraphEdgeList *list = g_hash_table_lookup(edge_table, source); - QOSGraphEdgeOptions def_opts = { }; - - if (!list) { - list = g_new0(QOSGraphEdgeList, 1); - key = g_strdup(source); - g_hash_table_insert(edge_table, key, list); - } - - if (!opts) { - opts = &def_opts; - } - - QOSGraphEdge *edge = g_new0(QOSGraphEdge, 1); - edge->type = type; - edge->dest = g_strdup(dest); - edge->edge_name = g_strdup(opts->edge_name ?: dest); - edge->arg = g_memdup(opts->arg, opts->size_arg); - - edge->before_cmd_line = - opts->before_cmd_line ? g_strconcat(" ", opts->before_cmd_line, NULL) : NULL; - edge->extra_device_opts = - opts->extra_device_opts ? g_strconcat(",", opts->extra_device_opts, NULL) : NULL; - edge->after_cmd_line = - opts->after_cmd_line ? g_strconcat(" ", opts->after_cmd_line, NULL) : NULL; - - QSLIST_INSERT_HEAD(list, edge, edge_list); -} - -/* destroy_edges(): frees all edges inside a given @list */ -static void destroy_edges(void *list) -{ - QOSGraphEdge *temp; - QOSGraphEdgeList *elist = list; - - while (!QSLIST_EMPTY(elist)) { - temp = QSLIST_FIRST(elist); - QSLIST_REMOVE_HEAD(elist, edge_list); - g_free(temp->dest); - g_free(temp->before_cmd_line); - g_free(temp->after_cmd_line); - g_free(temp->extra_device_opts); - g_free(temp->edge_name); - g_free(temp->arg); - g_free(temp); - } - g_free(elist); -} - -/** - * create_node(): creates a node @name of type @type - * and inserts it to the nodes hash table. - * By default, node is not available. - */ -static QOSGraphNode *create_node(const char *name, QOSNodeType type) -{ - if (g_hash_table_lookup(node_table, name)) { - g_printerr("Node %s already created\n", name); - abort(); - } - - QOSGraphNode *node = g_new0(QOSGraphNode, 1); - node->type = type; - node->available = false; - node->name = g_strdup(name); - g_hash_table_insert(node_table, node->name, node); - return node; -} - -/** - * destroy_node(): frees a node @val from the nodes hash table. - * Note that node->name is not free'd since it will represent the - * hash table key - */ -static void destroy_node(void *val) -{ - QOSGraphNode *node = val; - g_free(node->command_line); - g_free(node); -} - -/** - * destroy_string(): frees @key from the nodes hash table. - * Actually frees the node->name - */ -static void destroy_string(void *key) -{ - g_free(key); -} - -/** - * search_node(): search for a node @key in the nodes hash table - * Returns the QOSGraphNode if found, #NULL otherwise - */ -static QOSGraphNode *search_node(const char *key) -{ - return g_hash_table_lookup(node_table, key); -} - -/** - * get_edgelist(): returns the edge list (value) assigned to - * the @key in the edge hash table. - * This list will contain all edges with source equal to @key - * - * Returns: on success: the %QOSGraphEdgeList - * otherwise: abort() - */ -static QOSGraphEdgeList *get_edgelist(const char *key) -{ - return g_hash_table_lookup(edge_table, key); -} - -/** - * search_list_edges(): search for an edge with destination @dest - * in the given @edgelist. - * - * Returns: on success: the %QOSGraphEdge - * otherwise: #NULL - */ -static QOSGraphEdge *search_list_edges(QOSGraphEdgeList *edgelist, - const char *dest) -{ - QOSGraphEdge *tmp, *next; - if (!edgelist) { - return NULL; - } - QSLIST_FOREACH_SAFE(tmp, edgelist, edge_list, next) { - if (g_strcmp0(tmp->dest, dest) == 0) { - break; - } - } - return tmp; -} - -/** - * search_machine(): search for a machine @name in the node hash - * table. A machine is the child of the root node. - * This function forces the research in the childs of the root, - * to check the node is a proper machine - * - * Returns: on success: the %QOSGraphNode - * otherwise: #NULL - */ -static QOSGraphNode *search_machine(const char *name) -{ - QOSGraphNode *n; - QOSGraphEdgeList *root_list = get_edgelist(QOS_ROOT); - QOSGraphEdge *e = search_list_edges(root_list, name); - if (!e) { - return NULL; - } - n = search_node(e->dest); - if (n->type == QNODE_MACHINE) { - return n; - } - return NULL; -} - -/** - * create_interface(): checks if there is already - * a node @node in the node hash table, if not - * creates a node @node of type #QNODE_INTERFACE - * and inserts it. If there is one, check it's - * a #QNODE_INTERFACE and abort() if it's not. - */ -static void create_interface(const char *node) -{ - QOSGraphNode *interface; - interface = search_node(node); - if (!interface) { - create_node(node, QNODE_INTERFACE); - } else if (interface->type != QNODE_INTERFACE) { - fprintf(stderr, "Error: Node %s is not an interface\n", node); - abort(); - } -} - -/** - * build_machine_cmd_line(): builds the command line for the machine - * @node. The node name must be a valid qemu identifier, since it - * will be used to build the command line. - * - * It is also possible to pass an optional @args that will be - * concatenated to the command line. - * - * For machines, prepend -M to the machine name. ", @rgs" is added - * after the -M <machine> command. - */ -static void build_machine_cmd_line(QOSGraphNode *node, const char *args) -{ - char *machine = qos_get_machine_type(node->name); - if (args) { - node->command_line = g_strconcat("-M ", machine, ",", args, NULL); - } else { - node->command_line = g_strconcat("-M ", machine, " ", NULL); - } -} - -/** - * build_driver_cmd_line(): builds the command line for the driver - * @node. The node name must be a valid qemu identifier, since it - * will be used to build the command line. - * - * Driver do not need additional command line, since it will be - * provided by the edge options. - * - * For drivers, prepend -device to the node name. - */ -static void build_driver_cmd_line(QOSGraphNode *node) -{ - node->command_line = g_strconcat(" -device ", node->name, NULL); -} - -/* qos_print_cb(): callback prints all path found by the DFS algorithm. */ -static void qos_print_cb(QOSGraphNode *path, int length) -{ - #if QGRAPH_PRINT_DEBUG - printf("%d elements\n", length); - - if (!path) { - return; - } - - while (path->path_edge) { - printf("%s ", path->name); - switch (path->path_edge->type) { - case QEDGE_PRODUCES: - printf("--PRODUCES--> "); - break; - case QEDGE_CONSUMED_BY: - printf("--CONSUMED_BY--> "); - break; - case QEDGE_CONTAINS: - printf("--CONTAINS--> "); - break; - } - path = search_node(path->path_edge->dest); - } - - printf("%s\n\n", path->name); - #endif -} - -/* qos_push(): push a node @el and edge @e in the qos_node_stack */ -static void qos_push(QOSGraphNode *el, QOSStackElement *parent, - QOSGraphEdge *e) -{ - int len = 0; /* root is not counted */ - if (qos_node_tos == QOS_PATH_MAX_ELEMENT_SIZE) { - g_printerr("QOSStack: full stack, cannot push"); - abort(); - } - - if (parent) { - len = parent->length + 1; - } - qos_node_stack[qos_node_tos++] = (QOSStackElement) { - .node = el, - .parent = parent, - .parent_edge = e, - .length = len, - }; -} - -/* qos_tos(): returns the top of stack, without popping */ -static QOSStackElement *qos_tos(void) -{ - return &qos_node_stack[qos_node_tos - 1]; -} - -/* qos_pop(): pops an element from the tos, setting it unvisited*/ -static QOSStackElement *qos_pop(void) -{ - if (qos_node_tos == 0) { - g_printerr("QOSStack: empty stack, cannot pop"); - abort(); - } - QOSStackElement *e = qos_tos(); - e->node->visited = false; - qos_node_tos--; - return e; -} - -/** - * qos_reverse_path(): reverses the found path, going from - * test-to-machine to machine-to-test - */ -static QOSGraphNode *qos_reverse_path(QOSStackElement *el) -{ - if (!el) { - return NULL; - } - - el->node->path_edge = NULL; - - while (el->parent) { - el->parent->node->path_edge = el->parent_edge; - el = el->parent; - } - - return el->node; -} - -/** - * qos_traverse_graph(): graph-walking algorithm, using Depth First Search it - * starts from the root @machine and walks all possible path until it - * reaches a test node. - * At that point, it reverses the path found and invokes the @callback. - * - * Being Depth First Search, time complexity is O(|V| + |E|), while - * space is O(|V|). In this case, the maximum stack size is set by - * QOS_PATH_MAX_ELEMENT_SIZE. - */ -static void qos_traverse_graph(QOSGraphNode *root, QOSTestCallback callback) -{ - QOSGraphNode *v, *dest_node, *path; - QOSStackElement *s_el; - QOSGraphEdge *e, *next; - QOSGraphEdgeList *list; - - qos_push(root, NULL, NULL); - - while (qos_node_tos > 0) { - s_el = qos_tos(); - v = s_el->node; - if (v->visited) { - qos_pop(); - continue; - } - v->visited = true; - list = get_edgelist(v->name); - if (!list) { - qos_pop(); - if (v->type == QNODE_TEST) { - v->visited = false; - path = qos_reverse_path(s_el); - callback(path, s_el->length); - } - } else { - QSLIST_FOREACH_SAFE(e, list, edge_list, next) { - dest_node = search_node(e->dest); - - if (!dest_node) { - fprintf(stderr, "node %s in %s -> %s does not exist\n", - e->dest, v->name, e->dest); - abort(); - } - - if (!dest_node->visited && dest_node->available) { - qos_push(dest_node, s_el, e); - } - } - } - } -} - -/* QGRAPH API*/ - -QOSGraphNode *qos_graph_get_node(const char *key) -{ - return search_node(key); -} - -bool qos_graph_has_node(const char *node) -{ - QOSGraphNode *n = search_node(node); - return n != NULL; -} - -QOSNodeType qos_graph_get_node_type(const char *node) -{ - QOSGraphNode *n = search_node(node); - if (n) { - return n->type; - } - return -1; -} - -bool qos_graph_get_node_availability(const char *node) -{ - QOSGraphNode *n = search_node(node); - if (n) { - return n->available; - } - return false; -} - -QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest) -{ - QOSGraphEdgeList *list = get_edgelist(node); - return search_list_edges(list, dest); -} - -QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge) -{ - if (!edge) { - return -1; - } - return edge->type;; -} - -char *qos_graph_edge_get_dest(QOSGraphEdge *edge) -{ - if (!edge) { - return NULL; - } - return edge->dest; -} - -void *qos_graph_edge_get_arg(QOSGraphEdge *edge) -{ - if (!edge) { - return NULL; - } - return edge->arg; -} - -char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge) -{ - if (!edge) { - return NULL; - } - return edge->after_cmd_line; -} - -char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge) -{ - if (!edge) { - return NULL; - } - return edge->before_cmd_line; -} - -char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge) -{ - if (!edge) { - return NULL; - } - return edge->extra_device_opts; -} - -char *qos_graph_edge_get_name(QOSGraphEdge *edge) -{ - if (!edge) { - return NULL; - } - return edge->edge_name; -} - -bool qos_graph_has_edge(const char *start, const char *dest) -{ - QOSGraphEdgeList *list = get_edgelist(start); - QOSGraphEdge *e = search_list_edges(list, dest); - return e != NULL; -} - -QOSGraphNode *qos_graph_get_machine(const char *node) -{ - return search_machine(node); -} - -bool qos_graph_has_machine(const char *node) -{ - QOSGraphNode *m = search_machine(node); - return m != NULL; -} - -void qos_print_graph(void) -{ - qos_graph_foreach_test_path(qos_print_cb); -} - -void qos_graph_init(void) -{ - if (!node_table) { - node_table = g_hash_table_new_full(g_str_hash, g_str_equal, - destroy_string, destroy_node); - create_node(QOS_ROOT, QNODE_DRIVER); - } - - if (!edge_table) { - edge_table = g_hash_table_new_full(g_str_hash, g_str_equal, - destroy_string, destroy_edges); - } -} - -void qos_graph_destroy(void) -{ - if (node_table) { - g_hash_table_destroy(node_table); - } - - if (edge_table) { - g_hash_table_destroy(edge_table); - } - - node_table = NULL; - edge_table = NULL; -} - -void qos_node_destroy(void *key) -{ - g_hash_table_remove(node_table, key); -} - -void qos_edge_destroy(void *key) -{ - g_hash_table_remove(edge_table, key); -} - -void qos_add_test(const char *name, const char *interface, - QOSTestFunc test_func, QOSGraphTestOptions *opts) -{ - QOSGraphNode *node; - char *test_name = g_strdup_printf("%s-tests/%s", interface, name);; - QOSGraphTestOptions def_opts = { }; - - if (!opts) { - opts = &def_opts; - } - node = create_node(test_name, QNODE_TEST); - node->u.test.function = test_func; - node->u.test.arg = opts->arg; - assert(!opts->edge.arg); - assert(!opts->edge.size_arg); - - node->u.test.before = opts->before; - node->u.test.subprocess = opts->subprocess; - node->available = true; - add_edge(interface, test_name, QEDGE_CONSUMED_BY, &opts->edge); - g_free(test_name); -} - -void qos_node_create_machine(const char *name, QOSCreateMachineFunc function) -{ - qos_node_create_machine_args(name, function, NULL); -} - -void qos_node_create_machine_args(const char *name, - QOSCreateMachineFunc function, - const char *opts) -{ - QOSGraphNode *node = create_node(name, QNODE_MACHINE); - build_machine_cmd_line(node, opts); - node->u.machine.constructor = function; - add_edge(QOS_ROOT, name, QEDGE_CONTAINS, NULL); -} - -void qos_node_create_driver(const char *name, QOSCreateDriverFunc function) -{ - QOSGraphNode *node = create_node(name, QNODE_DRIVER); - build_driver_cmd_line(node); - node->u.driver.constructor = function; -} - -void qos_node_contains(const char *container, const char *contained, - QOSGraphEdgeOptions *opts, ...) -{ - va_list va; - - if (opts == NULL) { - add_edge(container, contained, QEDGE_CONTAINS, NULL); - return; - } - - va_start(va, opts); - do { - add_edge(container, contained, QEDGE_CONTAINS, opts); - opts = va_arg(va, QOSGraphEdgeOptions *); - } while (opts != NULL); - - va_end(va); -} - -void qos_node_produces(const char *producer, const char *interface) -{ - create_interface(interface); - add_edge(producer, interface, QEDGE_PRODUCES, NULL); -} - -void qos_node_consumes(const char *consumer, const char *interface, - QOSGraphEdgeOptions *opts) -{ - create_interface(interface); - add_edge(interface, consumer, QEDGE_CONSUMED_BY, opts); -} - -void qos_graph_node_set_availability(const char *node, bool av) -{ - QOSGraphEdgeList *elist; - QOSGraphNode *n = search_node(node); - QOSGraphEdge *e, *next; - if (!n) { - return; - } - n->available = av; - elist = get_edgelist(node); - if (!elist) { - return; - } - QSLIST_FOREACH_SAFE(e, elist, edge_list, next) { - if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES) { - qos_graph_node_set_availability(e->dest, av); - } - } -} - -void qos_graph_foreach_test_path(QOSTestCallback fn) -{ - QOSGraphNode *root = qos_graph_get_node(QOS_ROOT); - qos_traverse_graph(root, fn); -} - -QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts) -{ - QOSGraphObject *obj; - - g_assert(node->type == QNODE_MACHINE); - obj = node->u.machine.constructor(qts); - obj->free = g_free; - return obj; -} - -QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent, - QGuestAllocator *alloc, void *arg) -{ - QOSGraphObject *obj; - - g_assert(node->type == QNODE_DRIVER); - obj = node->u.driver.constructor(parent, alloc, arg); - obj->free = g_free; - return obj; -} - -void qos_object_destroy(QOSGraphObject *obj) -{ - if (!obj) { - return; - } - if (obj->destructor) { - obj->destructor(obj); - } - if (obj->free) { - obj->free(obj); - } -} - -void qos_object_queue_destroy(QOSGraphObject *obj) -{ - g_test_queue_destroy((GDestroyNotify) qos_object_destroy, obj); -} - -void qos_object_start_hw(QOSGraphObject *obj) -{ - if (obj->start_hw) { - obj->start_hw(obj); - } -} - -char *qos_get_machine_type(char *name) -{ - while (*name != '\0' && *name != '/') { - name++; - } - - if (!*name || !name[1]) { - fprintf(stderr, "Machine name has to be of the form <arch>/<machine>\n"); - abort(); - } - - return name + 1; -} - -void qos_delete_cmd_line(const char *name) -{ - QOSGraphNode *node = search_node(name); - if (node) { - g_free(node->command_line); - node->command_line = NULL; - } -} diff --git a/tests/libqos/qgraph.h b/tests/libqos/qgraph.h deleted file mode 100644 index 3a25dda4b2..0000000000 --- a/tests/libqos/qgraph.h +++ /dev/null @@ -1,574 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef QGRAPH_H -#define QGRAPH_H - -#include <gmodule.h> -#include "qemu/module.h" -#include "malloc.h" - -/* maximum path length */ -#define QOS_PATH_MAX_ELEMENT_SIZE 50 - -typedef struct QOSGraphObject QOSGraphObject; -typedef struct QOSGraphNode QOSGraphNode; -typedef struct QOSGraphEdge QOSGraphEdge; -typedef struct QOSGraphNodeOptions QOSGraphNodeOptions; -typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions; -typedef struct QOSGraphTestOptions QOSGraphTestOptions; - -/* Constructor for drivers, machines and test */ -typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc, - void *addr); -typedef void *(*QOSCreateMachineFunc) (QTestState *qts); -typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc); - -/* QOSGraphObject functions */ -typedef void *(*QOSGetDriver) (void *object, const char *interface); -typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name); -typedef void (*QOSDestructorFunc) (QOSGraphObject *object); -typedef void (*QOSStartFunct) (QOSGraphObject *object); - -/* Test options functions */ -typedef void *(*QOSBeforeTest) (GString *cmd_line, void *arg); - -/** - * SECTION: qgraph.h - * @title: Qtest Driver Framework - * @short_description: interfaces to organize drivers and tests - * as nodes in a graph - * - * This Qgraph API provides all basic functions to create a graph - * and instantiate nodes representing machines, drivers and tests - * representing their relations with CONSUMES, PRODUCES, and CONTAINS - * edges. - * - * The idea is to have a framework where each test asks for a specific - * driver, and the framework takes care of allocating the proper devices - * required and passing the correct command line arguments to QEMU. - * - * A node can be of four types: - * - QNODE_MACHINE: for example "arm/raspi2" - * - QNODE_DRIVER: for example "generic-sdhci" - * - QNODE_INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers) - * an interface is not explicitly created, it will be auto- - * matically instantiated when a node consumes or produces - * it. - * - QNODE_TEST: for example "sdhci-test", consumes an interface and tests - * the functions provided - * - * Notes for the nodes: - * - QNODE_MACHINE: each machine struct must have a QGuestAllocator and - * implement get_driver to return the allocator passing - * "memory". The function can also return NULL if the - * allocator is not set. - * - QNODE_DRIVER: driver names must be unique, and machines and nodes - * planned to be "consumed" by other nodes must match QEMU - * drivers name, otherwise they won't be discovered - * - * An edge relation between two nodes (drivers or machines) X and Y can be: - * - X CONSUMES Y: Y can be plugged into X - * - X PRODUCES Y: X provides the interface Y - * - X CONTAINS Y: Y is part of X component - * - * Basic framework steps are the following: - * - All nodes and edges are created in their respective - * machine/driver/test files - * - The framework starts QEMU and asks for a list of available devices - * and machines (note that only machines and "consumed" nodes are mapped - * 1:1 with QEMU devices) - * - The framework walks the graph starting from the available machines and - * performs a Depth First Search for tests - * - Once a test is found, the path is walked again and all drivers are - * allocated accordingly and the final interface is passed to the test - * - The test is executed - * - Unused objects are cleaned and the path discovery is continued - * - * Depending on the QEMU binary used, only some drivers/machines will be - * available and only test that are reached by them will be executed. - * - * <example> - * <title>Creating new driver an its interface</title> - * <programlisting> - #include "libqos/qgraph.h" - - struct My_driver { - QOSGraphObject obj; - Node_produced prod; - Node_contained cont; - } - - static void my_destructor(QOSGraphObject *obj) - { - g_free(obj); - } - - static void my_get_driver(void *object, const char *interface) { - My_driver *dev = object; - if (!g_strcmp0(interface, "my_interface")) { - return &dev->prod; - } - abort(); - } - - static void my_get_device(void *object, const char *device) { - My_driver *dev = object; - if (!g_strcmp0(device, "my_driver_contained")) { - return &dev->cont; - } - abort(); - } - - static void *my_driver_constructor(void *node_consumed, - QOSGraphObject *alloc) - { - My_driver dev = g_new(My_driver, 1); - // get the node pointed by the produce edge - dev->obj.get_driver = my_get_driver; - // get the node pointed by the contains - dev->obj.get_device = my_get_device; - // free the object - dev->obj.destructor = my_destructor; - do_something_with_node_consumed(node_consumed); - // set all fields of contained device - init_contained_device(&dev->cont); - return &dev->obj; - } - - static void register_my_driver(void) - { - qos_node_create_driver("my_driver", my_driver_constructor); - // contained drivers don't need a constructor, - // they will be init by the parent. - qos_node_create_driver("my_driver_contained", NULL); - - // For the sake of this example, assume machine x86_64/pc contains - // "other_node". - // This relation, along with the machine and "other_node" creation, - // should be defined in the x86_64_pc-machine.c file. - // "my_driver" will then consume "other_node" - qos_node_contains("my_driver", "my_driver_contained"); - qos_node_produces("my_driver", "my_interface"); - qos_node_consumes("my_driver", "other_node"); - } - * </programlisting> - * </example> - * - * In the above example, all possible types of relations are created: - * node "my_driver" consumes, contains and produces other nodes. - * more specifically: - * x86_64/pc -->contains--> other_node <--consumes-- my_driver - * | - * my_driver_contained <--contains--+ - * | - * my_interface <--produces--+ - * - * or inverting the consumes edge in consumed_by: - * - * x86_64/pc -->contains--> other_node --consumed_by--> my_driver - * | - * my_driver_contained <--contains--+ - * | - * my_interface <--produces--+ - * - * <example> - * <title>Creating new test</title> - * <programlisting> - * #include "libqos/qgraph.h" - * - * static void my_test_function(void *obj, void *data) - * { - * Node_produced *interface_to_test = obj; - * // test interface_to_test - * } - * - * static void register_my_test(void) - * { - * qos_add_test("my_interface", "my_test", my_test_function); - * } - * - * libqos_init(register_my_test); - * - * </programlisting> - * </example> - * - * Here a new test is created, consuming "my_interface" node - * and creating a valid path from a machine to a test. - * Final graph will be like this: - * x86_64/pc -->contains--> other_node <--consumes-- my_driver - * | - * my_driver_contained <--contains--+ - * | - * my_test --consumes--> my_interface <--produces--+ - * - * or inverting the consumes edge in consumed_by: - * - * x86_64/pc -->contains--> other_node --consumed_by--> my_driver - * | - * my_driver_contained <--contains--+ - * | - * my_test <--consumed_by-- my_interface <--produces--+ - * - * Assuming there the binary is - * QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64 - * a valid test path will be: - * "/x86_64/pc/other_node/my_driver/my_interface/my_test". - * - * Additional examples are also in libqos/test-qgraph.c - * - * Command line: - * Command line is built by using node names and optional arguments - * passed by the user when building the edges. - * - * There are three types of command line arguments: - * - in node : created from the node name. For example, machines will - * have "-M <machine>" to its command line, while devices - * "-device <device>". It is automatically done by the - * framework. - * - after node : added as additional argument to the node name. - * This argument is added optionally when creating edges, - * by setting the parameter @after_cmd_line and - * @extra_edge_opts in #QOSGraphEdgeOptions. - * The framework automatically adds - * a comma before @extra_edge_opts, - * because it is going to add attributes - * after the destination node pointed by - * the edge containing these options, and automatically - * adds a space before @after_cmd_line, because it - * adds an additional device, not an attribute. - * - before node : added as additional argument to the node name. - * This argument is added optionally when creating edges, - * by setting the parameter @before_cmd_line in - * #QOSGraphEdgeOptions. This attribute - * is going to add attributes before the destination node - * pointed by the edge containing these options. It is - * helpful to commands that are not node-representable, - * such as "-fdsev" or "-netdev". - * - * While adding command line in edges is always used, not all nodes names are - * used in every path walk: this is because the contained or produced ones - * are already added by QEMU, so only nodes that "consumes" will be used to - * build the command line. Also, nodes that will have { "abstract" : true } - * as QMP attribute will loose their command line, since they are not proper - * devices to be added in QEMU. - * - * Example: - * - QOSGraphEdgeOptions opts = { - .arg = NULL, - .size_arg = 0, - .after_cmd_line = "-device other", - .before_cmd_line = "-netdev something", - .extra_edge_opts = "addr=04.0", - }; - QOSGraphNode * node = qos_node_create_driver("my_node", constructor); - qos_node_consumes_args("my_node", "interface", &opts); - * - * Will produce the following command line: - * "-netdev something -device my_node,addr=04.0 -device other" - */ - -/** - * Edge options to be passed to the contains/consumes *_args function. - */ -struct QOSGraphEdgeOptions { - void *arg; /* - * optional arg that will be used by - * dest edge - */ - uint32_t size_arg; /* - * optional arg size that will be used by - * dest edge - */ - const char *extra_device_opts;/* - *optional additional command line for dest - * edge, used to add additional attributes - * *after* the node command line, the - * framework automatically prepends "," - * to this argument. - */ - const char *before_cmd_line; /* - * optional additional command line for dest - * edge, used to add additional attributes - * *before* the node command line, usually - * other non-node represented commands, - * like "-fdsev synt" - */ - const char *after_cmd_line; /* - * optional extra command line to be added - * after the device command. This option - * is used to add other devices - * command line that depend on current node. - * Automatically prepends " " to this - * argument - */ - const char *edge_name; /* - * optional edge to differentiate multiple - * devices with same node name - */ -}; - -/** - * Test options to be passed to the test functions. - */ -struct QOSGraphTestOptions { - QOSGraphEdgeOptions edge; /* edge arguments that will be used by test. - * Note that test *does not* use edge_name, - * and uses instead arg and size_arg as - * data arg for its test function. - */ - void *arg; /* passed to the .before function, or to the - * test function if there is no .before - * function - */ - QOSBeforeTest before; /* executed before the test. Can add - * additional parameters to the command line - * and modify the argument to the test function. - */ - bool subprocess; /* run the test in a subprocess */ -}; - -/** - * Each driver, test or machine of this framework will have a - * QOSGraphObject as first field. - * - * This set of functions offered by QOSGraphObject are executed - * in different stages of the framework: - * - get_driver / get_device : Once a machine-to-test path has been - * found, the framework traverses it again and allocates all the - * nodes, using the provided constructor. To satisfy their relations, - * i.e. for produces or contains, where a struct constructor needs - * an external parameter represented by the previous node, - * the framework will call get_device (for contains) or - * get_driver (for produces), depending on the edge type, passing - * them the name of the next node to be taken and getting from them - * the corresponding pointer to the actual structure of the next node to - * be used in the path. - * - * - start_hw: This function is executed after all the path objects - * have been allocated, but before the test is run. It starts the hw, setting - * the initial configurations (*_device_enable) and making it ready for the - * test. - * - * - destructor: Opposite to the node constructor, destroys the object. - * This function is called after the test has been executed, and performs - * a complete cleanup of each node allocated field. In case no constructor - * is provided, no destructor will be called. - * - */ -struct QOSGraphObject { - /* for produces edges, returns void * */ - QOSGetDriver get_driver; - /* for contains edges, returns a QOSGraphObject * */ - QOSGetDevice get_device; - /* start the hw, get ready for the test */ - QOSStartFunct start_hw; - /* destroy this QOSGraphObject */ - QOSDestructorFunc destructor; - /* free the memory associated to the QOSGraphObject and its contained - * children */ - GDestroyNotify free; -}; - -/** - * qos_graph_init(): initialize the framework, creates two hash - * tables: one for the nodes and another for the edges. - */ -void qos_graph_init(void); - -/** - * qos_graph_destroy(): deallocates all the hash tables, - * freeing all nodes and edges. - */ -void qos_graph_destroy(void); - -/** - * qos_node_destroy(): removes and frees a node from the, - * nodes hash table. - */ -void qos_node_destroy(void *key); - -/** - * qos_edge_destroy(): removes and frees an edge from the, - * edges hash table. - */ -void qos_edge_destroy(void *key); - -/** - * qos_add_test(): adds a test node @name to the nodes hash table. - * - * The test will consume a @interface node, and once the - * graph walking algorithm has found it, the @test_func will be - * executed. It also has the possibility to - * add an optional @opts (see %QOSGraphNodeOptions). - * - * For tests, opts->edge.arg and size_arg represent the arg to pass - * to @test_func - */ -void qos_add_test(const char *name, const char *interface, - QOSTestFunc test_func, - QOSGraphTestOptions *opts); - -/** - * qos_node_create_machine(): creates the machine @name and - * adds it to the node hash table. - * - * This node will be of type QNODE_MACHINE and have @function - * as constructor - */ -void qos_node_create_machine(const char *name, QOSCreateMachineFunc function); - -/** - * qos_node_create_machine_args(): same as qos_node_create_machine, - * but with the possibility to add an optional ", @opts" after -M machine - * command line. - */ -void qos_node_create_machine_args(const char *name, - QOSCreateMachineFunc function, - const char *opts); - -/** - * qos_node_create_driver(): creates the driver @name and - * adds it to the node hash table. - * - * This node will be of type QNODE_DRIVER and have @function - * as constructor - */ -void qos_node_create_driver(const char *name, QOSCreateDriverFunc function); - -/** - * qos_node_contains(): creates one or more edges of type QEDGE_CONTAINS - * and adds them to the edge list mapped to @container in the - * edge hash table. - * - * The edges will have @container as source and @contained as destination. - * - * If @opts is NULL, a single edge will be added with no options. - * If @opts is non-NULL, the arguments after @contained represent a - * NULL-terminated list of %QOSGraphEdgeOptions structs, and an - * edge will be added for each of them. - * - * This function can be useful when there are multiple devices - * with the same node name contained in a machine/other node - * - * For example, if "arm/raspi2" contains 2 "generic-sdhci" - * devices, the right commands will be: - * qos_node_create_machine("arm/raspi2"); - * qos_node_create_driver("generic-sdhci", constructor); - * //assume rest of the fields are set NULL - * QOSGraphEdgeOptions op1 = { .edge_name = "emmc" }; - * QOSGraphEdgeOptions op2 = { .edge_name = "sdcard" }; - * qos_node_contains("arm/raspi2", "generic-sdhci", &op1, &op2, NULL); - * - * Of course this also requires that the @container's get_device function - * should implement a case for "emmc" and "sdcard". - * - * For contains, op1.arg and op1.size_arg represent the arg to pass - * to @contained constructor to properly initialize it. - */ -void qos_node_contains(const char *container, const char *contained, - QOSGraphEdgeOptions *opts, ...); - -/** - * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and - * adds it to the edge list mapped to @producer in the - * edge hash table. - * - * This edge will have @producer as source and @interface as destination. - */ -void qos_node_produces(const char *producer, const char *interface); - -/** - * qos_node_consumes(): creates an edge of type QEDGE_CONSUMED_BY and - * adds it to the edge list mapped to @interface in the - * edge hash table. - * - * This edge will have @interface as source and @consumer as destination. - * It also has the possibility to add an optional @opts - * (see %QOSGraphEdgeOptions) - */ -void qos_node_consumes(const char *consumer, const char *interface, - QOSGraphEdgeOptions *opts); - -/** - * qos_invalidate_command_line(): invalidates current command line, so that - * qgraph framework cannot try to cache the current command line and - * forces QEMU to restart. - */ -void qos_invalidate_command_line(void); - -/** - * qos_get_current_command_line(): return the command line required by the - * machine and driver objects. This is the same string that was passed to - * the test's "before" callback, if any. - */ -const char *qos_get_current_command_line(void); - -/** - * qos_allocate_objects(): - * @qts: The #QTestState that will be referred to by the machine object. - * @alloc: Where to store the allocator for the machine object, or %NULL. - * - * Allocate driver objects for the current test - * path, but relative to the QTestState @qts. - * - * Returns a test object just like the one that was passed to - * the test function, but relative to @qts. - */ -void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc); - -/** - * qos_object_destroy(): calls the destructor for @obj - */ -void qos_object_destroy(QOSGraphObject *obj); - -/** - * qos_object_queue_destroy(): queue the destructor for @obj so that it is - * called at the end of the test - */ -void qos_object_queue_destroy(QOSGraphObject *obj); - -/** - * qos_object_start_hw(): calls the start_hw function for @obj - */ -void qos_object_start_hw(QOSGraphObject *obj); - -/** - * qos_machine_new(): instantiate a new machine node - * @node: A machine node to be instantiated - * @qts: The #QTestState that will be referred to by the machine object. - * - * Returns a machine object. - */ -QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts); - -/** - * qos_machine_new(): instantiate a new driver node - * @node: A driver node to be instantiated - * @parent: A #QOSGraphObject to be consumed by the new driver node - * @alloc: An allocator to be used by the new driver node. - * @arg: The argument for the consumed-by edge to @node. - * - * Calls the constructor for the driver object. - */ -QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent, - QGuestAllocator *alloc, void *arg); - - -#endif diff --git a/tests/libqos/qgraph_internal.h b/tests/libqos/qgraph_internal.h deleted file mode 100644 index f4734c8681..0000000000 --- a/tests/libqos/qgraph_internal.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef QGRAPH_INTERNAL_H -#define QGRAPH_INTERNAL_H - -/* This header is declaring additional helper functions defined in - * libqos/qgraph.c - * It should not be included in tests - */ - -#include "libqos/qgraph.h" - -typedef struct QOSGraphMachine QOSGraphMachine; -typedef enum QOSEdgeType QOSEdgeType; -typedef enum QOSNodeType QOSNodeType; - -/* callback called when the walk path algorithm found a - * valid path - */ -typedef void (*QOSTestCallback) (QOSGraphNode *path, int len); - -/* edge types*/ -enum QOSEdgeType { - QEDGE_CONTAINS, - QEDGE_PRODUCES, - QEDGE_CONSUMED_BY -}; - -/* node types*/ -enum QOSNodeType { - QNODE_MACHINE, - QNODE_DRIVER, - QNODE_INTERFACE, - QNODE_TEST -}; - -/* Graph Node */ -struct QOSGraphNode { - QOSNodeType type; - bool available; /* set by QEMU via QMP, used during graph walk */ - bool visited; /* used during graph walk */ - char *name; /* used to identify the node */ - char *command_line; /* used to start QEMU at test execution */ - union { - struct { - QOSCreateDriverFunc constructor; - } driver; - struct { - QOSCreateMachineFunc constructor; - } machine; - struct { - QOSTestFunc function; - void *arg; - QOSBeforeTest before; - bool subprocess; - } test; - } u; - - /** - * only used when traversing the path, never rely on that except in the - * qos_traverse_graph callback function - */ - QOSGraphEdge *path_edge; -}; - -/** - * qos_graph_get_node(): returns the node mapped to that @key. - * It performs an hash map search O(1) - * - * Returns: on success: the %QOSGraphNode - * otherwise: #NULL - */ -QOSGraphNode *qos_graph_get_node(const char *key); - -/** - * qos_graph_has_node(): returns #TRUE if the node - * has map has a node mapped to that @key. - */ -bool qos_graph_has_node(const char *node); - -/** - * qos_graph_get_node_type(): returns the %QOSNodeType - * of the node @node. - * It performs an hash map search O(1) - * Returns: on success: the %QOSNodeType - * otherwise: #-1 - */ -QOSNodeType qos_graph_get_node_type(const char *node); - -/** - * qos_graph_get_node_availability(): returns the availability (boolean) - * of the node @node. - */ -bool qos_graph_get_node_availability(const char *node); - -/** - * qos_graph_get_edge(): returns the edge - * linking of the node @node with @dest. - * - * Returns: on success: the %QOSGraphEdge - * otherwise: #NULL - */ -QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest); - -/** - * qos_graph_edge_get_type(): returns the edge type - * of the edge @edge. - * - * Returns: on success: the %QOSEdgeType - * otherwise: #-1 - */ -QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge); - -/** - * qos_graph_edge_get_dest(): returns the name of the node - * pointed as destination of edge @edge. - * - * Returns: on success: the destination - * otherwise: #NULL - */ -char *qos_graph_edge_get_dest(QOSGraphEdge *edge); - -/** - * qos_graph_has_edge(): returns #TRUE if there - * exists an edge from @start to @dest. - */ -bool qos_graph_has_edge(const char *start, const char *dest); - -/** - * qos_graph_edge_get_arg(): returns the args assigned - * to that @edge. - * - * Returns: on success: the arg - * otherwise: #NULL - */ -void *qos_graph_edge_get_arg(QOSGraphEdge *edge); - -/** - * qos_graph_edge_get_after_cmd_line(): returns the edge - * command line that will be added after all the node arguments - * and all the before_cmd_line arguments. - * - * Returns: on success: the char* arg - * otherwise: #NULL - */ -char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge); - -/** - * qos_graph_edge_get_before_cmd_line(): returns the edge - * command line that will be added before the node command - * line argument. - * - * Returns: on success: the char* arg - * otherwise: #NULL - */ -char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge); - -/** - * qos_graph_edge_get_extra_device_opts(): returns the arg - * command line that will be added to the node command - * line argument. - * - * Returns: on success: the char* arg - * otherwise: #NULL - */ -char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge); - -/** - * qos_graph_edge_get_name(): returns the name - * assigned to the destination node (different only) - * if there are multiple devices with the same node name - * e.g. a node has two "generic-sdhci", "emmc" and "sdcard" - * there will be two edges with edge_name ="emmc" and "sdcard" - * - * Returns always the char* edge_name - */ -char *qos_graph_edge_get_name(QOSGraphEdge *edge); - -/** - * qos_graph_get_machine(): returns the machine assigned - * to that @node name. - * - * It performs a search only trough the list of machines - * (i.e. the QOS_ROOT child). - * - * Returns: on success: the %QOSGraphNode - * otherwise: #NULL - */ -QOSGraphNode *qos_graph_get_machine(const char *node); - -/** - * qos_graph_has_machine(): returns #TRUE if the node - * has map has a node mapped to that @node. - */ -bool qos_graph_has_machine(const char *node); - - -/** - * qos_print_graph(): walks the graph and prints - * all machine-to-test paths. - */ -void qos_print_graph(void); - -/** - * qos_graph_foreach_test_path(): executes the Depth First search - * algorithm and applies @fn to all discovered paths. - * - * See qos_traverse_graph() in qgraph.c for more info on - * how it works. - */ -void qos_graph_foreach_test_path(QOSTestCallback fn); - -/** - * qos_get_machine_type(): return QEMU machine type for a machine node. - * This function requires every machine @name to be in the form - * <arch>/<machine_name>, like "arm/raspi2" or "x86_64/pc". - * - * The function will validate the format and return a pointer to - * @machine to <machine_name>. For example, when passed "x86_64/pc" - * it will return "pc". - * - * Note that this function *does not* allocate any new string. - */ -char *qos_get_machine_type(char *name); - -/** - * qos_delete_cmd_line(): delete the - * command line present in node mapped with key @name. - * - * This function is called when the QMP query returns a node with - * { "abstract" : true } attribute. - */ -void qos_delete_cmd_line(const char *name); - -/** - * qos_graph_node_set_availability(): sets the node identified - * by @node with availability @av. - */ -void qos_graph_node_set_availability(const char *node, bool av); - -#endif diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c deleted file mode 100644 index d81ff4274d..0000000000 --- a/tests/libqos/rtas.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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/rtas.h" - -static void qrtas_copy_args(QTestState *qts, uint64_t target_args, - uint32_t nargs, uint32_t *args) -{ - int i; - - for (i = 0; i < nargs; i++) { - qtest_writel(qts, target_args + i * sizeof(uint32_t), args[i]); - } -} - -static void qrtas_copy_ret(QTestState *qts, uint64_t target_ret, - uint32_t nret, uint32_t *ret) -{ - int i; - - for (i = 0; i < nret; i++) { - ret[i] = qtest_readl(qts, target_ret + i * sizeof(uint32_t)); - } -} - -static uint64_t qrtas_call(QTestState *qts, QGuestAllocator *alloc, - const char *name, - uint32_t nargs, uint32_t *args, - uint32_t nret, uint32_t *ret) -{ - uint64_t res; - uint64_t target_args, target_ret; - - target_args = guest_alloc(alloc, nargs * sizeof(uint32_t)); - target_ret = guest_alloc(alloc, nret * sizeof(uint32_t)); - - qrtas_copy_args(qts, target_args, nargs, args); - res = qtest_rtas_call(qts, name, nargs, target_args, nret, target_ret); - qrtas_copy_ret(qts, target_ret, nret, ret); - - guest_free(alloc, target_ret); - guest_free(alloc, target_args); - - return res; -} - -int qrtas_get_time_of_day(QTestState *qts, QGuestAllocator *alloc, - struct tm *tm, uint32_t *ns) -{ - int res; - uint32_t ret[8]; - - res = qrtas_call(qts, alloc, "get-time-of-day", 0, NULL, 8, ret); - if (res != 0) { - return res; - } - - res = ret[0]; - memset(tm, 0, sizeof(*tm)); - tm->tm_year = ret[1] - 1900; - tm->tm_mon = ret[2] - 1; - tm->tm_mday = ret[3]; - tm->tm_hour = ret[4]; - tm->tm_min = ret[5]; - tm->tm_sec = ret[6]; - *ns = ret[7]; - - return res; -} - -uint32_t qrtas_ibm_read_pci_config(QTestState *qts, QGuestAllocator *alloc, - uint64_t buid, - uint32_t addr, uint32_t size) -{ - int res; - uint32_t args[4], ret[2]; - - args[0] = addr; - args[1] = buid >> 32; - args[2] = buid & 0xffffffff; - args[3] = size; - res = qrtas_call(qts, alloc, "ibm,read-pci-config", 4, args, 2, ret); - if (res != 0) { - return -1; - } - - if (ret[0] != 0) { - return -1; - } - - return ret[1]; -} - -int qrtas_ibm_write_pci_config(QTestState *qts, QGuestAllocator *alloc, - uint64_t buid, - uint32_t addr, uint32_t size, uint32_t val) -{ - int res; - uint32_t args[5], ret[1]; - - args[0] = addr; - args[1] = buid >> 32; - args[2] = buid & 0xffffffff; - args[3] = size; - args[4] = val; - res = qrtas_call(qts, alloc, "ibm,write-pci-config", 5, args, 1, ret); - if (res != 0) { - return -1; - } - - if (ret[0] != 0) { - return -1; - } - - return 0; -} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h deleted file mode 100644 index 459e23aaf4..0000000000 --- a/tests/libqos/rtas.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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_RTAS_H -#define LIBQOS_RTAS_H -#include "libqos/malloc.h" - -int qrtas_get_time_of_day(QTestState *qts, QGuestAllocator *alloc, - struct tm *tm, uint32_t *ns); -uint32_t qrtas_ibm_read_pci_config(QTestState *qts, QGuestAllocator *alloc, - uint64_t buid, uint32_t addr, uint32_t size); -int qrtas_ibm_write_pci_config(QTestState *qts, QGuestAllocator *alloc, - uint64_t buid, uint32_t addr, uint32_t size, - uint32_t val); -#endif /* LIBQOS_RTAS_H */ diff --git a/tests/libqos/sdhci.c b/tests/libqos/sdhci.c deleted file mode 100644 index 309794bc52..0000000000 --- a/tests/libqos/sdhci.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "libqos/qgraph.h" -#include "pci.h" -#include "qemu/module.h" -#include "sdhci.h" -#include "hw/pci/pci.h" - -static void set_qsdhci_fields(QSDHCI *s, uint8_t version, uint8_t baseclock, - bool sdma, uint64_t reg) -{ - s->props.version = version; - s->props.baseclock = baseclock; - s->props.capab.sdma = sdma; - s->props.capab.reg = reg; -} - -/* Memory mapped implementation of QSDHCI */ - -static uint16_t sdhci_mm_readw(QSDHCI *s, uint32_t reg) -{ - QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci); - return qtest_readw(smm->qts, smm->addr + reg); -} - -static uint64_t sdhci_mm_readq(QSDHCI *s, uint32_t reg) -{ - QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci); - return qtest_readq(smm->qts, smm->addr + reg); -} - -static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val) -{ - QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci); - qtest_writeq(smm->qts, smm->addr + reg, val); -} - -static void *sdhci_mm_get_driver(void *obj, const char *interface) -{ - QSDHCI_MemoryMapped *smm = obj; - if (!g_strcmp0(interface, "sdhci")) { - return &smm->sdhci; - } - fprintf(stderr, "%s not present in generic-sdhci\n", interface); - g_assert_not_reached(); -} - -void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts, - uint32_t addr, QSDHCIProperties *common) -{ - sdhci->obj.get_driver = sdhci_mm_get_driver; - sdhci->sdhci.readw = sdhci_mm_readw; - sdhci->sdhci.readq = sdhci_mm_readq; - sdhci->sdhci.writeq = sdhci_mm_writeq; - memcpy(&sdhci->sdhci.props, common, sizeof(QSDHCIProperties)); - sdhci->addr = addr; - sdhci->qts = qts; -} - -/* PCI implementation of QSDHCI */ - -static uint16_t sdhci_pci_readw(QSDHCI *s, uint32_t reg) -{ - QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci); - return qpci_io_readw(&spci->dev, spci->mem_bar, reg); -} - -static uint64_t sdhci_pci_readq(QSDHCI *s, uint32_t reg) -{ - QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci); - return qpci_io_readq(&spci->dev, spci->mem_bar, reg); -} - -static void sdhci_pci_writeq(QSDHCI *s, uint32_t reg, uint64_t val) -{ - QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci); - return qpci_io_writeq(&spci->dev, spci->mem_bar, reg, val); -} - -static void *sdhci_pci_get_driver(void *object, const char *interface) -{ - QSDHCI_PCI *spci = object; - if (!g_strcmp0(interface, "sdhci")) { - return &spci->sdhci; - } - - fprintf(stderr, "%s not present in sdhci-pci\n", interface); - g_assert_not_reached(); -} - -static void sdhci_pci_start_hw(QOSGraphObject *obj) -{ - QSDHCI_PCI *spci = (QSDHCI_PCI *)obj; - qpci_device_enable(&spci->dev); -} - -static void sdhci_destructor(QOSGraphObject *obj) -{ - QSDHCI_PCI *spci = (QSDHCI_PCI *)obj; - qpci_iounmap(&spci->dev, spci->mem_bar); -} - -static void *sdhci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr) -{ - QSDHCI_PCI *spci = g_new0(QSDHCI_PCI, 1); - QPCIBus *bus = pci_bus; - uint64_t barsize; - - qpci_device_init(&spci->dev, bus, addr); - spci->mem_bar = qpci_iomap(&spci->dev, 0, &barsize); - spci->sdhci.readw = sdhci_pci_readw; - spci->sdhci.readq = sdhci_pci_readq; - spci->sdhci.writeq = sdhci_pci_writeq; - set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4); - - spci->obj.get_driver = sdhci_pci_get_driver; - spci->obj.start_hw = sdhci_pci_start_hw; - spci->obj.destructor = sdhci_destructor; - return &spci->obj; -} - -static void qsdhci_register_nodes(void) -{ - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - .vendor_id = PCI_VENDOR_ID_REDHAT, - .device_id = PCI_DEVICE_ID_REDHAT_SDHCI, - }; - - QOSGraphEdgeOptions opts = { - .extra_device_opts = "addr=04.0", - }; - - /* generic-sdhci */ - qos_node_create_driver("generic-sdhci", NULL); - qos_node_produces("generic-sdhci", "sdhci"); - - /* sdhci-pci */ - add_qpci_address(&opts, &addr); - qos_node_create_driver("sdhci-pci", sdhci_pci_create); - qos_node_produces("sdhci-pci", "sdhci"); - qos_node_consumes("sdhci-pci", "pci-bus", &opts); - -} - -libqos_init(qsdhci_register_nodes); diff --git a/tests/libqos/sdhci.h b/tests/libqos/sdhci.h deleted file mode 100644 index a88b45ae9d..0000000000 --- a/tests/libqos/sdhci.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef QGRAPH_QSDHCI_H -#define QGRAPH_QSDHCI_H - -#include "libqos/qgraph.h" -#include "pci.h" - -typedef struct QSDHCI QSDHCI; -typedef struct QSDHCI_MemoryMapped QSDHCI_MemoryMapped; -typedef struct QSDHCI_PCI QSDHCI_PCI; -typedef struct QSDHCIProperties QSDHCIProperties; - -/* Properties common to all QSDHCI devices */ -struct QSDHCIProperties { - uint8_t version; - uint8_t baseclock; - struct { - bool sdma; - uint64_t reg; - } capab; -}; - -struct QSDHCI { - uint16_t (*readw)(QSDHCI *s, uint32_t reg); - uint64_t (*readq)(QSDHCI *s, uint32_t reg); - void (*writeq)(QSDHCI *s, uint32_t reg, uint64_t val); - QSDHCIProperties props; -}; - -/* Memory Mapped implementation of QSDHCI */ -struct QSDHCI_MemoryMapped { - QOSGraphObject obj; - QTestState *qts; - QSDHCI sdhci; - uint64_t addr; -}; - -/* PCI implementation of QSDHCI */ -struct QSDHCI_PCI { - QOSGraphObject obj; - QPCIDevice dev; - QSDHCI sdhci; - QPCIBar mem_bar; -}; - -/** - * qos_init_sdhci_mm(): external constructor used by all drivers/machines - * that "contain" a #QSDHCI_MemoryMapped driver - */ -void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts, - uint32_t addr, QSDHCIProperties *common); - -#endif diff --git a/tests/libqos/tpci200.c b/tests/libqos/tpci200.c deleted file mode 100644 index ae590a456e..0000000000 --- a/tests/libqos/tpci200.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * QTest testcase for tpci200 PCI-IndustryPack bridge - * - * Copyright (c) 2014 SUSE LINUX Products GmbH - * - * 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 "qemu/module.h" -#include "libqos/qgraph.h" -#include "libqos/pci.h" - -typedef struct QTpci200 QTpci200; -typedef struct QIpack QIpack; - -struct QIpack { - -}; -struct QTpci200 { - QOSGraphObject obj; - QPCIDevice dev; - QIpack ipack; -}; - -/* tpci200 */ -static void *tpci200_get_driver(void *obj, const char *interface) -{ - QTpci200 *tpci200 = obj; - if (!g_strcmp0(interface, "ipack")) { - return &tpci200->ipack; - } - if (!g_strcmp0(interface, "pci-device")) { - return &tpci200->dev; - } - - fprintf(stderr, "%s not present in tpci200\n", interface); - g_assert_not_reached(); -} - -static void *tpci200_create(void *pci_bus, QGuestAllocator *alloc, void *addr) -{ - QTpci200 *tpci200 = g_new0(QTpci200, 1); - QPCIBus *bus = pci_bus; - - qpci_device_init(&tpci200->dev, bus, addr); - tpci200->obj.get_driver = tpci200_get_driver; - return &tpci200->obj; -} - -static void tpci200_register_nodes(void) -{ - QOSGraphEdgeOptions opts = { - .extra_device_opts = "addr=04.0,id=ipack0", - }; - add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) }); - - qos_node_create_driver("tpci200", tpci200_create); - qos_node_consumes("tpci200", "pci-bus", &opts); - qos_node_produces("tpci200", "ipack"); - qos_node_produces("tpci200", "pci-device"); -} - -libqos_init(tpci200_register_nodes); diff --git a/tests/libqos/usb.c b/tests/libqos/usb.c deleted file mode 100644 index d7a9cb3c72..0000000000 --- a/tests/libqos/usb.c +++ /dev/null @@ -1,57 +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 "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->bar = qpci_iomap(hc->dev, bar, NULL); -} - -void uhci_deinit(struct qhc *hc) -{ - g_free(hc->dev); -} - -void uhci_port_test(struct qhc *hc, int port, uint16_t expect) -{ - uint16_t value = qpci_io_readw(hc->dev, hc->bar, 0x10 + 2 * port); - uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1); - - g_assert((value & mask) == (expect & mask)); -} - -void usb_test_hotplug(QTestState *qts, const char *hcd_id, const char *port, - void (*port_check)(void)) -{ - char *id = g_strdup_printf("usbdev%s", port); - char *bus = g_strdup_printf("%s.0", hcd_id); - - qtest_qmp_device_add(qts, "usb-tablet", id, "{'port': %s, 'bus': %s}", - port, bus); - - if (port_check) { - port_check(); - } - - qtest_qmp_device_del(qts, id); - - g_free(bus); - g_free(id); -} diff --git a/tests/libqos/usb.h b/tests/libqos/usb.h deleted file mode 100644 index eeced39a2f..0000000000 --- a/tests/libqos/usb.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef LIBQOS_USB_H -#define LIBQOS_USB_H - -#include "libqos/pci-pc.h" - -struct qhc { - QPCIDevice *dev; - QPCIBar bar; -}; - -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 uhci_deinit(struct qhc *hc); - -void usb_test_hotplug(QTestState *qts, const char *bus_name, const char *port, - void (*port_check)(void)); -#endif diff --git a/tests/libqos/virtio-9p.c b/tests/libqos/virtio-9p.c deleted file mode 100644 index 77dbfb62ad..0000000000 --- a/tests/libqos/virtio-9p.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "standard-headers/linux/virtio_ids.h" -#include "libqos/virtio-9p.h" -#include "libqos/qgraph.h" - -static QGuestAllocator *alloc; - -static void virtio_9p_cleanup(QVirtio9P *interface) -{ - qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc); -} - -static void virtio_9p_setup(QVirtio9P *interface) -{ - uint64_t features; - - features = qvirtio_get_features(interface->vdev); - features &= ~(QVIRTIO_F_BAD_FEATURE | (1ull << VIRTIO_RING_F_EVENT_IDX)); - qvirtio_set_features(interface->vdev, features); - - interface->vq = qvirtqueue_setup(interface->vdev, alloc, 0); - qvirtio_set_driver_ok(interface->vdev); -} - -/* virtio-9p-device */ -static void virtio_9p_device_destructor(QOSGraphObject *obj) -{ - QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj; - QVirtio9P *v9p = &v_9p->v9p; - - virtio_9p_cleanup(v9p); -} - -static void virtio_9p_device_start_hw(QOSGraphObject *obj) -{ - QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj; - QVirtio9P *v9p = &v_9p->v9p; - - virtio_9p_setup(v9p); -} - -static void *virtio_9p_get_driver(QVirtio9P *v_9p, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-9p")) { - return v_9p; - } - if (!g_strcmp0(interface, "virtio")) { - return v_9p->vdev; - } - - fprintf(stderr, "%s not present in virtio-9p-device\n", interface); - g_assert_not_reached(); -} - -static void *virtio_9p_device_get_driver(void *object, const char *interface) -{ - QVirtio9PDevice *v_9p = object; - return virtio_9p_get_driver(&v_9p->v9p, interface); -} - -static void *virtio_9p_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtio9PDevice *virtio_device = g_new0(QVirtio9PDevice, 1); - QVirtio9P *interface = &virtio_device->v9p; - - interface->vdev = virtio_dev; - alloc = t_alloc; - - virtio_device->obj.destructor = virtio_9p_device_destructor; - virtio_device->obj.get_driver = virtio_9p_device_get_driver; - virtio_device->obj.start_hw = virtio_9p_device_start_hw; - - return &virtio_device->obj; -} - -/* virtio-9p-pci */ -static void virtio_9p_pci_destructor(QOSGraphObject *obj) -{ - QVirtio9PPCI *v9_pci = (QVirtio9PPCI *) obj; - QVirtio9P *interface = &v9_pci->v9p; - QOSGraphObject *pci_vobj = &v9_pci->pci_vdev.obj; - - virtio_9p_cleanup(interface); - qvirtio_pci_destructor(pci_vobj); -} - -static void virtio_9p_pci_start_hw(QOSGraphObject *obj) -{ - QVirtio9PPCI *v9_pci = (QVirtio9PPCI *) obj; - QVirtio9P *interface = &v9_pci->v9p; - QOSGraphObject *pci_vobj = &v9_pci->pci_vdev.obj; - - qvirtio_pci_start_hw(pci_vobj); - virtio_9p_setup(interface); -} - -static void *virtio_9p_pci_get_driver(void *object, const char *interface) -{ - QVirtio9PPCI *v_9p = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_9p->pci_vdev.pdev; - } - return virtio_9p_get_driver(&v_9p->v9p, interface); -} - -static void *virtio_9p_pci_create(void *pci_bus, QGuestAllocator *t_alloc, - void *addr) -{ - QVirtio9PPCI *v9_pci = g_new0(QVirtio9PPCI, 1); - QVirtio9P *interface = &v9_pci->v9p; - QOSGraphObject *obj = &v9_pci->pci_vdev.obj; - - virtio_pci_init(&v9_pci->pci_vdev, pci_bus, addr); - interface->vdev = &v9_pci->pci_vdev.vdev; - alloc = t_alloc; - - g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_9P); - - obj->destructor = virtio_9p_pci_destructor; - obj->start_hw = virtio_9p_pci_start_hw; - obj->get_driver = virtio_9p_pci_get_driver; - - return obj; -} - -static void virtio_9p_register_nodes(void) -{ - const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG; - const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG; - - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - }; - - QOSGraphEdgeOptions opts = { - .before_cmd_line = "-fsdev synth,id=fsdev0", - }; - - /* virtio-9p-device */ - opts.extra_device_opts = str_simple, - qos_node_create_driver("virtio-9p-device", virtio_9p_device_create); - qos_node_consumes("virtio-9p-device", "virtio-bus", &opts); - qos_node_produces("virtio-9p-device", "virtio"); - qos_node_produces("virtio-9p-device", "virtio-9p"); - - /* virtio-9p-pci */ - opts.extra_device_opts = str_addr; - add_qpci_address(&opts, &addr); - qos_node_create_driver("virtio-9p-pci", virtio_9p_pci_create); - qos_node_consumes("virtio-9p-pci", "pci-bus", &opts); - qos_node_produces("virtio-9p-pci", "pci-device"); - qos_node_produces("virtio-9p-pci", "virtio"); - qos_node_produces("virtio-9p-pci", "virtio-9p"); - -} - -libqos_init(virtio_9p_register_nodes); diff --git a/tests/libqos/virtio-9p.h b/tests/libqos/virtio-9p.h deleted file mode 100644 index b54e89b3a1..0000000000 --- a/tests/libqos/virtio-9p.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_9P_H -#define TESTS_LIBQOS_VIRTIO_9P_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtio9P QVirtio9P; -typedef struct QVirtio9PPCI QVirtio9PPCI; -typedef struct QVirtio9PDevice QVirtio9PDevice; - -#define MOUNT_TAG "qtest" - -struct QVirtio9P { - QVirtioDevice *vdev; - QVirtQueue *vq; -}; - -struct QVirtio9PPCI { - QVirtioPCIDevice pci_vdev; - QVirtio9P v9p; -}; - -struct QVirtio9PDevice { - QOSGraphObject obj; - QVirtio9P v9p; -}; - -#endif diff --git a/tests/libqos/virtio-balloon.c b/tests/libqos/virtio-balloon.c deleted file mode 100644 index 42a4c5831e..0000000000 --- a/tests/libqos/virtio-balloon.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-balloon.h" - -/* virtio-balloon-device */ -static void *qvirtio_balloon_get_driver(QVirtioBalloon *v_balloon, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-balloon")) { - return v_balloon; - } - if (!g_strcmp0(interface, "virtio")) { - return v_balloon->vdev; - } - - fprintf(stderr, "%s not present in virtio-balloon-device\n", interface); - g_assert_not_reached(); -} - -static void *qvirtio_balloon_device_get_driver(void *object, - const char *interface) -{ - QVirtioBalloonDevice *v_balloon = object; - return qvirtio_balloon_get_driver(&v_balloon->balloon, interface); -} - -static void *virtio_balloon_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioBalloonDevice *virtio_bdevice = g_new0(QVirtioBalloonDevice, 1); - QVirtioBalloon *interface = &virtio_bdevice->balloon; - - interface->vdev = virtio_dev; - - virtio_bdevice->obj.get_driver = qvirtio_balloon_device_get_driver; - - return &virtio_bdevice->obj; -} - -/* virtio-balloon-pci */ -static void *qvirtio_balloon_pci_get_driver(void *object, - const char *interface) -{ - QVirtioBalloonPCI *v_balloon = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_balloon->pci_vdev.pdev; - } - return qvirtio_balloon_get_driver(&v_balloon->balloon, interface); -} - -static void *virtio_balloon_pci_create(void *pci_bus, QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioBalloonPCI *virtio_bpci = g_new0(QVirtioBalloonPCI, 1); - QVirtioBalloon *interface = &virtio_bpci->balloon; - QOSGraphObject *obj = &virtio_bpci->pci_vdev.obj; - - - virtio_pci_init(&virtio_bpci->pci_vdev, pci_bus, addr); - interface->vdev = &virtio_bpci->pci_vdev.vdev; - - obj->get_driver = qvirtio_balloon_pci_get_driver; - - return obj; -} - -static void virtio_balloon_register_nodes(void) -{ - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - }; - - QOSGraphEdgeOptions opts = { - .extra_device_opts = "addr=04.0", - }; - - /* virtio-balloon-device */ - qos_node_create_driver("virtio-balloon-device", - virtio_balloon_device_create); - qos_node_consumes("virtio-balloon-device", "virtio-bus", NULL); - qos_node_produces("virtio-balloon-device", "virtio"); - qos_node_produces("virtio-balloon-device", "virtio-balloon"); - - /* virtio-balloon-pci */ - add_qpci_address(&opts, &addr); - qos_node_create_driver("virtio-balloon-pci", virtio_balloon_pci_create); - qos_node_consumes("virtio-balloon-pci", "pci-bus", &opts); - qos_node_produces("virtio-balloon-pci", "pci-device"); - qos_node_produces("virtio-balloon-pci", "virtio"); - qos_node_produces("virtio-balloon-pci", "virtio-balloon"); -} - -libqos_init(virtio_balloon_register_nodes); diff --git a/tests/libqos/virtio-balloon.h b/tests/libqos/virtio-balloon.h deleted file mode 100644 index 52661cc87d..0000000000 --- a/tests/libqos/virtio-balloon.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_BALLOON_H -#define TESTS_LIBQOS_VIRTIO_BALLOON_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtioBalloon QVirtioBalloon; -typedef struct QVirtioBalloonPCI QVirtioBalloonPCI; -typedef struct QVirtioBalloonDevice QVirtioBalloonDevice; - -struct QVirtioBalloon { - QVirtioDevice *vdev; -}; - -struct QVirtioBalloonPCI { - QVirtioPCIDevice pci_vdev; - QVirtioBalloon balloon; -}; - -struct QVirtioBalloonDevice { - QOSGraphObject obj; - QVirtioBalloon balloon; -}; - -#endif diff --git a/tests/libqos/virtio-blk.c b/tests/libqos/virtio-blk.c deleted file mode 100644 index 726e93c5c1..0000000000 --- a/tests/libqos/virtio-blk.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "standard-headers/linux/virtio_blk.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-blk.h" - -#define PCI_SLOT 0x04 -#define PCI_FN 0x00 - -/* virtio-blk-device */ -static void *qvirtio_blk_get_driver(QVirtioBlk *v_blk, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-blk")) { - return v_blk; - } - if (!g_strcmp0(interface, "virtio")) { - return v_blk->vdev; - } - - fprintf(stderr, "%s not present in virtio-blk-device\n", interface); - g_assert_not_reached(); -} - -static void *qvirtio_blk_device_get_driver(void *object, - const char *interface) -{ - QVirtioBlkDevice *v_blk = object; - return qvirtio_blk_get_driver(&v_blk->blk, interface); -} - -static void *virtio_blk_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioBlkDevice *virtio_blk = g_new0(QVirtioBlkDevice, 1); - QVirtioBlk *interface = &virtio_blk->blk; - - interface->vdev = virtio_dev; - - virtio_blk->obj.get_driver = qvirtio_blk_device_get_driver; - - return &virtio_blk->obj; -} - -/* virtio-blk-pci */ -static void *qvirtio_blk_pci_get_driver(void *object, const char *interface) -{ - QVirtioBlkPCI *v_blk = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_blk->pci_vdev.pdev; - } - return qvirtio_blk_get_driver(&v_blk->blk, interface); -} - -static void *virtio_blk_pci_create(void *pci_bus, QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioBlkPCI *virtio_blk = g_new0(QVirtioBlkPCI, 1); - QVirtioBlk *interface = &virtio_blk->blk; - QOSGraphObject *obj = &virtio_blk->pci_vdev.obj; - - virtio_pci_init(&virtio_blk->pci_vdev, pci_bus, addr); - interface->vdev = &virtio_blk->pci_vdev.vdev; - - g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_BLOCK); - - obj->get_driver = qvirtio_blk_pci_get_driver; - - return obj; -} - -static void virtio_blk_register_nodes(void) -{ - /* FIXME: every test using these two nodes needs to setup a - * -drive,id=drive0 otherwise QEMU is not going to start. - * Therefore, we do not include "produces" edge for virtio - * and pci-device yet. - */ - - char *arg = g_strdup_printf("id=drv0,drive=drive0,addr=%x.%x", - PCI_SLOT, PCI_FN); - - QPCIAddress addr = { - .devfn = QPCI_DEVFN(PCI_SLOT, PCI_FN), - }; - - QOSGraphEdgeOptions opts = { }; - - /* virtio-blk-device */ - opts.extra_device_opts = "drive=drive0"; - qos_node_create_driver("virtio-blk-device", virtio_blk_device_create); - qos_node_consumes("virtio-blk-device", "virtio-bus", &opts); - qos_node_produces("virtio-blk-device", "virtio-blk"); - - /* virtio-blk-pci */ - opts.extra_device_opts = arg; - add_qpci_address(&opts, &addr); - qos_node_create_driver("virtio-blk-pci", virtio_blk_pci_create); - qos_node_consumes("virtio-blk-pci", "pci-bus", &opts); - qos_node_produces("virtio-blk-pci", "virtio-blk"); - - g_free(arg); -} - -libqos_init(virtio_blk_register_nodes); diff --git a/tests/libqos/virtio-blk.h b/tests/libqos/virtio-blk.h deleted file mode 100644 index c05adc659d..0000000000 --- a/tests/libqos/virtio-blk.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_BLK_H -#define TESTS_LIBQOS_VIRTIO_BLK_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtioBlk QVirtioBlk; -typedef struct QVirtioBlkPCI QVirtioBlkPCI; -typedef struct QVirtioBlkDevice QVirtioBlkDevice; - -/* virtqueue is created in each test */ -struct QVirtioBlk { - QVirtioDevice *vdev; -}; - -struct QVirtioBlkPCI { - QVirtioPCIDevice pci_vdev; - QVirtioBlk blk; -}; - -struct QVirtioBlkDevice { - QOSGraphObject obj; - QVirtioBlk blk; -}; - -#endif diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c deleted file mode 100644 index e0a2bd7bc6..0000000000 --- a/tests/libqos/virtio-mmio.c +++ /dev/null @@ -1,266 +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 "libqtest.h" -#include "qemu/module.h" -#include "libqos/virtio.h" -#include "libqos/virtio-mmio.h" -#include "libqos/malloc.h" -#include "libqos/qgraph.h" -#include "standard-headers/linux/virtio_ring.h" - -static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t off) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return qtest_readb(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); -} - -static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t off) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return qtest_readw(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); -} - -static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t off) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); -} - -static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t off) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return qtest_readq(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); -} - -static uint64_t qvirtio_mmio_get_features(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - uint64_t lo; - uint64_t hi = 0; - - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0); - lo = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES); - - if (dev->version >= 2) { - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 1); - hi = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES); - } - - return (hi << 32) | lo; -} - -static void qvirtio_mmio_set_features(QVirtioDevice *d, uint64_t features) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - dev->features = features; - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0); - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features); - - if (dev->version >= 2) { - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 1); - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, - features >> 32); - } -} - -static uint64_t qvirtio_mmio_get_guest_features(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return dev->features; -} - -static uint8_t qvirtio_mmio_get_status(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return (uint8_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS); -} - -static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status); -} - -static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - uint32_t isr; - - isr = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1; - if (isr != 0) { - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1); - return true; - } - - return false; -} - -static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - uint32_t isr; - - isr = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2; - if (isr != 0) { - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2); - return true; - } - - return false; -} - -static void qvirtio_mmio_wait_config_isr_status(QVirtioDevice *d, - gint64 timeout_us) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - gint64 start_time = g_get_monotonic_time(); - - do { - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - qtest_clock_step(dev->qts, 100); - } while (!qvirtio_mmio_get_config_isr_status(d)); -} - -static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index); - - g_assert_cmphex(qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0); -} - -static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - return (uint16_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX); -} - -static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - uint64_t pfn = vq->desc / dev->page_size; - - qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn); -} - -static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - QVirtQueue *vq; - uint64_t addr; - - vq = g_malloc0(sizeof(*vq)); - vq->vdev = d; - qvirtio_mmio_queue_select(d, index); - qtest_writel(dev->qts, 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 & (1ull << VIRTIO_RING_F_INDIRECT_DESC); - vq->event = dev->features & (1ull << VIRTIO_RING_F_EVENT_IDX); - - qtest_writel(dev->qts, 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(dev->qts, alloc, vq, addr); - qvirtio_mmio_set_queue_address(d, vq); - - return vq; -} - -static void qvirtio_mmio_virtqueue_cleanup(QVirtQueue *vq, - QGuestAllocator *alloc) -{ - guest_free(alloc, vq->desc); - g_free(vq); -} - -static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev); - qtest_writel(dev->qts, 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, - .wait_config_isr_status = qvirtio_mmio_wait_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_cleanup = qvirtio_mmio_virtqueue_cleanup, - .virtqueue_kick = qvirtio_mmio_virtqueue_kick, -}; - -static void *qvirtio_mmio_get_driver(void *obj, const char *interface) -{ - QVirtioMMIODevice *virtio_mmio = obj; - if (!g_strcmp0(interface, "virtio-bus")) { - return &virtio_mmio->vdev; - } - fprintf(stderr, "%s not present in virtio-mmio\n", interface); - g_assert_not_reached(); -} - -static void qvirtio_mmio_start_hw(QOSGraphObject *obj) -{ - QVirtioMMIODevice *dev = (QVirtioMMIODevice *) obj; - qvirtio_start_device(&dev->vdev); -} - -void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, QTestState *qts, - uint64_t addr, uint32_t page_size) -{ - uint32_t magic; - magic = qtest_readl(qts, addr + QVIRTIO_MMIO_MAGIC_VALUE); - g_assert(magic == ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)); - - dev->version = qtest_readl(qts, addr + QVIRTIO_MMIO_VERSION); - g_assert(dev->version == 1 || dev->version == 2); - - dev->qts = qts; - dev->addr = addr; - dev->page_size = page_size; - dev->vdev.device_type = qtest_readl(qts, addr + QVIRTIO_MMIO_DEVICE_ID); - dev->vdev.bus = &qvirtio_mmio; - - qtest_writel(qts, addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size); - - dev->obj.get_driver = qvirtio_mmio_get_driver; - dev->obj.start_hw = qvirtio_mmio_start_hw; -} - -static void virtio_mmio_register_nodes(void) -{ - qos_node_create_driver("virtio-mmio", NULL); - qos_node_produces("virtio-mmio", "virtio-bus"); -} - -libqos_init(virtio_mmio_register_nodes); diff --git a/tests/libqos/virtio-mmio.h b/tests/libqos/virtio-mmio.h deleted file mode 100644 index 0e45778b07..0000000000 --- a/tests/libqos/virtio-mmio.h +++ /dev/null @@ -1,51 +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" -#include "libqos/qgraph.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 { - QOSGraphObject obj; - QVirtioDevice vdev; - QTestState *qts; - uint64_t addr; - uint32_t page_size; - uint32_t features; /* As it cannot be read later, save it */ - uint32_t version; -} QVirtioMMIODevice; - -extern const QVirtioBus qvirtio_mmio; - -void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, QTestState *qts, - uint64_t addr, uint32_t page_size); - -#endif diff --git a/tests/libqos/virtio-net.c b/tests/libqos/virtio-net.c deleted file mode 100644 index 710d440c3d..0000000000 --- a/tests/libqos/virtio-net.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-net.h" -#include "hw/virtio/virtio-net.h" - - -static QGuestAllocator *alloc; - -static void virtio_net_cleanup(QVirtioNet *interface) -{ - int i; - - for (i = 0; i < interface->n_queues; i++) { - qvirtqueue_cleanup(interface->vdev->bus, interface->queues[i], alloc); - } - g_free(interface->queues); -} - -static void virtio_net_setup(QVirtioNet *interface) -{ - QVirtioDevice *vdev = interface->vdev; - uint64_t features; - int i; - - features = qvirtio_get_features(vdev); - features &= ~(QVIRTIO_F_BAD_FEATURE | - (1ull << VIRTIO_RING_F_INDIRECT_DESC) | - (1ull << VIRTIO_RING_F_EVENT_IDX)); - qvirtio_set_features(vdev, features); - - if (features & (1ull << VIRTIO_NET_F_MQ)) { - interface->n_queues = qvirtio_config_readw(vdev, 8) * 2; - } else { - interface->n_queues = 2; - } - interface->n_queues++; /* Account for the ctrl queue */ - - interface->queues = g_new(QVirtQueue *, interface->n_queues); - for (i = 0; i < interface->n_queues; i++) { - interface->queues[i] = qvirtqueue_setup(vdev, alloc, i); - } - qvirtio_set_driver_ok(vdev); -} - -/* virtio-net-device */ -static void qvirtio_net_device_destructor(QOSGraphObject *obj) -{ - QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj; - virtio_net_cleanup(&v_net->net); -} - -static void qvirtio_net_device_start_hw(QOSGraphObject *obj) -{ - QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj; - QVirtioNet *interface = &v_net->net; - - virtio_net_setup(interface); -} - -static void *qvirtio_net_get_driver(QVirtioNet *v_net, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-net")) { - return v_net; - } - if (!g_strcmp0(interface, "virtio")) { - return v_net->vdev; - } - - fprintf(stderr, "%s not present in virtio-net-device\n", interface); - g_assert_not_reached(); -} - -static void *qvirtio_net_device_get_driver(void *object, - const char *interface) -{ - QVirtioNetDevice *v_net = object; - return qvirtio_net_get_driver(&v_net->net, interface); -} - -static void *virtio_net_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioNetDevice *virtio_ndevice = g_new0(QVirtioNetDevice, 1); - QVirtioNet *interface = &virtio_ndevice->net; - - interface->vdev = virtio_dev; - alloc = t_alloc; - - virtio_ndevice->obj.destructor = qvirtio_net_device_destructor; - virtio_ndevice->obj.get_driver = qvirtio_net_device_get_driver; - virtio_ndevice->obj.start_hw = qvirtio_net_device_start_hw; - - return &virtio_ndevice->obj; -} - -/* virtio-net-pci */ -static void qvirtio_net_pci_destructor(QOSGraphObject *obj) -{ - QVirtioNetPCI *v_net = (QVirtioNetPCI *) obj; - QVirtioNet *interface = &v_net->net; - QOSGraphObject *pci_vobj = &v_net->pci_vdev.obj; - - virtio_net_cleanup(interface); - qvirtio_pci_destructor(pci_vobj); -} - -static void qvirtio_net_pci_start_hw(QOSGraphObject *obj) -{ - QVirtioNetPCI *v_net = (QVirtioNetPCI *) obj; - QVirtioNet *interface = &v_net->net; - QOSGraphObject *pci_vobj = &v_net->pci_vdev.obj; - - qvirtio_pci_start_hw(pci_vobj); - virtio_net_setup(interface); -} - -static void *qvirtio_net_pci_get_driver(void *object, - const char *interface) -{ - QVirtioNetPCI *v_net = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_net->pci_vdev.pdev; - } - return qvirtio_net_get_driver(&v_net->net, interface); -} - -static void *virtio_net_pci_create(void *pci_bus, QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioNetPCI *virtio_bpci = g_new0(QVirtioNetPCI, 1); - QVirtioNet *interface = &virtio_bpci->net; - QOSGraphObject *obj = &virtio_bpci->pci_vdev.obj; - - virtio_pci_init(&virtio_bpci->pci_vdev, pci_bus, addr); - interface->vdev = &virtio_bpci->pci_vdev.vdev; - alloc = t_alloc; - - g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_NET); - - obj->destructor = qvirtio_net_pci_destructor; - obj->start_hw = qvirtio_net_pci_start_hw; - obj->get_driver = qvirtio_net_pci_get_driver; - - return obj; -} - -static void virtio_net_register_nodes(void) -{ - /* FIXME: every test using these nodes needs to setup a - * -netdev socket,id=hs0 otherwise QEMU is not going to start. - * Therefore, we do not include "produces" edge for virtio - * and pci-device yet. - */ - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - }; - - QOSGraphEdgeOptions opts = { }; - - /* virtio-net-device */ - opts.extra_device_opts = "netdev=hs0"; - qos_node_create_driver("virtio-net-device", - virtio_net_device_create); - qos_node_consumes("virtio-net-device", "virtio-bus", &opts); - qos_node_produces("virtio-net-device", "virtio-net"); - - /* virtio-net-pci */ - opts.extra_device_opts = "netdev=hs0,addr=04.0"; - add_qpci_address(&opts, &addr); - qos_node_create_driver("virtio-net-pci", virtio_net_pci_create); - qos_node_consumes("virtio-net-pci", "pci-bus", &opts); - qos_node_produces("virtio-net-pci", "virtio-net"); -} - -libqos_init(virtio_net_register_nodes); diff --git a/tests/libqos/virtio-net.h b/tests/libqos/virtio-net.h deleted file mode 100644 index 855c67d00f..0000000000 --- a/tests/libqos/virtio-net.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_NET_H -#define TESTS_LIBQOS_VIRTIO_NET_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtioNet QVirtioNet; -typedef struct QVirtioNetPCI QVirtioNetPCI; -typedef struct QVirtioNetDevice QVirtioNetDevice; - -struct QVirtioNet { - QVirtioDevice *vdev; - int n_queues; /* total number of virtqueues (rx, tx, ctrl) */ - QVirtQueue **queues; -}; - -struct QVirtioNetPCI { - QVirtioPCIDevice pci_vdev; - QVirtioNet net; -}; - -struct QVirtioNetDevice { - QOSGraphObject obj; - QVirtioNet net; -}; - -#endif diff --git a/tests/libqos/virtio-pci-modern.c b/tests/libqos/virtio-pci-modern.c deleted file mode 100644 index 18d118866f..0000000000 --- a/tests/libqos/virtio-pci-modern.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * libqos VIRTIO 1.0 PCI driver - * - * Copyright (c) 2019 Red Hat, Inc - * - * 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 "standard-headers/linux/pci_regs.h" -#include "standard-headers/linux/virtio_pci.h" -#include "standard-headers/linux/virtio_config.h" -#include "virtio-pci-modern.h" - -static uint8_t config_readb(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readb(dev->pdev, dev->bar, dev->device_cfg_offset + addr); -} - -static uint16_t config_readw(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readw(dev->pdev, dev->bar, dev->device_cfg_offset + addr); -} - -static uint32_t config_readl(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readl(dev->pdev, dev->bar, dev->device_cfg_offset + addr); -} - -static uint64_t config_readq(QVirtioDevice *d, uint64_t addr) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readq(dev->pdev, dev->bar, dev->device_cfg_offset + addr); -} - -static uint64_t get_features(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - uint64_t lo, hi; - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - device_feature_select), - 0); - lo = qpci_io_readl(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, device_feature)); - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - device_feature_select), - 1); - hi = qpci_io_readl(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, device_feature)); - - return (hi << 32) | lo; -} - -static void set_features(QVirtioDevice *d, uint64_t features) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - /* Drivers must enable VIRTIO 1.0 or else use the Legacy interface */ - g_assert_cmphex(features & (1ull << VIRTIO_F_VERSION_1), !=, 0); - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - guest_feature_select), - 0); - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - guest_feature), - features); - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - guest_feature_select), - 1); - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - guest_feature), - features >> 32); -} - -static uint64_t get_guest_features(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - uint64_t lo, hi; - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - guest_feature_select), - 0); - lo = qpci_io_readl(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, guest_feature)); - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - guest_feature_select), - 1); - hi = qpci_io_readl(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, guest_feature)); - - return (hi << 32) | lo; -} - -static uint8_t get_status(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - return qpci_io_readb(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - device_status)); -} - -static void set_status(QVirtioDevice *d, uint8_t status) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - return qpci_io_writeb(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - device_status), - status); -} - -static bool get_msix_status(QVirtioPCIDevice *dev, uint32_t msix_entry, - uint32_t msix_addr, uint32_t msix_data) -{ - uint32_t data; - - g_assert_cmpint(msix_entry, !=, -1); - if (qpci_msix_masked(dev->pdev, msix_entry)) { - /* No ISR checking should be done if masked, but read anyway */ - return qpci_msix_pending(dev->pdev, msix_entry); - } - - data = qtest_readl(dev->pdev->bus->qts, msix_addr); - if (data == msix_data) { - qtest_writel(dev->pdev->bus->qts, msix_addr, 0); - return true; - } else { - return false; - } -} - -static bool get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - if (dev->pdev->msix_enabled) { - QVirtQueuePCI *vqpci = container_of(vq, QVirtQueuePCI, vq); - - return get_msix_status(dev, vqpci->msix_entry, vqpci->msix_addr, - vqpci->msix_data); - } - - return qpci_io_readb(dev->pdev, dev->bar, dev->isr_cfg_offset) & 1; -} - -static bool get_config_isr_status(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - if (dev->pdev->msix_enabled) { - return get_msix_status(dev, dev->config_msix_entry, - dev->config_msix_addr, dev->config_msix_data); - } - - return qpci_io_readb(dev->pdev, dev->bar, dev->isr_cfg_offset) & 2; -} - -static void wait_config_isr_status(QVirtioDevice *d, gint64 timeout_us) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - gint64 start_time = g_get_monotonic_time(); - - do { - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - qtest_clock_step(dev->pdev->bus->qts, 100); - } while (!get_config_isr_status(d)); -} - -static void queue_select(QVirtioDevice *d, uint16_t index) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - qpci_io_writew(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_select), - index); -} - -static uint16_t get_queue_size(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - return qpci_io_readw(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_size)); -} - -static void set_queue_address(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_desc_lo), - vq->desc); - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_desc_hi), - vq->desc >> 32); - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_avail_lo), - vq->avail); - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_avail_hi), - vq->avail >> 32); - - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_used_lo), - vq->used); - qpci_io_writel(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_used_hi), - vq->used >> 32); -} - -static QVirtQueue *virtqueue_setup(QVirtioDevice *d, QGuestAllocator *alloc, - uint16_t index) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - QVirtQueue *vq; - QVirtQueuePCI *vqpci; - uint16_t notify_off; - - vq = qvirtio_pci_virtqueue_setup_common(d, alloc, index); - vqpci = container_of(vq, QVirtQueuePCI, vq); - - notify_off = qpci_io_readw(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - queue_notify_off)); - - vqpci->notify_offset = dev->notify_cfg_offset + - notify_off * dev->notify_off_multiplier; - - qpci_io_writew(dev->pdev, dev->bar, dev->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_enable), 1); - - return vq; -} - -static void virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - QVirtQueuePCI *vqpci = container_of(vq, QVirtQueuePCI, vq); - - qpci_io_writew(dev->pdev, dev->bar, vqpci->notify_offset, vq->index); -} - -static const QVirtioBus qvirtio_pci_virtio_1 = { - .config_readb = config_readb, - .config_readw = config_readw, - .config_readl = config_readl, - .config_readq = config_readq, - .get_features = get_features, - .set_features = set_features, - .get_guest_features = get_guest_features, - .get_status = get_status, - .set_status = set_status, - .get_queue_isr_status = get_queue_isr_status, - .wait_config_isr_status = wait_config_isr_status, - .queue_select = queue_select, - .get_queue_size = get_queue_size, - .set_queue_address = set_queue_address, - .virtqueue_setup = virtqueue_setup, - .virtqueue_cleanup = qvirtio_pci_virtqueue_cleanup_common, - .virtqueue_kick = virtqueue_kick, -}; - -static void set_config_vector(QVirtioPCIDevice *d, uint16_t entry) -{ - uint16_t vector; - - qpci_io_writew(d->pdev, d->bar, d->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, msix_config), entry); - vector = qpci_io_readw(d->pdev, d->bar, d->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - msix_config)); - g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR); -} - -static void set_queue_vector(QVirtioPCIDevice *d, uint16_t vq_idx, - uint16_t entry) -{ - uint16_t vector; - - queue_select(&d->vdev, vq_idx); - qpci_io_writew(d->pdev, d->bar, d->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, queue_msix_vector), - entry); - vector = qpci_io_readw(d->pdev, d->bar, d->common_cfg_offset + - offsetof(struct virtio_pci_common_cfg, - queue_msix_vector)); - g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR); -} - -static const QVirtioPCIMSIXOps qvirtio_pci_msix_ops_virtio_1 = { - .set_config_vector = set_config_vector, - .set_queue_vector = set_queue_vector, -}; - -static bool probe_device_type(QVirtioPCIDevice *dev) -{ - uint16_t vendor_id; - uint16_t device_id; - - /* "Drivers MUST match devices with the PCI Vendor ID 0x1AF4" */ - vendor_id = qpci_config_readw(dev->pdev, PCI_VENDOR_ID); - if (vendor_id != 0x1af4) { - return false; - } - - /* - * "Any PCI device with ... PCI Device ID 0x1000 through 0x107F inclusive - * is a virtio device" - */ - device_id = qpci_config_readw(dev->pdev, PCI_DEVICE_ID); - if (device_id < 0x1000 || device_id > 0x107f) { - return false; - } - - /* - * "Devices MAY utilize a Transitional PCI Device ID range, 0x1000 to - * 0x103F depending on the device type" - */ - if (device_id < 0x1040) { - /* - * "Transitional devices MUST have the PCI Subsystem Device ID matching - * the Virtio Device ID" - */ - dev->vdev.device_type = qpci_config_readw(dev->pdev, PCI_SUBSYSTEM_ID); - } else { - /* - * "The PCI Device ID is calculated by adding 0x1040 to the Virtio - * Device ID" - */ - dev->vdev.device_type = device_id - 0x1040; - } - - return true; -} - -/* Find the first VIRTIO 1.0 PCI structure for a given type */ -static bool find_structure(QVirtioPCIDevice *dev, uint8_t cfg_type, - uint8_t *bar, uint32_t *offset, uint32_t *length, - uint8_t *cfg_addr) -{ - uint8_t addr = 0; - - while ((addr = qpci_find_capability(dev->pdev, PCI_CAP_ID_VNDR, - addr)) != 0) { - uint8_t type; - - type = qpci_config_readb(dev->pdev, - addr + offsetof(struct virtio_pci_cap, cfg_type)); - if (type != cfg_type) { - continue; - } - - *bar = qpci_config_readb(dev->pdev, - addr + offsetof(struct virtio_pci_cap, bar)); - *offset = qpci_config_readl(dev->pdev, - addr + offsetof(struct virtio_pci_cap, offset)); - *length = qpci_config_readl(dev->pdev, - addr + offsetof(struct virtio_pci_cap, length)); - if (cfg_addr) { - *cfg_addr = addr; - } - - return true; - } - - return false; -} - -static bool probe_device_layout(QVirtioPCIDevice *dev) -{ - uint8_t bar; - uint8_t cfg_addr; - uint32_t length; - - /* - * Due to the qpci_iomap() API we only support devices that put all - * structures in the same PCI BAR. Luckily this is true with QEMU. - */ - - if (!find_structure(dev, VIRTIO_PCI_CAP_COMMON_CFG, &bar, - &dev->common_cfg_offset, &length, NULL)) { - return false; - } - dev->bar_idx = bar; - - if (!find_structure(dev, VIRTIO_PCI_CAP_NOTIFY_CFG, &bar, - &dev->notify_cfg_offset, &length, &cfg_addr)) { - return false; - } - g_assert_cmphex(bar, ==, dev->bar_idx); - - dev->notify_off_multiplier = qpci_config_readl(dev->pdev, - cfg_addr + offsetof(struct virtio_pci_notify_cap, - notify_off_multiplier)); - - if (!find_structure(dev, VIRTIO_PCI_CAP_ISR_CFG, &bar, - &dev->isr_cfg_offset, &length, NULL)) { - return false; - } - g_assert_cmphex(bar, ==, dev->bar_idx); - - if (!find_structure(dev, VIRTIO_PCI_CAP_DEVICE_CFG, &bar, - &dev->device_cfg_offset, &length, NULL)) { - return false; - } - g_assert_cmphex(bar, ==, dev->bar_idx); - - return true; -} - -/* Probe a VIRTIO 1.0 device */ -bool qvirtio_pci_init_virtio_1(QVirtioPCIDevice *dev) -{ - if (!probe_device_type(dev)) { - return false; - } - - if (!probe_device_layout(dev)) { - return false; - } - - dev->vdev.bus = &qvirtio_pci_virtio_1; - dev->msix_ops = &qvirtio_pci_msix_ops_virtio_1; - dev->vdev.big_endian = false; - return true; -} diff --git a/tests/libqos/virtio-pci-modern.h b/tests/libqos/virtio-pci-modern.h deleted file mode 100644 index 6bf2b207c3..0000000000 --- a/tests/libqos/virtio-pci-modern.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * libqos virtio PCI VIRTIO 1.0 definitions - * - * Copyright (c) 2019 Red Hat, Inc - * - * 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_MODERN_H -#define LIBQOS_VIRTIO_PCI_MODERN_H - -#include "virtio-pci.h" - -bool qvirtio_pci_init_virtio_1(QVirtioPCIDevice *dev); - -#endif /* LIBQOS_VIRTIO_PCI_MODERN_H */ diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c deleted file mode 100644 index 62851c29bb..0000000000 --- a/tests/libqos/virtio-pci.c +++ /dev/null @@ -1,435 +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 "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 "libqos/qgraph.h" -#include "standard-headers/linux/virtio_ring.h" -#include "standard-headers/linux/virtio_pci.h" - -#include "hw/pci/pci.h" -#include "hw/pci/pci_regs.h" - -#include "virtio-pci-modern.h" - -/* virtio-pci is a superclass of all virtio-xxx-pci devices; - * the relation between virtio-pci and virtio-xxx-pci is implicit, - * and therefore virtio-pci does not produce virtio and is not - * reached by any edge, not even as a "contains" edge. - * In facts, every device is a QVirtioPCIDevice with - * additional fields, since every one has its own - * number of queues and various attributes. - * Virtio-pci provides default functions to start the - * hw and destroy the object, and nodes that want to - * override them should always remember to call the - * original qvirtio_pci_destructor and qvirtio_pci_start_hw. - */ - -#define CONFIG_BASE(dev) (VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled)) - -static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readb(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); -} - -/* PCI is always read in little-endian order - * but virtio ( < 1.0) is in guest order - * so with a big-endian guest the order has been reversed, - * reverse it again - * virtio-1.0 is always little-endian, like PCI - */ - -static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - uint16_t value; - - value = qpci_io_readw(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); - if (qvirtio_is_big_endian(d)) { - value = bswap16(value); - } - return value; -} - -static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - uint32_t value; - - value = qpci_io_readl(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); - if (qvirtio_is_big_endian(d)) { - value = bswap32(value); - } - return value; -} - -static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - uint64_t val; - - val = qpci_io_readq(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); - if (qvirtio_is_big_endian(d)) { - val = bswap64(val); - } - - return val; -} - -static uint64_t qvirtio_pci_get_features(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_HOST_FEATURES); -} - -static void qvirtio_pci_set_features(QVirtioDevice *d, uint64_t features) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES, features); -} - -static uint64_t qvirtio_pci_get_guest_features(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES); -} - -static uint8_t qvirtio_pci_get_status(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS); -} - -static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS, status); -} - -static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - 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 = qtest_readl(dev->pdev->bus->qts, vqpci->msix_addr); - if (data == vqpci->msix_data) { - qtest_writel(dev->pdev->bus->qts, vqpci->msix_addr, 0); - return true; - } else { - return false; - } - } - } else { - return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 1; - } -} - -static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - 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 = qtest_readl(dev->pdev->bus->qts, dev->config_msix_addr); - if (data == dev->config_msix_data) { - qtest_writel(dev->pdev->bus->qts, dev->config_msix_addr, 0); - return true; - } else { - return false; - } - } - } else { - return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 2; - } -} - -static void qvirtio_pci_wait_config_isr_status(QVirtioDevice *d, - gint64 timeout_us) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - gint64 start_time = g_get_monotonic_time(); - - do { - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - qtest_clock_step(dev->pdev->bus->qts, 100); - } while (!qvirtio_pci_get_config_isr_status(d)); -} - -static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_SEL, index); -} - -static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - return qpci_io_readw(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NUM); -} - -static void qvirtio_pci_set_queue_address(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - uint64_t pfn = vq->desc / VIRTIO_PCI_VRING_ALIGN; - - qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_PFN, pfn); -} - -QVirtQueue *qvirtio_pci_virtqueue_setup_common(QVirtioDevice *d, - QGuestAllocator *alloc, - uint16_t index) -{ - uint64_t feat; - uint64_t addr; - QVirtQueuePCI *vqpci; - QVirtioPCIDevice *qvpcidev = container_of(d, QVirtioPCIDevice, vdev); - - vqpci = g_malloc0(sizeof(*vqpci)); - feat = d->bus->get_guest_features(d); - - d->bus->queue_select(d, index); - vqpci->vq.vdev = d; - vqpci->vq.index = index; - vqpci->vq.size = d->bus->get_queue_size(d); - vqpci->vq.free_head = 0; - vqpci->vq.num_free = vqpci->vq.size; - vqpci->vq.align = VIRTIO_PCI_VRING_ALIGN; - vqpci->vq.indirect = feat & (1ull << VIRTIO_RING_F_INDIRECT_DESC); - vqpci->vq.event = feat & (1ull << VIRTIO_RING_F_EVENT_IDX); - - 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, - VIRTIO_PCI_VRING_ALIGN)); - qvring_init(qvpcidev->pdev->bus->qts, alloc, &vqpci->vq, addr); - d->bus->set_queue_address(d, &vqpci->vq); - - return &vqpci->vq; -} - -void qvirtio_pci_virtqueue_cleanup_common(QVirtQueue *vq, - QGuestAllocator *alloc) -{ - QVirtQueuePCI *vqpci = container_of(vq, QVirtQueuePCI, vq); - - guest_free(alloc, vq->desc); - g_free(vqpci); -} - -static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq) -{ - QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev); - qpci_io_writew(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NOTIFY, vq->index); -} - -static const QVirtioBus qvirtio_pci_legacy = { - .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, - .wait_config_isr_status = qvirtio_pci_wait_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_common, - .virtqueue_cleanup = qvirtio_pci_virtqueue_cleanup_common, - .virtqueue_kick = qvirtio_pci_virtqueue_kick, -}; - -static void qvirtio_pci_set_config_vector(QVirtioPCIDevice *d, uint16_t entry) -{ - uint16_t vector; - - qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR, entry); - vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR); - g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR); -} - -static void qvirtio_pci_set_queue_vector(QVirtioPCIDevice *d, uint16_t vq_idx, - uint16_t entry) -{ - uint16_t vector; - - qvirtio_pci_queue_select(&d->vdev, vq_idx); - qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR, entry); - vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR); - g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR); -} - -static const QVirtioPCIMSIXOps qvirtio_pci_msix_ops_legacy = { - .set_config_vector = qvirtio_pci_set_config_vector, - .set_queue_vector = qvirtio_pci_set_queue_vector, -}; - -void qvirtio_pci_device_enable(QVirtioPCIDevice *d) -{ - qpci_device_enable(d->pdev); - d->bar = qpci_iomap(d->pdev, d->bar_idx, NULL); -} - -void qvirtio_pci_device_disable(QVirtioPCIDevice *d) -{ - qpci_iounmap(d->pdev, d->bar); -} - -void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci, - QGuestAllocator *alloc, uint16_t entry) -{ - uint32_t control; - uint64_t off; - - g_assert(d->pdev->msix_enabled); - off = d->pdev->msix_table_off + (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, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_LOWER_ADDR, vqpci->msix_addr & ~0UL); - qpci_io_writel(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_UPPER_ADDR, - (vqpci->msix_addr >> 32) & ~0UL); - qpci_io_writel(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_DATA, vqpci->msix_data); - - control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_VECTOR_CTRL); - qpci_io_writel(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_VECTOR_CTRL, - control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); - - d->msix_ops->set_queue_vector(d, vqpci->vq.index, entry); -} - -void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d, - QGuestAllocator *alloc, uint16_t entry) -{ - uint32_t control; - uint64_t off; - - g_assert(d->pdev->msix_enabled); - off = d->pdev->msix_table_off + (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, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_LOWER_ADDR, d->config_msix_addr & ~0UL); - qpci_io_writel(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_UPPER_ADDR, - (d->config_msix_addr >> 32) & ~0UL); - qpci_io_writel(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_DATA, d->config_msix_data); - - control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_VECTOR_CTRL); - qpci_io_writel(d->pdev, d->pdev->msix_table_bar, - off + PCI_MSIX_ENTRY_VECTOR_CTRL, - control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); - - d->msix_ops->set_config_vector(d, entry); -} - -void qvirtio_pci_destructor(QOSGraphObject *obj) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj; - qvirtio_pci_device_disable(dev); - g_free(dev->pdev); -} - -void qvirtio_pci_start_hw(QOSGraphObject *obj) -{ - QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj; - qvirtio_pci_device_enable(dev); - qvirtio_start_device(&dev->vdev); -} - -static void qvirtio_pci_init_legacy(QVirtioPCIDevice *dev) -{ - dev->vdev.device_type = qpci_config_readw(dev->pdev, PCI_SUBSYSTEM_ID); - dev->bar_idx = 0; - dev->vdev.bus = &qvirtio_pci_legacy; - dev->msix_ops = &qvirtio_pci_msix_ops_legacy; - dev->vdev.big_endian = qtest_big_endian(dev->pdev->bus->qts); -} - -static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev) -{ - dev->pdev = pci_dev; - dev->config_msix_entry = -1; - - if (!qvirtio_pci_init_virtio_1(dev)) { - qvirtio_pci_init_legacy(dev); - } - - /* each virtio-xxx-pci device should override at least this function */ - dev->obj.get_driver = NULL; - dev->obj.start_hw = qvirtio_pci_start_hw; - dev->obj.destructor = qvirtio_pci_destructor; -} - -void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr) -{ - QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn); - g_assert_nonnull(pci_dev); - qvirtio_pci_init_from_pcidev(dev, pci_dev); -} - -QVirtioPCIDevice *virtio_pci_new(QPCIBus *bus, QPCIAddress * addr) -{ - QVirtioPCIDevice *dev; - QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn); - if (!pci_dev) { - return NULL; - } - - dev = g_new0(QVirtioPCIDevice, 1); - qvirtio_pci_init_from_pcidev(dev, pci_dev); - dev->obj.free = g_free; - return dev; -} diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h deleted file mode 100644 index 294d5567ee..0000000000 --- a/tests/libqos/virtio-pci.h +++ /dev/null @@ -1,86 +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" -#include "libqos/qgraph.h" - -typedef struct QVirtioPCIMSIXOps QVirtioPCIMSIXOps; - -typedef struct QVirtioPCIDevice { - QOSGraphObject obj; - QVirtioDevice vdev; - QPCIDevice *pdev; - QPCIBar bar; - const QVirtioPCIMSIXOps *msix_ops; - uint16_t config_msix_entry; - uint64_t config_msix_addr; - uint32_t config_msix_data; - - int bar_idx; - - /* VIRTIO 1.0 */ - uint32_t common_cfg_offset; - uint32_t notify_cfg_offset; - uint32_t notify_off_multiplier; - uint32_t isr_cfg_offset; - uint32_t device_cfg_offset; -} QVirtioPCIDevice; - -struct QVirtioPCIMSIXOps { - /* Set the Configuration Vector for MSI-X */ - void (*set_config_vector)(QVirtioPCIDevice *d, uint16_t entry); - - /* Set the Queue Vector for MSI-X */ - void (*set_queue_vector)(QVirtioPCIDevice *d, uint16_t vq_idx, - uint16_t entry); -}; - -typedef struct QVirtQueuePCI { - QVirtQueue vq; - uint16_t msix_entry; - uint64_t msix_addr; - uint32_t msix_data; - - /* VIRTIO 1.0 */ - uint64_t notify_offset; -} QVirtQueuePCI; - -void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr); -QVirtioPCIDevice *virtio_pci_new(QPCIBus *bus, QPCIAddress * addr); - -/* virtio-pci object functions available for subclasses that - * override the original start_hw and destroy - * function. All virtio-xxx-pci subclass that override must - * take care of calling these two functions in the respective - * places - */ -void qvirtio_pci_destructor(QOSGraphObject *obj); -void qvirtio_pci_start_hw(QOSGraphObject *obj); - - -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); - -/* Used by Legacy and Modern virtio-pci code */ -QVirtQueue *qvirtio_pci_virtqueue_setup_common(QVirtioDevice *d, - QGuestAllocator *alloc, - uint16_t index); -void qvirtio_pci_virtqueue_cleanup_common(QVirtQueue *vq, - QGuestAllocator *alloc); - -#endif diff --git a/tests/libqos/virtio-rng.c b/tests/libqos/virtio-rng.c deleted file mode 100644 index b86349e2fd..0000000000 --- a/tests/libqos/virtio-rng.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-rng.h" - -/* virtio-rng-device */ -static void *qvirtio_rng_get_driver(QVirtioRng *v_rng, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-rng")) { - return v_rng; - } - if (!g_strcmp0(interface, "virtio")) { - return v_rng->vdev; - } - - fprintf(stderr, "%s not present in virtio-rng-device\n", interface); - g_assert_not_reached(); -} - -static void *qvirtio_rng_device_get_driver(void *object, - const char *interface) -{ - QVirtioRngDevice *v_rng = object; - return qvirtio_rng_get_driver(&v_rng->rng, interface); -} - -static void *virtio_rng_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioRngDevice *virtio_rdevice = g_new0(QVirtioRngDevice, 1); - QVirtioRng *interface = &virtio_rdevice->rng; - - interface->vdev = virtio_dev; - - virtio_rdevice->obj.get_driver = qvirtio_rng_device_get_driver; - - return &virtio_rdevice->obj; -} - -/* virtio-rng-pci */ -static void *qvirtio_rng_pci_get_driver(void *object, const char *interface) -{ - QVirtioRngPCI *v_rng = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_rng->pci_vdev.pdev; - } - return qvirtio_rng_get_driver(&v_rng->rng, interface); -} - -static void *virtio_rng_pci_create(void *pci_bus, QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioRngPCI *virtio_rpci = g_new0(QVirtioRngPCI, 1); - QVirtioRng *interface = &virtio_rpci->rng; - QOSGraphObject *obj = &virtio_rpci->pci_vdev.obj; - - virtio_pci_init(&virtio_rpci->pci_vdev, pci_bus, addr); - interface->vdev = &virtio_rpci->pci_vdev.vdev; - - obj->get_driver = qvirtio_rng_pci_get_driver; - - return obj; -} - -static void virtio_rng_register_nodes(void) -{ - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - }; - - QOSGraphEdgeOptions opts = { - .extra_device_opts = "addr=04.0", - }; - - /* virtio-rng-device */ - qos_node_create_driver("virtio-rng-device", virtio_rng_device_create); - qos_node_consumes("virtio-rng-device", "virtio-bus", NULL); - qos_node_produces("virtio-rng-device", "virtio"); - qos_node_produces("virtio-rng-device", "virtio-rng"); - - /* virtio-rng-pci */ - add_qpci_address(&opts, &addr); - qos_node_create_driver("virtio-rng-pci", virtio_rng_pci_create); - qos_node_consumes("virtio-rng-pci", "pci-bus", &opts); - qos_node_produces("virtio-rng-pci", "pci-device"); - qos_node_produces("virtio-rng-pci", "virtio"); - qos_node_produces("virtio-rng-pci", "virtio-rng"); -} - -libqos_init(virtio_rng_register_nodes); diff --git a/tests/libqos/virtio-rng.h b/tests/libqos/virtio-rng.h deleted file mode 100644 index 9e192f11f7..0000000000 --- a/tests/libqos/virtio-rng.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_RNG_H -#define TESTS_LIBQOS_VIRTIO_RNG_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtioRng QVirtioRng; -typedef struct QVirtioRngPCI QVirtioRngPCI; -typedef struct QVirtioRngDevice QVirtioRngDevice; - -struct QVirtioRng { - QVirtioDevice *vdev; -}; - -struct QVirtioRngPCI { - QVirtioPCIDevice pci_vdev; - QVirtioRng rng; -}; - -struct QVirtioRngDevice { - QOSGraphObject obj; - QVirtioRng rng; -}; - -#endif diff --git a/tests/libqos/virtio-scsi.c b/tests/libqos/virtio-scsi.c deleted file mode 100644 index de739bec5f..0000000000 --- a/tests/libqos/virtio-scsi.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "standard-headers/linux/virtio_ids.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-scsi.h" - -/* virtio-scsi-device */ -static void *qvirtio_scsi_get_driver(QVirtioSCSI *v_scsi, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-scsi")) { - return v_scsi; - } - if (!g_strcmp0(interface, "virtio")) { - return v_scsi->vdev; - } - - fprintf(stderr, "%s not present in virtio-scsi-device\n", interface); - g_assert_not_reached(); -} - -static void *qvirtio_scsi_device_get_driver(void *object, - const char *interface) -{ - QVirtioSCSIDevice *v_scsi = object; - return qvirtio_scsi_get_driver(&v_scsi->scsi, interface); -} - -static void *virtio_scsi_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioSCSIDevice *virtio_bdevice = g_new0(QVirtioSCSIDevice, 1); - QVirtioSCSI *interface = &virtio_bdevice->scsi; - - interface->vdev = virtio_dev; - - virtio_bdevice->obj.get_driver = qvirtio_scsi_device_get_driver; - - return &virtio_bdevice->obj; -} - -/* virtio-scsi-pci */ -static void *qvirtio_scsi_pci_get_driver(void *object, - const char *interface) -{ - QVirtioSCSIPCI *v_scsi = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_scsi->pci_vdev.pdev; - } - return qvirtio_scsi_get_driver(&v_scsi->scsi, interface); -} - -static void *virtio_scsi_pci_create(void *pci_bus, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioSCSIPCI *virtio_spci = g_new0(QVirtioSCSIPCI, 1); - QVirtioSCSI *interface = &virtio_spci->scsi; - QOSGraphObject *obj = &virtio_spci->pci_vdev.obj; - - virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr); - interface->vdev = &virtio_spci->pci_vdev.vdev; - - g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_SCSI); - - obj->get_driver = qvirtio_scsi_pci_get_driver; - - return obj; -} - -static void virtio_scsi_register_nodes(void) -{ - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - }; - - QOSGraphEdgeOptions opts = { - .before_cmd_line = "-drive id=drv0,if=none,file=null-co://," - "file.read-zeroes=on,format=raw", - .after_cmd_line = "-device scsi-hd,bus=vs0.0,drive=drv0", - }; - - /* virtio-scsi-device */ - opts.extra_device_opts = "id=vs0"; - qos_node_create_driver("virtio-scsi-device", - virtio_scsi_device_create); - qos_node_consumes("virtio-scsi-device", "virtio-bus", &opts); - qos_node_produces("virtio-scsi-device", "virtio-scsi"); - - /* virtio-scsi-pci */ - opts.extra_device_opts = "id=vs0,addr=04.0"; - add_qpci_address(&opts, &addr); - qos_node_create_driver("virtio-scsi-pci", virtio_scsi_pci_create); - qos_node_consumes("virtio-scsi-pci", "pci-bus", &opts); - qos_node_produces("virtio-scsi-pci", "pci-device"); - qos_node_produces("virtio-scsi-pci", "virtio-scsi"); -} - -libqos_init(virtio_scsi_register_nodes); diff --git a/tests/libqos/virtio-scsi.h b/tests/libqos/virtio-scsi.h deleted file mode 100644 index 4ca19a6a7a..0000000000 --- a/tests/libqos/virtio-scsi.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_SCSI_H -#define TESTS_LIBQOS_VIRTIO_SCSI_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtioSCSI QVirtioSCSI; -typedef struct QVirtioSCSIPCI QVirtioSCSIPCI; -typedef struct QVirtioSCSIDevice QVirtioSCSIDevice; - -struct QVirtioSCSI { - QVirtioDevice *vdev; -}; - -struct QVirtioSCSIPCI { - QVirtioPCIDevice pci_vdev; - QVirtioSCSI scsi; -}; - -struct QVirtioSCSIDevice { - QOSGraphObject obj; - QVirtioSCSI scsi; -}; - -#endif diff --git a/tests/libqos/virtio-serial.c b/tests/libqos/virtio-serial.c deleted file mode 100644 index 3e5b8b82c7..0000000000 --- a/tests/libqos/virtio-serial.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "qemu/module.h" -#include "libqos/qgraph.h" -#include "libqos/virtio-serial.h" - -static void *qvirtio_serial_get_driver(QVirtioSerial *v_serial, - const char *interface) -{ - if (!g_strcmp0(interface, "virtio-serial")) { - return v_serial; - } - if (!g_strcmp0(interface, "virtio")) { - return v_serial->vdev; - } - - fprintf(stderr, "%s not present in virtio-serial-device\n", interface); - g_assert_not_reached(); -} - -static void *qvirtio_serial_device_get_driver(void *object, - const char *interface) -{ - QVirtioSerialDevice *v_serial = object; - return qvirtio_serial_get_driver(&v_serial->serial, interface); -} - -static void *virtio_serial_device_create(void *virtio_dev, - QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioSerialDevice *virtio_device = g_new0(QVirtioSerialDevice, 1); - QVirtioSerial *interface = &virtio_device->serial; - - interface->vdev = virtio_dev; - - virtio_device->obj.get_driver = qvirtio_serial_device_get_driver; - - return &virtio_device->obj; -} - -/* virtio-serial-pci */ -static void *qvirtio_serial_pci_get_driver(void *object, const char *interface) -{ - QVirtioSerialPCI *v_serial = object; - if (!g_strcmp0(interface, "pci-device")) { - return v_serial->pci_vdev.pdev; - } - return qvirtio_serial_get_driver(&v_serial->serial, interface); -} - -static void *virtio_serial_pci_create(void *pci_bus, QGuestAllocator *t_alloc, - void *addr) -{ - QVirtioSerialPCI *virtio_spci = g_new0(QVirtioSerialPCI, 1); - QVirtioSerial *interface = &virtio_spci->serial; - QOSGraphObject *obj = &virtio_spci->pci_vdev.obj; - - virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr); - interface->vdev = &virtio_spci->pci_vdev.vdev; - - obj->get_driver = qvirtio_serial_pci_get_driver; - - return obj; -} - -static void virtio_serial_register_nodes(void) -{ - QPCIAddress addr = { - .devfn = QPCI_DEVFN(4, 0), - }; - - QOSGraphEdgeOptions edge_opts = { }; - - /* virtio-serial-device */ - edge_opts.extra_device_opts = "id=vser0"; - qos_node_create_driver("virtio-serial-device", - virtio_serial_device_create); - qos_node_consumes("virtio-serial-device", "virtio-bus", &edge_opts); - qos_node_produces("virtio-serial-device", "virtio"); - qos_node_produces("virtio-serial-device", "virtio-serial"); - - /* virtio-serial-pci */ - edge_opts.extra_device_opts = "id=vser0,addr=04.0"; - add_qpci_address(&edge_opts, &addr); - qos_node_create_driver("virtio-serial-pci", virtio_serial_pci_create); - qos_node_consumes("virtio-serial-pci", "pci-bus", &edge_opts); - qos_node_produces("virtio-serial-pci", "pci-device"); - qos_node_produces("virtio-serial-pci", "virtio"); - qos_node_produces("virtio-serial-pci", "virtio-serial"); -} - -libqos_init(virtio_serial_register_nodes); diff --git a/tests/libqos/virtio-serial.h b/tests/libqos/virtio-serial.h deleted file mode 100644 index 080fa8428d..0000000000 --- a/tests/libqos/virtio-serial.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#ifndef TESTS_LIBQOS_VIRTIO_SERIAL_H -#define TESTS_LIBQOS_VIRTIO_SERIAL_H - -#include "libqos/qgraph.h" -#include "libqos/virtio.h" -#include "libqos/virtio-pci.h" - -typedef struct QVirtioSerial QVirtioSerial; -typedef struct QVirtioSerialPCI QVirtioSerialPCI; -typedef struct QVirtioSerialDevice QVirtioSerialDevice; - -struct QVirtioSerial { - QVirtioDevice *vdev; -}; - -struct QVirtioSerialPCI { - QVirtioPCIDevice pci_vdev; - QVirtioSerial serial; -}; - -struct QVirtioSerialDevice { - QOSGraphObject obj; - QVirtioSerial serial; -}; - -#endif diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c deleted file mode 100644 index 9aa360620c..0000000000 --- a/tests/libqos/virtio.c +++ /dev/null @@ -1,450 +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 "qemu/bswap.h" -#include "libqtest.h" -#include "libqos/virtio.h" -#include "standard-headers/linux/virtio_config.h" -#include "standard-headers/linux/virtio_ring.h" - -/* - * qtest_readX/writeX() functions transfer host endian from/to guest endian. - * This works great for Legacy VIRTIO devices where we need guest endian - * accesses. For VIRTIO 1.0 the vring is little-endian so the automatic guest - * endianness conversion is not wanted. - * - * The following qvirtio_readX/writeX() functions handle Legacy and VIRTIO 1.0 - * accesses seamlessly. - */ -static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr) -{ - uint16_t val = qtest_readw(qts, addr); - - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) { - val = bswap16(val); - } - return val; -} - -static uint32_t qvirtio_readl(QVirtioDevice *d, QTestState *qts, uint64_t addr) -{ - uint32_t val = qtest_readl(qts, addr); - - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) { - val = bswap32(val); - } - return val; -} - -static void qvirtio_writew(QVirtioDevice *d, QTestState *qts, - uint64_t addr, uint16_t val) -{ - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) { - val = bswap16(val); - } - qtest_writew(qts, addr, val); -} - -static void qvirtio_writel(QVirtioDevice *d, QTestState *qts, - uint64_t addr, uint32_t val) -{ - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) { - val = bswap32(val); - } - qtest_writel(qts, addr, val); -} - -static void qvirtio_writeq(QVirtioDevice *d, QTestState *qts, - uint64_t addr, uint64_t val) -{ - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) { - val = bswap64(val); - } - qtest_writeq(qts, addr, val); -} - -uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr) -{ - g_assert_true(d->features_negotiated); - return d->bus->config_readb(d, addr); -} - -uint16_t qvirtio_config_readw(QVirtioDevice *d, uint64_t addr) -{ - g_assert_true(d->features_negotiated); - return d->bus->config_readw(d, addr); -} - -uint32_t qvirtio_config_readl(QVirtioDevice *d, uint64_t addr) -{ - g_assert_true(d->features_negotiated); - return d->bus->config_readl(d, addr); -} - -uint64_t qvirtio_config_readq(QVirtioDevice *d, uint64_t addr) -{ - g_assert_true(d->features_negotiated); - return d->bus->config_readq(d, addr); -} - -uint64_t qvirtio_get_features(QVirtioDevice *d) -{ - return d->bus->get_features(d); -} - -void qvirtio_set_features(QVirtioDevice *d, uint64_t features) -{ - d->features = features; - d->bus->set_features(d, features); - - /* - * This could be a separate function for drivers that want to access - * configuration space before setting FEATURES_OK, but no existing users - * need that and it's less code for callers if this is done implicitly. - */ - if (features & (1ull << VIRTIO_F_VERSION_1)) { - uint8_t status = d->bus->get_status(d) | - VIRTIO_CONFIG_S_FEATURES_OK; - - d->bus->set_status(d, status); - g_assert_cmphex(d->bus->get_status(d), ==, status); - } - - d->features_negotiated = true; -} - -QVirtQueue *qvirtqueue_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index) -{ - g_assert_true(d->features_negotiated); - return d->bus->virtqueue_setup(d, alloc, index); -} - -void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq, - QGuestAllocator *alloc) -{ - return bus->virtqueue_cleanup(vq, alloc); -} - -void qvirtio_reset(QVirtioDevice *d) -{ - d->bus->set_status(d, 0); - g_assert_cmphex(d->bus->get_status(d), ==, 0); - d->features_negotiated = false; -} - -void qvirtio_set_acknowledge(QVirtioDevice *d) -{ - d->bus->set_status(d, d->bus->get_status(d) | VIRTIO_CONFIG_S_ACKNOWLEDGE); - g_assert_cmphex(d->bus->get_status(d), ==, VIRTIO_CONFIG_S_ACKNOWLEDGE); -} - -void qvirtio_set_driver(QVirtioDevice *d) -{ - d->bus->set_status(d, d->bus->get_status(d) | VIRTIO_CONFIG_S_DRIVER); - g_assert_cmphex(d->bus->get_status(d), ==, - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_ACKNOWLEDGE); -} - -void qvirtio_set_driver_ok(QVirtioDevice *d) -{ - d->bus->set_status(d, d->bus->get_status(d) | VIRTIO_CONFIG_S_DRIVER_OK); - g_assert_cmphex(d->bus->get_status(d), ==, VIRTIO_CONFIG_S_DRIVER_OK | - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_ACKNOWLEDGE | - (d->features & (1ull << VIRTIO_F_VERSION_1) ? - VIRTIO_CONFIG_S_FEATURES_OK : 0)); -} - -void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d, - QVirtQueue *vq, gint64 timeout_us) -{ - gint64 start_time = g_get_monotonic_time(); - - for (;;) { - qtest_clock_step(qts, 100); - if (d->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(QTestState *qts, QVirtioDevice *d, - QVirtQueue *vq, - uint64_t addr, - gint64 timeout_us) -{ - gint64 start_time = g_get_monotonic_time(); - uint8_t val; - - while ((val = qtest_readb(qts, addr)) == 0xff) { - qtest_clock_step(qts, 100); - g_assert(!d->bus->get_queue_isr_status(d, vq)); - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - } - return val; -} - -/* - * qvirtio_wait_used_elem: - * @desc_idx: The next expected vq->desc[] index in the used ring - * @len: A pointer that is filled with the length written into the buffer, may - * be NULL - * @timeout_us: How many microseconds to wait before failing - * - * This function waits for the next completed request on the used ring. - */ -void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d, - QVirtQueue *vq, - uint32_t desc_idx, - uint32_t *len, - gint64 timeout_us) -{ - gint64 start_time = g_get_monotonic_time(); - - for (;;) { - uint32_t got_desc_idx; - - qtest_clock_step(qts, 100); - - if (d->bus->get_queue_isr_status(d, vq) && - qvirtqueue_get_buf(qts, vq, &got_desc_idx, len)) { - g_assert_cmpint(got_desc_idx, ==, desc_idx); - return; - } - - g_assert(g_get_monotonic_time() - start_time <= timeout_us); - } -} - -void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us) -{ - d->bus->wait_config_isr_status(d, timeout_us); -} - -void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq, - uint64_t addr) -{ - int i; - - vq->desc = addr; - vq->avail = vq->desc + vq->size * sizeof(struct vring_desc); - 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 */ - qvirtio_writeq(vq->vdev, qts, vq->desc + (16 * i), 0); - /* vq->desc[i].next */ - qvirtio_writew(vq->vdev, qts, vq->desc + (16 * i) + 14, i + 1); - } - - /* vq->avail->flags */ - qvirtio_writew(vq->vdev, qts, vq->avail, 0); - /* vq->avail->idx */ - qvirtio_writew(vq->vdev, qts, vq->avail + 2, 0); - /* vq->avail->used_event */ - qvirtio_writew(vq->vdev, qts, vq->avail + 4 + (2 * vq->size), 0); - - /* vq->used->flags */ - qvirtio_writew(vq->vdev, qts, vq->used, 0); - /* vq->used->avail_event */ - qvirtio_writew(vq->vdev, qts, vq->used + 2 + - sizeof(struct vring_used_elem) * vq->size, 0); -} - -QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, 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(struct vring_desc) * elem); - - for (i = 0; i < elem - 1; ++i) { - /* indirect->desc[i].addr */ - qvirtio_writeq(d, qs, indirect->desc + (16 * i), 0); - /* indirect->desc[i].flags */ - qvirtio_writew(d, qs, indirect->desc + (16 * i) + 12, - VRING_DESC_F_NEXT); - /* indirect->desc[i].next */ - qvirtio_writew(d, qs, indirect->desc + (16 * i) + 14, i + 1); - } - - return indirect; -} - -void qvring_indirect_desc_add(QVirtioDevice *d, QTestState *qts, - QVRingIndirectDesc *indirect, - uint64_t data, uint32_t len, bool write) -{ - uint16_t flags; - - g_assert_cmpint(indirect->index, <, indirect->elem); - - flags = qvirtio_readw(d, qts, indirect->desc + - (16 * indirect->index) + 12); - - if (write) { - flags |= VRING_DESC_F_WRITE; - } - - /* indirect->desc[indirect->index].addr */ - qvirtio_writeq(d, qts, indirect->desc + (16 * indirect->index), data); - /* indirect->desc[indirect->index].len */ - qvirtio_writel(d, qts, indirect->desc + (16 * indirect->index) + 8, len); - /* indirect->desc[indirect->index].flags */ - qvirtio_writew(d, qts, indirect->desc + (16 * indirect->index) + 12, - flags); - - indirect->index++; -} - -uint32_t qvirtqueue_add(QTestState *qts, QVirtQueue *vq, uint64_t data, - uint32_t len, bool write, bool next) -{ - uint16_t flags = 0; - vq->num_free--; - - if (write) { - flags |= VRING_DESC_F_WRITE; - } - - if (next) { - flags |= VRING_DESC_F_NEXT; - } - - /* vq->desc[vq->free_head].addr */ - qvirtio_writeq(vq->vdev, qts, vq->desc + (16 * vq->free_head), data); - /* vq->desc[vq->free_head].len */ - qvirtio_writel(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 8, len); - /* vq->desc[vq->free_head].flags */ - qvirtio_writew(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 12, flags); - - return vq->free_head++; /* Return and increase, in this order */ -} - -uint32_t qvirtqueue_add_indirect(QTestState *qts, 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 */ - qvirtio_writeq(vq->vdev, qts, vq->desc + (16 * vq->free_head), - indirect->desc); - /* vq->desc[vq->free_head].len */ - qvirtio_writel(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 8, - sizeof(struct vring_desc) * indirect->elem); - /* vq->desc[vq->free_head].flags */ - qvirtio_writew(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 12, - VRING_DESC_F_INDIRECT); - - return vq->free_head++; /* Return and increase, in this order */ -} - -void qvirtqueue_kick(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, - uint32_t free_head) -{ - /* vq->avail->idx */ - uint16_t idx = qvirtio_readw(d, qts, vq->avail + 2); - /* vq->used->flags */ - uint16_t flags; - /* vq->used->avail_event */ - uint16_t avail_event; - - /* vq->avail->ring[idx % vq->size] */ - qvirtio_writew(d, qts, vq->avail + 4 + (2 * (idx % vq->size)), free_head); - /* vq->avail->idx */ - qvirtio_writew(d, qts, vq->avail + 2, idx + 1); - - /* Must read after idx is updated */ - flags = qvirtio_readw(d, qts, vq->avail); - avail_event = qvirtio_readw(d, qts, vq->used + 4 + - sizeof(struct vring_used_elem) * vq->size); - - /* < 1 because we add elements to avail queue one by one */ - if ((flags & VRING_USED_F_NO_NOTIFY) == 0 && - (!vq->event || (uint16_t)(idx-avail_event) < 1)) { - d->bus->virtqueue_kick(d, vq); - } -} - -/* - * qvirtqueue_get_buf: - * @desc_idx: A pointer that is filled with the vq->desc[] index, may be NULL - * @len: A pointer that is filled with the length written into the buffer, may - * be NULL - * - * This function gets the next used element if there is one ready. - * - * Returns: true if an element was ready, false otherwise - */ -bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx, - uint32_t *len) -{ - uint16_t idx; - uint64_t elem_addr, addr; - - idx = qvirtio_readw(vq->vdev, qts, - vq->used + offsetof(struct vring_used, idx)); - if (idx == vq->last_used_idx) { - return false; - } - - elem_addr = vq->used + - offsetof(struct vring_used, ring) + - (vq->last_used_idx % vq->size) * - sizeof(struct vring_used_elem); - - if (desc_idx) { - addr = elem_addr + offsetof(struct vring_used_elem, id); - *desc_idx = qvirtio_readl(vq->vdev, qts, addr); - } - - if (len) { - addr = elem_addr + offsetof(struct vring_used_elem, len); - *len = qvirtio_readw(vq->vdev, qts, addr); - } - - vq->last_used_idx++; - return true; -} - -void qvirtqueue_set_used_event(QTestState *qts, QVirtQueue *vq, uint16_t idx) -{ - g_assert(vq->event); - - /* vq->avail->used_event */ - qvirtio_writew(vq->vdev, qts, vq->avail + 4 + (2 * vq->size), idx); -} - -void qvirtio_start_device(QVirtioDevice *vdev) -{ - qvirtio_reset(vdev); - qvirtio_set_acknowledge(vdev); - qvirtio_set_driver(vdev); -} - -bool qvirtio_is_big_endian(QVirtioDevice *d) -{ - return d->big_endian; -} diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h deleted file mode 100644 index 529ef7555a..0000000000 --- a/tests/libqos/virtio.h +++ /dev/null @@ -1,155 +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" -#include "standard-headers/linux/virtio_ring.h" - -#define QVIRTIO_F_BAD_FEATURE 0x40000000ull - -typedef struct QVirtioBus QVirtioBus; - -typedef struct QVirtioDevice { - const QVirtioBus *bus; - /* Device type */ - uint16_t device_type; - uint64_t features; - bool big_endian; - bool features_negotiated; -} QVirtioDevice; - -typedef struct QVirtQueue { - QVirtioDevice *vdev; - uint64_t desc; /* This points to an array of struct vring_desc */ - uint64_t avail; /* This points to a struct vring_avail */ - uint64_t used; /* This points to a struct vring_used */ - uint16_t index; - uint32_t size; - uint32_t free_head; - uint32_t num_free; - uint32_t align; - uint16_t last_used_idx; - bool indirect; - bool event; -} QVirtQueue; - -typedef struct QVRingIndirectDesc { - uint64_t desc; /* This points to an array fo struct vring_desc */ - uint16_t index; - uint16_t elem; -} QVRingIndirectDesc; - -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 */ - uint64_t (*get_features)(QVirtioDevice *d); - - /* Set features of the device */ - void (*set_features)(QVirtioDevice *d, uint64_t features); - - /* Get features of the guest */ - uint64_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); - - /* Wait for the configuration ISR status of the device */ - void (*wait_config_isr_status)(QVirtioDevice *d, gint64 timeout_us); - - /* 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, QVirtQueue *vq); - - /* Setup the virtqueue specified by index */ - QVirtQueue *(*virtqueue_setup)(QVirtioDevice *d, QGuestAllocator *alloc, - uint16_t index); - - /* Free virtqueue resources */ - void (*virtqueue_cleanup)(QVirtQueue *vq, QGuestAllocator *alloc); - - /* Notify changes in virtqueue */ - void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq); -}; - -static inline uint32_t qvring_size(uint32_t num, uint32_t align) -{ - return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (3 + num) - + align - 1) & ~(align - 1)) - + sizeof(uint16_t) * 3 + sizeof(struct vring_used_elem) * num; -} - -uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr); -uint16_t qvirtio_config_readw(QVirtioDevice *d, uint64_t addr); -uint32_t qvirtio_config_readl(QVirtioDevice *d, uint64_t addr); -uint64_t qvirtio_config_readq(QVirtioDevice *d, uint64_t addr); -uint64_t qvirtio_get_features(QVirtioDevice *d); -void qvirtio_set_features(QVirtioDevice *d, uint64_t features); -bool qvirtio_is_big_endian(QVirtioDevice *d); - -void qvirtio_reset(QVirtioDevice *d); -void qvirtio_set_acknowledge(QVirtioDevice *d); -void qvirtio_set_driver(QVirtioDevice *d); -void qvirtio_set_driver_ok(QVirtioDevice *d); - -void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d, - QVirtQueue *vq, gint64 timeout_us); -uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d, - QVirtQueue *vq, - uint64_t addr, - gint64 timeout_us); -void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d, - QVirtQueue *vq, - uint32_t desc_idx, - uint32_t *len, - gint64 timeout_us); -void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us); -QVirtQueue *qvirtqueue_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index); -void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq, - QGuestAllocator *alloc); - -void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq, - uint64_t addr); -QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, QVirtioDevice *d, - QGuestAllocator *alloc, - uint16_t elem); -void qvring_indirect_desc_add(QVirtioDevice *d, QTestState *qts, - QVRingIndirectDesc *indirect, - uint64_t data, uint32_t len, bool write); -uint32_t qvirtqueue_add(QTestState *qts, QVirtQueue *vq, uint64_t data, - uint32_t len, bool write, bool next); -uint32_t qvirtqueue_add_indirect(QTestState *qts, QVirtQueue *vq, - QVRingIndirectDesc *indirect); -void qvirtqueue_kick(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, - uint32_t free_head); -bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx, - uint32_t *len); - -void qvirtqueue_set_used_event(QTestState *qts, QVirtQueue *vq, uint16_t idx); - -void qvirtio_start_device(QVirtioDevice *vdev); - -#endif diff --git a/tests/libqos/x86_64_pc-machine.c b/tests/libqos/x86_64_pc-machine.c deleted file mode 100644 index 6dfa705217..0000000000 --- a/tests/libqos/x86_64_pc-machine.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * libqos driver framework - * - * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/> - */ - -#include "qemu/osdep.h" -#include "libqtest.h" -#include "libqos/qgraph.h" -#include "pci-pc.h" -#include "qemu/module.h" -#include "malloc-pc.h" - -typedef struct QX86PCMachine QX86PCMachine; -typedef struct i440FX_pcihost i440FX_pcihost; -typedef struct QSDHCI_PCI QSDHCI_PCI; - -struct i440FX_pcihost { - QOSGraphObject obj; - QPCIBusPC pci; -}; - -struct QX86PCMachine { - QOSGraphObject obj; - QGuestAllocator alloc; - i440FX_pcihost bridge; -}; - -/* i440FX_pcihost */ - -static QOSGraphObject *i440FX_host_get_device(void *obj, const char *device) -{ - i440FX_pcihost *host = obj; - if (!g_strcmp0(device, "pci-bus-pc")) { - return &host->pci.obj; - } - fprintf(stderr, "%s not present in i440FX-pcihost\n", device); - g_assert_not_reached(); -} - -static void qos_create_i440FX_host(i440FX_pcihost *host, - QTestState *qts, - QGuestAllocator *alloc) -{ - host->obj.get_device = i440FX_host_get_device; - qpci_init_pc(&host->pci, qts, alloc); -} - -/* x86_64/pc machine */ - -static void pc_destructor(QOSGraphObject *obj) -{ - QX86PCMachine *machine = (QX86PCMachine *) obj; - alloc_destroy(&machine->alloc); -} - -static void *pc_get_driver(void *object, const char *interface) -{ - QX86PCMachine *machine = object; - if (!g_strcmp0(interface, "memory")) { - return &machine->alloc; - } - - fprintf(stderr, "%s not present in x86_64/pc\n", interface); - g_assert_not_reached(); -} - -static QOSGraphObject *pc_get_device(void *obj, const char *device) -{ - QX86PCMachine *machine = obj; - if (!g_strcmp0(device, "i440FX-pcihost")) { - return &machine->bridge.obj; - } - - fprintf(stderr, "%s not present in x86_64/pc\n", device); - g_assert_not_reached(); -} - -static void *qos_create_machine_pc(QTestState *qts) -{ - QX86PCMachine *machine = g_new0(QX86PCMachine, 1); - machine->obj.get_device = pc_get_device; - machine->obj.get_driver = pc_get_driver; - machine->obj.destructor = pc_destructor; - pc_alloc_init(&machine->alloc, qts, ALLOC_NO_FLAGS); - qos_create_i440FX_host(&machine->bridge, qts, &machine->alloc); - - return &machine->obj; -} - -static void pc_machine_register_nodes(void) -{ - qos_node_create_machine("i386/pc", qos_create_machine_pc); - qos_node_contains("i386/pc", "i440FX-pcihost", NULL); - - qos_node_create_machine("x86_64/pc", qos_create_machine_pc); - qos_node_contains("x86_64/pc", "i440FX-pcihost", NULL); - - qos_node_create_driver("i440FX-pcihost", NULL); - qos_node_contains("i440FX-pcihost", "pci-bus-pc", NULL); -} - -libqos_init(pc_machine_register_nodes); |