Il 08/05/2013 11:43, Kevin Wolf ha scritto: > This tests that single sectors can be successfully written and correctly > read back. > > Signed-off-by: Kevin Wolf <kw...@redhat.com> > --- > tests/ide-test.c | 221 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 221 insertions(+) > > diff --git a/tests/ide-test.c b/tests/ide-test.c > index 45036e3..5fc496f 100644 > --- a/tests/ide-test.c > +++ b/tests/ide-test.c > @@ -29,8 +29,12 @@ > #include <glib.h> > > #include "libqtest.h" > +#include "libqos/pci-pc.h" > +#include "libqos/malloc-pc.h" > > #include "qemu-common.h" > +#include "hw/pci/pci_ids.h" > +#include "hw/pci/pci_regs.h" > > #define TEST_IMAGE_SIZE 64 * 1024 * 1024 > > @@ -60,12 +64,42 @@ enum { > }; > > enum { > + LBA = 0x40, > +}; > + > +enum { > + bmreg_cmd = 0x0, > + bmreg_status = 0x2, > + bmreg_prdt = 0x4, > +}; > + > +enum { > + CMD_READ_DMA = 0xc8, > + CMD_WRITE_DMA = 0xca, > CMD_IDENTIFY = 0xec, > }; > > +enum { > + BM_CMD_START = 0x1, > + BM_CMD_WRITE = 0x8, /* write = from device to memory */ > +}; > + > +enum { > + BM_STS_ACTIVE = 0x1, > + BM_STS_ERROR = 0x2, > + BM_STS_INTR = 0x4, > +}; > + > +enum { > + PRDT_EOT = 0x80000000, > +}; > + > #define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, > (mask)) > #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) > > +static QPCIBus *pcibus = NULL; > +static QGuestAllocator *guest_malloc; > + > static char tmp_path[] = "/tmp/qtest.XXXXXX"; > > static void ide_test_start(const char *cmdline_fmt, ...) > @@ -79,6 +113,7 @@ static void ide_test_start(const char *cmdline_fmt, ...) > > qtest_start(cmdline); > qtest_irq_intercept_in(global_qtest, "ioapic"); > + guest_malloc = pc_alloc_init(); > } > > static void ide_test_quit(void) > @@ -86,6 +121,188 @@ static void ide_test_quit(void) > qtest_quit(global_qtest); > } > > +static QPCIDevice *get_pci_device(uint16_t *bmdma_base) > +{ > + QPCIDevice *dev; > + uint16_t vendor_id, device_id; > + > + if (!pcibus) { > + pcibus = qpci_init_pc(); > + } > + > + /* Find PCI device and verify it's the right one */ > + dev = qpci_device_find(pcibus, QPCI_DEVFN(IDE_PCI_DEV, IDE_PCI_FUNC)); > + g_assert(dev != NULL); > + > + vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID); > + device_id = qpci_config_readw(dev, PCI_DEVICE_ID); > + g_assert(vendor_id == PCI_VENDOR_ID_INTEL); > + g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1); > + > + /* Map bmdma BAR */ > + *bmdma_base = (uint16_t)(uintptr_t) qpci_iomap(dev, 4); > + > + qpci_device_enable(dev); > + > + return dev; > +} > + > +static void free_pci_device(QPCIDevice *dev) > +{ > + /* libqos doesn't have a function for this, so free it manually */ > + g_free(dev); > +} > + > +typedef struct PrdtEntry { > + uint32_t addr; > + uint32_t size; > +} QEMU_PACKED PrdtEntry; > + > +#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, > (mask)) > +#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) > + > +static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, > + PrdtEntry *prdt, int prdt_entries) > +{ > + QPCIDevice *dev; > + uint16_t bmdma_base; > + uintptr_t guest_prdt; > + size_t len; > + bool from_dev; > + uint8_t status; > + > + dev = get_pci_device(&bmdma_base); > + > + switch (cmd) { > + case CMD_READ_DMA: > + from_dev = true; > + break; > + case CMD_WRITE_DMA: > + from_dev = false; > + break; > + default: > + g_assert_not_reached(); > + } > + > + /* Select device 0 */ > + outb(IDE_BASE + reg_device, 0 | LBA); > + > + /* Stop any running transfer, clear any pending interrupt */ > + outb(bmdma_base + bmreg_cmd, 0); > + outb(bmdma_base + bmreg_status, BM_STS_INTR); > + > + /* Setup PRDT */ > + len = sizeof(*prdt) * prdt_entries; > + guest_prdt = guest_alloc(guest_malloc, len); > + memwrite(guest_prdt, prdt, len);
What endianness? Paolo > + outl(bmdma_base + bmreg_prdt, guest_prdt);