qemu/tests/ide-test.c
<<
>>
Prefs
   1/*
   2 * IDE test cases
   3 *
   4 * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26
  27
  28#include "libqtest.h"
  29#include "libqos/libqos.h"
  30#include "libqos/pci-pc.h"
  31#include "libqos/malloc-pc.h"
  32
  33#include "qemu-common.h"
  34#include "qemu/bswap.h"
  35#include "hw/pci/pci_ids.h"
  36#include "hw/pci/pci_regs.h"
  37
  38#define TEST_IMAGE_SIZE 64 * 1024 * 1024
  39
  40#define IDE_PCI_DEV     1
  41#define IDE_PCI_FUNC    1
  42
  43#define IDE_BASE 0x1f0
  44#define IDE_PRIMARY_IRQ 14
  45
  46#define ATAPI_BLOCK_SIZE 2048
  47
  48/* How many bytes to receive via ATAPI PIO at one time.
  49 * Must be less than 0xFFFF. */
  50#define BYTE_COUNT_LIMIT 5120
  51
  52enum {
  53    reg_data        = 0x0,
  54    reg_feature     = 0x1,
  55    reg_nsectors    = 0x2,
  56    reg_lba_low     = 0x3,
  57    reg_lba_middle  = 0x4,
  58    reg_lba_high    = 0x5,
  59    reg_device      = 0x6,
  60    reg_status      = 0x7,
  61    reg_command     = 0x7,
  62};
  63
  64enum {
  65    BSY     = 0x80,
  66    DRDY    = 0x40,
  67    DF      = 0x20,
  68    DRQ     = 0x08,
  69    ERR     = 0x01,
  70};
  71
  72enum {
  73    DEV     = 0x10,
  74    LBA     = 0x40,
  75};
  76
  77enum {
  78    bmreg_cmd       = 0x0,
  79    bmreg_status    = 0x2,
  80    bmreg_prdt      = 0x4,
  81};
  82
  83enum {
  84    CMD_READ_DMA    = 0xc8,
  85    CMD_WRITE_DMA   = 0xca,
  86    CMD_FLUSH_CACHE = 0xe7,
  87    CMD_IDENTIFY    = 0xec,
  88    CMD_PACKET      = 0xa0,
  89
  90    CMDF_ABORT      = 0x100,
  91    CMDF_NO_BM      = 0x200,
  92};
  93
  94enum {
  95    BM_CMD_START    =  0x1,
  96    BM_CMD_WRITE    =  0x8, /* write = from device to memory */
  97};
  98
  99enum {
 100    BM_STS_ACTIVE   =  0x1,
 101    BM_STS_ERROR    =  0x2,
 102    BM_STS_INTR     =  0x4,
 103};
 104
 105enum {
 106    PRDT_EOT        = 0x80000000,
 107};
 108
 109#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
 110#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
 111
 112static QPCIBus *pcibus = NULL;
 113static QGuestAllocator *guest_malloc;
 114
 115static char tmp_path[] = "/tmp/qtest.XXXXXX";
 116static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
 117
 118static void ide_test_start(const char *cmdline_fmt, ...)
 119{
 120    va_list ap;
 121    char *cmdline;
 122
 123    va_start(ap, cmdline_fmt);
 124    cmdline = g_strdup_vprintf(cmdline_fmt, ap);
 125    va_end(ap);
 126
 127    qtest_start(cmdline);
 128    guest_malloc = pc_alloc_init();
 129
 130    g_free(cmdline);
 131}
 132
 133static void ide_test_quit(void)
 134{
 135    pc_alloc_uninit(guest_malloc);
 136    guest_malloc = NULL;
 137    qtest_end();
 138}
 139
 140static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
 141{
 142    QPCIDevice *dev;
 143    uint16_t vendor_id, device_id;
 144
 145    if (!pcibus) {
 146        pcibus = qpci_init_pc();
 147    }
 148
 149    /* Find PCI device and verify it's the right one */
 150    dev = qpci_device_find(pcibus, QPCI_DEVFN(IDE_PCI_DEV, IDE_PCI_FUNC));
 151    g_assert(dev != NULL);
 152
 153    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
 154    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
 155    g_assert(vendor_id == PCI_VENDOR_ID_INTEL);
 156    g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
 157
 158    /* Map bmdma BAR */
 159    *bmdma_base = (uint16_t)(uintptr_t) qpci_iomap(dev, 4, NULL);
 160
 161    qpci_device_enable(dev);
 162
 163    return dev;
 164}
 165
 166static void free_pci_device(QPCIDevice *dev)
 167{
 168    /* libqos doesn't have a function for this, so free it manually */
 169    g_free(dev);
 170}
 171
 172typedef struct PrdtEntry {
 173    uint32_t addr;
 174    uint32_t size;
 175} QEMU_PACKED PrdtEntry;
 176
 177#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
 178#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
 179
 180static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
 181                            PrdtEntry *prdt, int prdt_entries,
 182                            void(*post_exec)(uint64_t sector, int nb_sectors))
 183{
 184    QPCIDevice *dev;
 185    uint16_t bmdma_base;
 186    uintptr_t guest_prdt;
 187    size_t len;
 188    bool from_dev;
 189    uint8_t status;
 190    int flags;
 191
 192    dev = get_pci_device(&bmdma_base);
 193
 194    flags = cmd & ~0xff;
 195    cmd &= 0xff;
 196
 197    switch (cmd) {
 198    case CMD_READ_DMA:
 199    case CMD_PACKET:
 200        /* Assuming we only test data reads w/ ATAPI, otherwise we need to know
 201         * the SCSI command being sent in the packet, too. */
 202        from_dev = true;
 203        break;
 204    case CMD_WRITE_DMA:
 205        from_dev = false;
 206        break;
 207    default:
 208        g_assert_not_reached();
 209    }
 210
 211    if (flags & CMDF_NO_BM) {
 212        qpci_config_writew(dev, PCI_COMMAND,
 213                           PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
 214    }
 215
 216    /* Select device 0 */
 217    outb(IDE_BASE + reg_device, 0 | LBA);
 218
 219    /* Stop any running transfer, clear any pending interrupt */
 220    outb(bmdma_base + bmreg_cmd, 0);
 221    outb(bmdma_base + bmreg_status, BM_STS_INTR);
 222
 223    /* Setup PRDT */
 224    len = sizeof(*prdt) * prdt_entries;
 225    guest_prdt = guest_alloc(guest_malloc, len);
 226    memwrite(guest_prdt, prdt, len);
 227    outl(bmdma_base + bmreg_prdt, guest_prdt);
 228
 229    /* ATA DMA command */
 230    if (cmd == CMD_PACKET) {
 231        /* Enables ATAPI DMA; otherwise PIO is attempted */
 232        outb(IDE_BASE + reg_feature, 0x01);
 233    } else {
 234        outb(IDE_BASE + reg_nsectors, nb_sectors);
 235        outb(IDE_BASE + reg_lba_low,    sector & 0xff);
 236        outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff);
 237        outb(IDE_BASE + reg_lba_high,   (sector >> 16) & 0xff);
 238    }
 239
 240    outb(IDE_BASE + reg_command, cmd);
 241
 242    if (post_exec) {
 243        post_exec(sector, nb_sectors);
 244    }
 245
 246    /* Start DMA transfer */
 247    outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
 248
 249    if (flags & CMDF_ABORT) {
 250        outb(bmdma_base + bmreg_cmd, 0);
 251    }
 252
 253    /* Wait for the DMA transfer to complete */
 254    do {
 255        status = inb(bmdma_base + bmreg_status);
 256    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
 257
 258    g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
 259
 260    /* Check IDE status code */
 261    assert_bit_set(inb(IDE_BASE + reg_status), DRDY);
 262    assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ);
 263
 264    /* Reading the status register clears the IRQ */
 265    g_assert(!get_irq(IDE_PRIMARY_IRQ));
 266
 267    /* Stop DMA transfer if still active */
 268    if (status & BM_STS_ACTIVE) {
 269        outb(bmdma_base + bmreg_cmd, 0);
 270    }
 271
 272    free_pci_device(dev);
 273
 274    return status;
 275}
 276
 277static void test_bmdma_simple_rw(void)
 278{
 279    uint8_t status;
 280    uint8_t *buf;
 281    uint8_t *cmpbuf;
 282    size_t len = 512;
 283    uintptr_t guest_buf = guest_alloc(guest_malloc, len);
 284
 285    PrdtEntry prdt[] = {
 286        {
 287            .addr = cpu_to_le32(guest_buf),
 288            .size = cpu_to_le32(len | PRDT_EOT),
 289        },
 290    };
 291
 292    buf = g_malloc(len);
 293    cmpbuf = g_malloc(len);
 294
 295    /* Write 0x55 pattern to sector 0 */
 296    memset(buf, 0x55, len);
 297    memwrite(guest_buf, buf, len);
 298
 299    status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt,
 300                              ARRAY_SIZE(prdt), NULL);
 301    g_assert_cmphex(status, ==, BM_STS_INTR);
 302    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 303
 304    /* Write 0xaa pattern to sector 1 */
 305    memset(buf, 0xaa, len);
 306    memwrite(guest_buf, buf, len);
 307
 308    status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt,
 309                              ARRAY_SIZE(prdt), NULL);
 310    g_assert_cmphex(status, ==, BM_STS_INTR);
 311    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 312
 313    /* Read and verify 0x55 pattern in sector 0 */
 314    memset(cmpbuf, 0x55, len);
 315
 316    status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt), NULL);
 317    g_assert_cmphex(status, ==, BM_STS_INTR);
 318    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 319
 320    memread(guest_buf, buf, len);
 321    g_assert(memcmp(buf, cmpbuf, len) == 0);
 322
 323    /* Read and verify 0xaa pattern in sector 1 */
 324    memset(cmpbuf, 0xaa, len);
 325
 326    status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt), NULL);
 327    g_assert_cmphex(status, ==, BM_STS_INTR);
 328    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 329
 330    memread(guest_buf, buf, len);
 331    g_assert(memcmp(buf, cmpbuf, len) == 0);
 332
 333
 334    g_free(buf);
 335    g_free(cmpbuf);
 336}
 337
 338static void test_bmdma_short_prdt(void)
 339{
 340    uint8_t status;
 341
 342    PrdtEntry prdt[] = {
 343        {
 344            .addr = 0,
 345            .size = cpu_to_le32(0x10 | PRDT_EOT),
 346        },
 347    };
 348
 349    /* Normal request */
 350    status = send_dma_request(CMD_READ_DMA, 0, 1,
 351                              prdt, ARRAY_SIZE(prdt), NULL);
 352    g_assert_cmphex(status, ==, 0);
 353    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 354
 355    /* Abort the request before it completes */
 356    status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
 357                              prdt, ARRAY_SIZE(prdt), NULL);
 358    g_assert_cmphex(status, ==, 0);
 359    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 360}
 361
 362static void test_bmdma_one_sector_short_prdt(void)
 363{
 364    uint8_t status;
 365
 366    /* Read 2 sectors but only give 1 sector in PRDT */
 367    PrdtEntry prdt[] = {
 368        {
 369            .addr = 0,
 370            .size = cpu_to_le32(0x200 | PRDT_EOT),
 371        },
 372    };
 373
 374    /* Normal request */
 375    status = send_dma_request(CMD_READ_DMA, 0, 2,
 376                              prdt, ARRAY_SIZE(prdt), NULL);
 377    g_assert_cmphex(status, ==, 0);
 378    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 379
 380    /* Abort the request before it completes */
 381    status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 2,
 382                              prdt, ARRAY_SIZE(prdt), NULL);
 383    g_assert_cmphex(status, ==, 0);
 384    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 385}
 386
 387static void test_bmdma_long_prdt(void)
 388{
 389    uint8_t status;
 390
 391    PrdtEntry prdt[] = {
 392        {
 393            .addr = 0,
 394            .size = cpu_to_le32(0x1000 | PRDT_EOT),
 395        },
 396    };
 397
 398    /* Normal request */
 399    status = send_dma_request(CMD_READ_DMA, 0, 1,
 400                              prdt, ARRAY_SIZE(prdt), NULL);
 401    g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
 402    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 403
 404    /* Abort the request before it completes */
 405    status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
 406                              prdt, ARRAY_SIZE(prdt), NULL);
 407    g_assert_cmphex(status, ==, BM_STS_INTR);
 408    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 409}
 410
 411static void test_bmdma_no_busmaster(void)
 412{
 413    uint8_t status;
 414
 415    /* No PRDT_EOT, each entry addr 0/size 64k, and in theory qemu shouldn't be
 416     * able to access it anyway because the Bus Master bit in the PCI command
 417     * register isn't set. This is complete nonsense, but it used to be pretty
 418     * good at confusing and occasionally crashing qemu. */
 419    PrdtEntry prdt[4096] = { };
 420
 421    status = send_dma_request(CMD_READ_DMA | CMDF_NO_BM, 0, 512,
 422                              prdt, ARRAY_SIZE(prdt), NULL);
 423
 424    /* Not entirely clear what the expected result is, but this is what we get
 425     * in practice. At least we want to be aware of any changes. */
 426    g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
 427    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 428}
 429
 430static void test_bmdma_setup(void)
 431{
 432    ide_test_start(
 433        "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
 434        "-global ide-hd.ver=%s",
 435        tmp_path, "testdisk", "version");
 436    qtest_irq_intercept_in(global_qtest, "ioapic");
 437}
 438
 439static void test_bmdma_teardown(void)
 440{
 441    ide_test_quit();
 442}
 443
 444static void string_cpu_to_be16(uint16_t *s, size_t bytes)
 445{
 446    g_assert((bytes & 1) == 0);
 447    bytes /= 2;
 448
 449    while (bytes--) {
 450        *s = cpu_to_be16(*s);
 451        s++;
 452    }
 453}
 454
 455static void test_identify(void)
 456{
 457    uint8_t data;
 458    uint16_t buf[256];
 459    int i;
 460    int ret;
 461
 462    ide_test_start(
 463        "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
 464        "-global ide-hd.ver=%s",
 465        tmp_path, "testdisk", "version");
 466
 467    /* IDENTIFY command on device 0*/
 468    outb(IDE_BASE + reg_device, 0);
 469    outb(IDE_BASE + reg_command, CMD_IDENTIFY);
 470
 471    /* Read in the IDENTIFY buffer and check registers */
 472    data = inb(IDE_BASE + reg_device);
 473    g_assert_cmpint(data & DEV, ==, 0);
 474
 475    for (i = 0; i < 256; i++) {
 476        data = inb(IDE_BASE + reg_status);
 477        assert_bit_set(data, DRDY | DRQ);
 478        assert_bit_clear(data, BSY | DF | ERR);
 479
 480        ((uint16_t*) buf)[i] = inw(IDE_BASE + reg_data);
 481    }
 482
 483    data = inb(IDE_BASE + reg_status);
 484    assert_bit_set(data, DRDY);
 485    assert_bit_clear(data, BSY | DF | ERR | DRQ);
 486
 487    /* Check serial number/version in the buffer */
 488    string_cpu_to_be16(&buf[10], 20);
 489    ret = memcmp(&buf[10], "testdisk            ", 20);
 490    g_assert(ret == 0);
 491
 492    string_cpu_to_be16(&buf[23], 8);
 493    ret = memcmp(&buf[23], "version ", 8);
 494    g_assert(ret == 0);
 495
 496    /* Write cache enabled bit */
 497    assert_bit_set(buf[85], 0x20);
 498
 499    ide_test_quit();
 500}
 501
 502/*
 503 * Write sector 1 with random data to make IDE storage dirty
 504 * Needed for flush tests so that flushes actually go though the block layer
 505 */
 506static void make_dirty(uint8_t device)
 507{
 508    uint8_t status;
 509    size_t len = 512;
 510    uintptr_t guest_buf;
 511    void* buf;
 512
 513    guest_buf = guest_alloc(guest_malloc, len);
 514    buf = g_malloc(len);
 515    g_assert(guest_buf);
 516    g_assert(buf);
 517
 518    memwrite(guest_buf, buf, len);
 519
 520    PrdtEntry prdt[] = {
 521        {
 522            .addr = cpu_to_le32(guest_buf),
 523            .size = cpu_to_le32(len | PRDT_EOT),
 524        },
 525    };
 526
 527    status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt,
 528                              ARRAY_SIZE(prdt), NULL);
 529    g_assert_cmphex(status, ==, BM_STS_INTR);
 530    assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
 531
 532    g_free(buf);
 533}
 534
 535static void test_flush(void)
 536{
 537    uint8_t data;
 538
 539    ide_test_start(
 540        "-drive file=blkdebug::%s,if=ide,cache=writeback,format=raw",
 541        tmp_path);
 542
 543    qtest_irq_intercept_in(global_qtest, "ioapic");
 544
 545    /* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
 546    make_dirty(0);
 547
 548    /* Delay the completion of the flush request until we explicitly do it */
 549    g_free(hmp("qemu-io ide0-hd0 \"break flush_to_os A\""));
 550
 551    /* FLUSH CACHE command on device 0*/
 552    outb(IDE_BASE + reg_device, 0);
 553    outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
 554
 555    /* Check status while request is in flight*/
 556    data = inb(IDE_BASE + reg_status);
 557    assert_bit_set(data, BSY | DRDY);
 558    assert_bit_clear(data, DF | ERR | DRQ);
 559
 560    /* Complete the command */
 561    g_free(hmp("qemu-io ide0-hd0 \"resume A\""));
 562
 563    /* Check registers */
 564    data = inb(IDE_BASE + reg_device);
 565    g_assert_cmpint(data & DEV, ==, 0);
 566
 567    do {
 568        data = inb(IDE_BASE + reg_status);
 569    } while (data & BSY);
 570
 571    assert_bit_set(data, DRDY);
 572    assert_bit_clear(data, BSY | DF | ERR | DRQ);
 573
 574    ide_test_quit();
 575}
 576
 577static void test_retry_flush(const char *machine)
 578{
 579    uint8_t data;
 580    const char *s;
 581
 582    prepare_blkdebug_script(debug_path, "flush_to_disk");
 583
 584    ide_test_start(
 585        "-vnc none "
 586        "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,format=raw,"
 587        "rerror=stop,werror=stop",
 588        debug_path, tmp_path);
 589
 590    qtest_irq_intercept_in(global_qtest, "ioapic");
 591
 592    /* Dirty media so that CMD_FLUSH_CACHE will actually go to disk */
 593    make_dirty(0);
 594
 595    /* FLUSH CACHE command on device 0*/
 596    outb(IDE_BASE + reg_device, 0);
 597    outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
 598
 599    /* Check status while request is in flight*/
 600    data = inb(IDE_BASE + reg_status);
 601    assert_bit_set(data, BSY | DRDY);
 602    assert_bit_clear(data, DF | ERR | DRQ);
 603
 604    qmp_eventwait("STOP");
 605
 606    /* Complete the command */
 607    s = "{'execute':'cont' }";
 608    qmp_discard_response(s);
 609
 610    /* Check registers */
 611    data = inb(IDE_BASE + reg_device);
 612    g_assert_cmpint(data & DEV, ==, 0);
 613
 614    do {
 615        data = inb(IDE_BASE + reg_status);
 616    } while (data & BSY);
 617
 618    assert_bit_set(data, DRDY);
 619    assert_bit_clear(data, BSY | DF | ERR | DRQ);
 620
 621    ide_test_quit();
 622}
 623
 624static void test_flush_nodev(void)
 625{
 626    ide_test_start("");
 627
 628    /* FLUSH CACHE command on device 0*/
 629    outb(IDE_BASE + reg_device, 0);
 630    outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
 631
 632    /* Just testing that qemu doesn't crash... */
 633
 634    ide_test_quit();
 635}
 636
 637static void test_pci_retry_flush(void)
 638{
 639    test_retry_flush("pc");
 640}
 641
 642static void test_isa_retry_flush(void)
 643{
 644    test_retry_flush("isapc");
 645}
 646
 647typedef struct Read10CDB {
 648    uint8_t opcode;
 649    uint8_t flags;
 650    uint32_t lba;
 651    uint8_t reserved;
 652    uint16_t nblocks;
 653    uint8_t control;
 654    uint16_t padding;
 655} __attribute__((__packed__)) Read10CDB;
 656
 657static void send_scsi_cdb_read10(uint64_t lba, int nblocks)
 658{
 659    Read10CDB pkt = { .padding = 0 };
 660    int i;
 661
 662    g_assert_cmpint(lba, <=, UINT32_MAX);
 663    g_assert_cmpint(nblocks, <=, UINT16_MAX);
 664    g_assert_cmpint(nblocks, >=, 0);
 665
 666    /* Construct SCSI CDB packet */
 667    pkt.opcode = 0x28;
 668    pkt.lba = cpu_to_be32(lba);
 669    pkt.nblocks = cpu_to_be16(nblocks);
 670
 671    /* Send Packet */
 672    for (i = 0; i < sizeof(Read10CDB)/2; i++) {
 673        outw(IDE_BASE + reg_data, cpu_to_le16(((uint16_t *)&pkt)[i]));
 674    }
 675}
 676
 677static void nsleep(int64_t nsecs)
 678{
 679    const struct timespec val = { .tv_nsec = nsecs };
 680    nanosleep(&val, NULL);
 681    clock_set(nsecs);
 682}
 683
 684static uint8_t ide_wait_clear(uint8_t flag)
 685{
 686    uint8_t data;
 687    time_t st;
 688
 689    /* Wait with a 5 second timeout */
 690    time(&st);
 691    while (true) {
 692        data = inb(IDE_BASE + reg_status);
 693        if (!(data & flag)) {
 694            return data;
 695        }
 696        if (difftime(time(NULL), st) > 5.0) {
 697            break;
 698        }
 699        nsleep(400);
 700    }
 701    g_assert_not_reached();
 702}
 703
 704static void ide_wait_intr(int irq)
 705{
 706    time_t st;
 707    bool intr;
 708
 709    time(&st);
 710    while (true) {
 711        intr = get_irq(irq);
 712        if (intr) {
 713            return;
 714        }
 715        if (difftime(time(NULL), st) > 5.0) {
 716            break;
 717        }
 718        nsleep(400);
 719    }
 720
 721    g_assert_not_reached();
 722}
 723
 724static void cdrom_pio_impl(int nblocks)
 725{
 726    FILE *fh;
 727    int patt_blocks = MAX(16, nblocks);
 728    size_t patt_len = ATAPI_BLOCK_SIZE * patt_blocks;
 729    char *pattern = g_malloc(patt_len);
 730    size_t rxsize = ATAPI_BLOCK_SIZE * nblocks;
 731    uint16_t *rx = g_malloc0(rxsize);
 732    int i, j;
 733    uint8_t data;
 734    uint16_t limit;
 735
 736    /* Prepopulate the CDROM with an interesting pattern */
 737    generate_pattern(pattern, patt_len, ATAPI_BLOCK_SIZE);
 738    fh = fopen(tmp_path, "w+");
 739    fwrite(pattern, ATAPI_BLOCK_SIZE, patt_blocks, fh);
 740    fclose(fh);
 741
 742    ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
 743                   "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
 744    qtest_irq_intercept_in(global_qtest, "ioapic");
 745
 746    /* PACKET command on device 0 */
 747    outb(IDE_BASE + reg_device, 0);
 748    outb(IDE_BASE + reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF);
 749    outb(IDE_BASE + reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF));
 750    outb(IDE_BASE + reg_command, CMD_PACKET);
 751    /* HP0: Check_Status_A State */
 752    nsleep(400);
 753    data = ide_wait_clear(BSY);
 754    /* HP1: Send_Packet State */
 755    assert_bit_set(data, DRQ | DRDY);
 756    assert_bit_clear(data, ERR | DF | BSY);
 757
 758    /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */
 759    send_scsi_cdb_read10(0, nblocks);
 760
 761    /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes.
 762     * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes.
 763     * We allow an odd limit only when the remaining transfer size is
 764     * less than BYTE_COUNT_LIMIT. However, SCSI's read10 command can only
 765     * request n blocks, so our request size is always even.
 766     * For this reason, we assume there is never a hanging byte to fetch. */
 767    g_assert(!(rxsize & 1));
 768    limit = BYTE_COUNT_LIMIT & ~1;
 769    for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) {
 770        size_t offset = i * (limit / 2);
 771        size_t rem = (rxsize / 2) - offset;
 772
 773        /* HP3: INTRQ_Wait */
 774        ide_wait_intr(IDE_PRIMARY_IRQ);
 775
 776        /* HP2: Check_Status_B (and clear IRQ) */
 777        data = ide_wait_clear(BSY);
 778        assert_bit_set(data, DRQ | DRDY);
 779        assert_bit_clear(data, ERR | DF | BSY);
 780
 781        /* HP4: Transfer_Data */
 782        for (j = 0; j < MIN((limit / 2), rem); j++) {
 783            rx[offset + j] = le16_to_cpu(inw(IDE_BASE + reg_data));
 784        }
 785    }
 786
 787    /* Check for final completion IRQ */
 788    ide_wait_intr(IDE_PRIMARY_IRQ);
 789
 790    /* Sanity check final state */
 791    data = ide_wait_clear(DRQ);
 792    assert_bit_set(data, DRDY);
 793    assert_bit_clear(data, DRQ | ERR | DF | BSY);
 794
 795    g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0);
 796    g_free(pattern);
 797    g_free(rx);
 798    test_bmdma_teardown();
 799}
 800
 801static void test_cdrom_pio(void)
 802{
 803    cdrom_pio_impl(1);
 804}
 805
 806static void test_cdrom_pio_large(void)
 807{
 808    /* Test a few loops of the PIO DRQ mechanism. */
 809    cdrom_pio_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE);
 810}
 811
 812
 813static void test_cdrom_dma(void)
 814{
 815    static const size_t len = ATAPI_BLOCK_SIZE;
 816    char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16);
 817    char *rx = g_malloc0(len);
 818    uintptr_t guest_buf;
 819    PrdtEntry prdt[1];
 820    FILE *fh;
 821
 822    ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 "
 823                   "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
 824    qtest_irq_intercept_in(global_qtest, "ioapic");
 825
 826    guest_buf = guest_alloc(guest_malloc, len);
 827    prdt[0].addr = cpu_to_le32(guest_buf);
 828    prdt[0].size = cpu_to_le32(len | PRDT_EOT);
 829
 830    generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE);
 831    fh = fopen(tmp_path, "w+");
 832    fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh);
 833    fclose(fh);
 834
 835    send_dma_request(CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10);
 836
 837    /* Read back data from guest memory into local qtest memory */
 838    memread(guest_buf, rx, len);
 839    g_assert_cmpint(memcmp(pattern, rx, len), ==, 0);
 840
 841    g_free(pattern);
 842    g_free(rx);
 843    test_bmdma_teardown();
 844}
 845
 846int main(int argc, char **argv)
 847{
 848    const char *arch = qtest_get_arch();
 849    int fd;
 850    int ret;
 851
 852    /* Check architecture */
 853    if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
 854        g_test_message("Skipping test for non-x86\n");
 855        return 0;
 856    }
 857
 858    /* Create temporary blkdebug instructions */
 859    fd = mkstemp(debug_path);
 860    g_assert(fd >= 0);
 861    close(fd);
 862
 863    /* Create a temporary raw image */
 864    fd = mkstemp(tmp_path);
 865    g_assert(fd >= 0);
 866    ret = ftruncate(fd, TEST_IMAGE_SIZE);
 867    g_assert(ret == 0);
 868    close(fd);
 869
 870    /* Run the tests */
 871    g_test_init(&argc, &argv, NULL);
 872
 873    qtest_add_func("/ide/identify", test_identify);
 874
 875    qtest_add_func("/ide/bmdma/setup", test_bmdma_setup);
 876    qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
 877    qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt);
 878    qtest_add_func("/ide/bmdma/one_sector_short_prdt",
 879                   test_bmdma_one_sector_short_prdt);
 880    qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
 881    qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
 882    qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
 883
 884    qtest_add_func("/ide/flush", test_flush);
 885    qtest_add_func("/ide/flush/nodev", test_flush_nodev);
 886    qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush);
 887    qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush);
 888
 889    qtest_add_func("/ide/cdrom/pio", test_cdrom_pio);
 890    qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large);
 891    qtest_add_func("/ide/cdrom/dma", test_cdrom_dma);
 892
 893    ret = g_test_run();
 894
 895    /* Cleanup */
 896    unlink(tmp_path);
 897    unlink(debug_path);
 898
 899    return ret;
 900}
 901