qemu/tests/hd-geo-test.c
<<
>>
Prefs
   1/*
   2 * Hard disk geometry test cases.
   3 *
   4 * Copyright (c) 2012 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Markus Armbruster <armbru@redhat.com>,
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13/*
  14 * Covers only IDE and tests only CMOS contents.  Better than nothing.
  15 * Improvements welcome.
  16 */
  17
  18#include "qemu/osdep.h"
  19#include "qemu-common.h"
  20#include "qemu/bswap.h"
  21#include "qapi/qmp/qlist.h"
  22#include "libqtest.h"
  23#include "libqos/fw_cfg.h"
  24#include "libqos/libqos.h"
  25#include "standard-headers/linux/qemu_fw_cfg.h"
  26
  27#define ARGV_SIZE 256
  28
  29static char *create_test_img(int secs)
  30{
  31    char *template = strdup("/tmp/qtest.XXXXXX");
  32    int fd, ret;
  33
  34    fd = mkstemp(template);
  35    g_assert(fd >= 0);
  36    ret = ftruncate(fd, (off_t)secs * 512);
  37    g_assert(ret == 0);
  38    close(fd);
  39    return template;
  40}
  41
  42typedef struct {
  43    int cyls, heads, secs, trans;
  44} CHST;
  45
  46typedef enum {
  47    mbr_blank, mbr_lba, mbr_chs,
  48    mbr_last
  49} MBRcontents;
  50
  51typedef enum {
  52    /* order is relevant */
  53    backend_small, backend_large, backend_empty,
  54    backend_last
  55} Backend;
  56
  57static const int img_secs[backend_last] = {
  58    [backend_small] = 61440,
  59    [backend_large] = 8388608,
  60    [backend_empty] = -1,
  61};
  62
  63static const CHST hd_chst[backend_last][mbr_last] = {
  64    [backend_small] = {
  65        [mbr_blank] = { 60, 16, 63, 0 },
  66        [mbr_lba]   = { 60, 16, 63, 2 },
  67        [mbr_chs]   = { 60, 16, 63, 0 }
  68    },
  69    [backend_large] = {
  70        [mbr_blank] = { 8322, 16, 63, 1 },
  71        [mbr_lba]   = { 8322, 16, 63, 1 },
  72        [mbr_chs]   = { 8322, 16, 63, 0 }
  73    },
  74};
  75
  76static char *img_file_name[backend_last];
  77
  78static const CHST *cur_ide[4];
  79
  80static bool is_hd(const CHST *expected_chst)
  81{
  82    return expected_chst && expected_chst->cyls;
  83}
  84
  85static void test_cmos_byte(QTestState *qts, int reg, int expected)
  86{
  87    enum { cmos_base = 0x70 };
  88    int actual;
  89
  90    qtest_outb(qts, cmos_base + 0, reg);
  91    actual = qtest_inb(qts, cmos_base + 1);
  92    g_assert(actual == expected);
  93}
  94
  95static void test_cmos_bytes(QTestState *qts, int reg0, int n,
  96                            uint8_t expected[])
  97{
  98    int i;
  99
 100    for (i = 0; i < 9; i++) {
 101        test_cmos_byte(qts, reg0 + i, expected[i]);
 102    }
 103}
 104
 105static void test_cmos_disk_data(QTestState *qts)
 106{
 107    test_cmos_byte(qts, 0x12,
 108                   (is_hd(cur_ide[0]) ? 0xf0 : 0) |
 109                   (is_hd(cur_ide[1]) ? 0x0f : 0));
 110}
 111
 112static void test_cmos_drive_cyl(QTestState *qts, int reg0,
 113                                const CHST *expected_chst)
 114{
 115    if (is_hd(expected_chst)) {
 116        int c = expected_chst->cyls;
 117        int h = expected_chst->heads;
 118        int s = expected_chst->secs;
 119        uint8_t expected_bytes[9] = {
 120            c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
 121            c & 0xff, c >> 8, s
 122        };
 123        test_cmos_bytes(qts, reg0, 9, expected_bytes);
 124    } else {
 125        int i;
 126
 127        for (i = 0; i < 9; i++) {
 128            test_cmos_byte(qts, reg0 + i, 0);
 129        }
 130    }
 131}
 132
 133static void test_cmos_drive1(QTestState *qts)
 134{
 135    test_cmos_byte(qts, 0x19, is_hd(cur_ide[0]) ? 47 : 0);
 136    test_cmos_drive_cyl(qts, 0x1b, cur_ide[0]);
 137}
 138
 139static void test_cmos_drive2(QTestState *qts)
 140{
 141    test_cmos_byte(qts, 0x1a, is_hd(cur_ide[1]) ? 47 : 0);
 142    test_cmos_drive_cyl(qts, 0x24, cur_ide[1]);
 143}
 144
 145static void test_cmos_disktransflag(QTestState *qts)
 146{
 147    int val, i;
 148
 149    val = 0;
 150    for (i = 0; i < ARRAY_SIZE(cur_ide); i++) {
 151        if (is_hd(cur_ide[i])) {
 152            val |= cur_ide[i]->trans << (2 * i);
 153        }
 154    }
 155    test_cmos_byte(qts, 0x39, val);
 156}
 157
 158static void test_cmos(QTestState *qts)
 159{
 160    test_cmos_disk_data(qts);
 161    test_cmos_drive1(qts);
 162    test_cmos_drive2(qts);
 163    test_cmos_disktransflag(qts);
 164}
 165
 166static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
 167{
 168    g_assert(argc + 1 < argv_sz);
 169    argv[argc++] = arg;
 170    argv[argc] = NULL;
 171    return argc;
 172}
 173
 174static int setup_common(char *argv[], int argv_sz)
 175{
 176    memset(cur_ide, 0, sizeof(cur_ide));
 177    return append_arg(0, argv, argv_sz,
 178                      g_strdup("-nodefaults"));
 179}
 180
 181static void setup_mbr(int img_idx, MBRcontents mbr)
 182{
 183    static const uint8_t part_lba[16] = {
 184        /* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
 185        0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
 186    };
 187    static const uint8_t part_chs[16] = {
 188        /* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
 189        0x80, 1, 1, 0, 6,  15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
 190    };
 191    uint8_t buf[512];
 192    int fd, ret;
 193
 194    memset(buf, 0, sizeof(buf));
 195
 196    if (mbr != mbr_blank) {
 197        buf[0x1fe] = 0x55;
 198        buf[0x1ff] = 0xAA;
 199        memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16);
 200    }
 201
 202    fd = open(img_file_name[img_idx], O_WRONLY);
 203    g_assert(fd >= 0);
 204    ret = write(fd, buf, sizeof(buf));
 205    g_assert(ret == sizeof(buf));
 206    close(fd);
 207}
 208
 209static int setup_ide(int argc, char *argv[], int argv_sz,
 210                     int ide_idx, const char *dev, int img_idx,
 211                     MBRcontents mbr)
 212{
 213    char *s1, *s2, *s3;
 214
 215    s1 = g_strdup_printf("-drive id=drive%d,if=%s",
 216                         ide_idx, dev ? "none" : "ide");
 217    s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
 218
 219    if (img_secs[img_idx] >= 0) {
 220        setup_mbr(img_idx, mbr);
 221        s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]);
 222    } else {
 223        s3 = g_strdup(",media=cdrom");
 224    }
 225    argc = append_arg(argc, argv, argv_sz,
 226                      g_strdup_printf("%s%s%s", s1, s2, s3));
 227    g_free(s1);
 228    g_free(s2);
 229    g_free(s3);
 230
 231    if (dev) {
 232        argc = append_arg(argc, argv, argv_sz,
 233                          g_strdup_printf("-device %s,drive=drive%d,"
 234                                          "bus=ide.%d,unit=%d",
 235                                          dev, ide_idx,
 236                                          ide_idx / 2, ide_idx % 2));
 237    }
 238    return argc;
 239}
 240
 241/*
 242 * Test case: no IDE devices
 243 */
 244static void test_ide_none(void)
 245{
 246    char **argv = g_new0(char *, ARGV_SIZE);
 247    char *args;
 248    QTestState *qts;
 249
 250    setup_common(argv, ARGV_SIZE);
 251    args = g_strjoinv(" ", argv);
 252    qts = qtest_init(args);
 253    g_strfreev(argv);
 254    g_free(args);
 255    test_cmos(qts);
 256    qtest_quit(qts);
 257}
 258
 259static void test_ide_mbr(bool use_device, MBRcontents mbr)
 260{
 261    char **argv = g_new0(char *, ARGV_SIZE);
 262    char *args;
 263    int argc;
 264    Backend i;
 265    const char *dev;
 266    QTestState *qts;
 267
 268    argc = setup_common(argv, ARGV_SIZE);
 269    for (i = 0; i < backend_last; i++) {
 270        cur_ide[i] = &hd_chst[i][mbr];
 271        dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
 272        argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
 273    }
 274    args = g_strjoinv(" ", argv);
 275    qts = qtest_init(args);
 276    g_strfreev(argv);
 277    g_free(args);
 278    test_cmos(qts);
 279    qtest_quit(qts);
 280}
 281
 282/*
 283 * Test case: IDE devices (if=ide) with blank MBRs
 284 */
 285static void test_ide_drive_mbr_blank(void)
 286{
 287    test_ide_mbr(false, mbr_blank);
 288}
 289
 290/*
 291 * Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
 292 */
 293static void test_ide_drive_mbr_lba(void)
 294{
 295    test_ide_mbr(false, mbr_lba);
 296}
 297
 298/*
 299 * Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
 300 */
 301static void test_ide_drive_mbr_chs(void)
 302{
 303    test_ide_mbr(false, mbr_chs);
 304}
 305
 306/*
 307 * Test case: IDE devices (if=none) with blank MBRs
 308 */
 309static void test_ide_device_mbr_blank(void)
 310{
 311    test_ide_mbr(true, mbr_blank);
 312}
 313
 314/*
 315 * Test case: IDE devices (if=none) with MBRs indicating LBA is in use
 316 */
 317static void test_ide_device_mbr_lba(void)
 318{
 319    test_ide_mbr(true, mbr_lba);
 320}
 321
 322/*
 323 * Test case: IDE devices (if=none) with MBRs indicating CHS is in use
 324 */
 325static void test_ide_device_mbr_chs(void)
 326{
 327    test_ide_mbr(true, mbr_chs);
 328}
 329
 330static void test_ide_drive_user(const char *dev, bool trans)
 331{
 332    char **argv = g_new0(char *, ARGV_SIZE);
 333    char *args, *opts;
 334    int argc;
 335    int secs = img_secs[backend_small];
 336    const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
 337    QTestState *qts;
 338
 339    argc = setup_common(argv, ARGV_SIZE);
 340    opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
 341                           dev, trans ? "bios-chs-trans=lba," : "",
 342                           expected_chst.cyls, expected_chst.heads,
 343                           expected_chst.secs);
 344    cur_ide[0] = &expected_chst;
 345    argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
 346    g_free(opts);
 347    args = g_strjoinv(" ", argv);
 348    qts = qtest_init(args);
 349    g_strfreev(argv);
 350    g_free(args);
 351    test_cmos(qts);
 352    qtest_quit(qts);
 353}
 354
 355/*
 356 * Test case: IDE device (if=none) with explicit CHS
 357 */
 358static void test_ide_device_user_chs(void)
 359{
 360    test_ide_drive_user("ide-hd", false);
 361}
 362
 363/*
 364 * Test case: IDE device (if=none) with explicit CHS and translation
 365 */
 366static void test_ide_device_user_chst(void)
 367{
 368    test_ide_drive_user("ide-hd", true);
 369}
 370
 371/*
 372 * Test case: IDE devices (if=ide), but use index=0 for CD-ROM
 373 */
 374static void test_ide_drive_cd_0(void)
 375{
 376    char **argv = g_new0(char *, ARGV_SIZE);
 377    char *args;
 378    int argc, ide_idx;
 379    Backend i;
 380    QTestState *qts;
 381
 382    argc = setup_common(argv, ARGV_SIZE);
 383    for (i = 0; i <= backend_empty; i++) {
 384        ide_idx = backend_empty - i;
 385        cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
 386        argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
 387    }
 388    args = g_strjoinv(" ", argv);
 389    qts = qtest_init(args);
 390    g_strfreev(argv);
 391    g_free(args);
 392    test_cmos(qts);
 393    qtest_quit(qts);
 394}
 395
 396typedef struct {
 397    bool active;
 398    uint32_t head;
 399    uint32_t sector;
 400    uint32_t cyl;
 401    uint32_t end_head;
 402    uint32_t end_sector;
 403    uint32_t end_cyl;
 404    uint32_t start_sect;
 405    uint32_t nr_sects;
 406} MBRpartitions[4];
 407
 408static MBRpartitions empty_mbr = { {false, 0, 0, 0, 0, 0, 0, 0, 0},
 409                                   {false, 0, 0, 0, 0, 0, 0, 0, 0},
 410                                   {false, 0, 0, 0, 0, 0, 0, 0, 0},
 411                                   {false, 0, 0, 0, 0, 0, 0, 0, 0} };
 412
 413static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors)
 414{
 415    const char *template = "/tmp/qtest.XXXXXX";
 416    char *raw_path = strdup(template);
 417    char *qcow2_path = strdup(template);
 418    char cmd[100 + 2 * PATH_MAX];
 419    uint8_t buf[512];
 420    int i, ret, fd, offset;
 421    uint64_t qcow2_size = sectors * 512;
 422    uint8_t status, parttype, head, sector, cyl;
 423    char *qemu_img_path;
 424    char *qemu_img_abs_path;
 425
 426    offset = 0xbe;
 427
 428    for (i = 0; i < 4; i++) {
 429        status = mbr[i].active ? 0x80 : 0x00;
 430        g_assert(mbr[i].head < 256);
 431        g_assert(mbr[i].sector < 64);
 432        g_assert(mbr[i].cyl < 1024);
 433        head = mbr[i].head;
 434        sector = mbr[i].sector + ((mbr[i].cyl & 0x300) >> 2);
 435        cyl = mbr[i].cyl & 0xff;
 436
 437        buf[offset + 0x0] = status;
 438        buf[offset + 0x1] = head;
 439        buf[offset + 0x2] = sector;
 440        buf[offset + 0x3] = cyl;
 441
 442        parttype = 0;
 443        g_assert(mbr[i].end_head < 256);
 444        g_assert(mbr[i].end_sector < 64);
 445        g_assert(mbr[i].end_cyl < 1024);
 446        head = mbr[i].end_head;
 447        sector = mbr[i].end_sector + ((mbr[i].end_cyl & 0x300) >> 2);
 448        cyl = mbr[i].end_cyl & 0xff;
 449
 450        buf[offset + 0x4] = parttype;
 451        buf[offset + 0x5] = head;
 452        buf[offset + 0x6] = sector;
 453        buf[offset + 0x7] = cyl;
 454
 455        (*(uint32_t *)&buf[offset + 0x8]) = cpu_to_le32(mbr[i].start_sect);
 456        (*(uint32_t *)&buf[offset + 0xc]) = cpu_to_le32(mbr[i].nr_sects);
 457
 458        offset += 0x10;
 459    }
 460
 461    fd = mkstemp(raw_path);
 462    g_assert(fd);
 463    close(fd);
 464
 465    fd = open(raw_path, O_WRONLY);
 466    g_assert(fd >= 0);
 467    ret = write(fd, buf, sizeof(buf));
 468    g_assert(ret == sizeof(buf));
 469    close(fd);
 470
 471    fd = mkstemp(qcow2_path);
 472    g_assert(fd);
 473    close(fd);
 474
 475    qemu_img_path = getenv("QTEST_QEMU_IMG");
 476    g_assert(qemu_img_path);
 477    qemu_img_abs_path = realpath(qemu_img_path, NULL);
 478    g_assert(qemu_img_abs_path);
 479
 480    ret = snprintf(cmd, sizeof(cmd),
 481                   "%s convert -f raw -O qcow2 %s %s > /dev/null",
 482                   qemu_img_abs_path,
 483                   raw_path, qcow2_path);
 484    g_assert((0 < ret) && (ret <= sizeof(cmd)));
 485    ret = system(cmd);
 486    g_assert(ret == 0);
 487
 488    ret = snprintf(cmd, sizeof(cmd),
 489                   "%s resize %s %" PRIu64 " > /dev/null",
 490                   qemu_img_abs_path,
 491                   qcow2_path, qcow2_size);
 492    g_assert((0 < ret) && (ret <= sizeof(cmd)));
 493    ret = system(cmd);
 494    g_assert(ret == 0);
 495
 496    free(qemu_img_abs_path);
 497
 498    unlink(raw_path);
 499    free(raw_path);
 500
 501    return qcow2_path;
 502}
 503
 504#define BIOS_GEOMETRY_MAX_SIZE 10000
 505
 506typedef struct {
 507    uint32_t c;
 508    uint32_t h;
 509    uint32_t s;
 510} CHS;
 511
 512typedef struct {
 513    const char *dev_path;
 514    CHS chs;
 515} CHSResult;
 516
 517static void read_bootdevices(QFWCFG *fw_cfg, CHSResult expected[])
 518{
 519    char *buf = g_malloc0(BIOS_GEOMETRY_MAX_SIZE);
 520    char *cur;
 521    GList *results = NULL, *cur_result;
 522    CHSResult *r;
 523    int i;
 524    int res;
 525    bool found;
 526
 527    qfw_cfg_get_file(fw_cfg, "bios-geometry", buf, BIOS_GEOMETRY_MAX_SIZE);
 528
 529    for (cur = buf; *cur; cur++) {
 530        if (*cur == '\n') {
 531            *cur = '\0';
 532        }
 533    }
 534    cur = buf;
 535
 536    while (strlen(cur)) {
 537
 538        r = g_malloc0(sizeof(*r));
 539        r->dev_path = g_malloc0(strlen(cur) + 1);
 540        res = sscanf(cur, "%s %" PRIu32 " %" PRIu32 " %" PRIu32,
 541                     (char *)r->dev_path,
 542                     &(r->chs.c), &(r->chs.h), &(r->chs.s));
 543
 544        g_assert(res == 4);
 545
 546        results = g_list_prepend(results, r);
 547
 548        cur += strlen(cur) + 1;
 549    }
 550
 551    i = 0;
 552
 553    while (expected[i].dev_path) {
 554        found = false;
 555        cur_result = results;
 556        while (cur_result) {
 557            r = cur_result->data;
 558            if (!strcmp(r->dev_path, expected[i].dev_path) &&
 559                !memcmp(&(r->chs), &(expected[i].chs), sizeof(r->chs))) {
 560                found = true;
 561                break;
 562            }
 563            cur_result = g_list_next(cur_result);
 564        }
 565        g_assert(found);
 566        g_free((char *)((CHSResult *)cur_result->data)->dev_path);
 567        g_free(cur_result->data);
 568        results = g_list_delete_link(results, cur_result);
 569        i++;
 570    }
 571
 572    g_assert(results == NULL);
 573
 574    g_free(buf);
 575}
 576
 577#define MAX_DRIVES 30
 578
 579typedef struct {
 580    char **argv;
 581    int argc;
 582    char **drives;
 583    int n_drives;
 584    int n_scsi_disks;
 585    int n_scsi_controllers;
 586    int n_virtio_disks;
 587} TestArgs;
 588
 589static TestArgs *create_args(void)
 590{
 591    TestArgs *args = g_malloc0(sizeof(*args));
 592    args->argv = g_new0(char *, ARGV_SIZE);
 593    args->argc = append_arg(args->argc, args->argv,
 594                            ARGV_SIZE, g_strdup("-nodefaults"));
 595    args->drives = g_new0(char *, MAX_DRIVES);
 596    return args;
 597}
 598
 599static void add_drive_with_mbr(TestArgs *args,
 600                               MBRpartitions mbr, uint64_t sectors)
 601{
 602    char *img_file_name;
 603    char part[300];
 604    int ret;
 605
 606    g_assert(args->n_drives < MAX_DRIVES);
 607
 608    img_file_name = create_qcow2_with_mbr(mbr, sectors);
 609
 610    args->drives[args->n_drives] = img_file_name;
 611    ret = snprintf(part, sizeof(part),
 612                   "-drive file=%s,if=none,format=qcow2,id=disk%d",
 613                   img_file_name, args->n_drives);
 614    g_assert((0 < ret) && (ret <= sizeof(part)));
 615    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
 616    args->n_drives++;
 617}
 618
 619static void add_ide_disk(TestArgs *args,
 620                         int drive_idx, int bus, int unit, int c, int h, int s)
 621{
 622    char part[300];
 623    int ret;
 624
 625    ret = snprintf(part, sizeof(part),
 626                   "-device ide-hd,drive=disk%d,bus=ide.%d,unit=%d,"
 627                   "lcyls=%d,lheads=%d,lsecs=%d",
 628                   drive_idx, bus, unit, c, h, s);
 629    g_assert((0 < ret) && (ret <= sizeof(part)));
 630    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
 631}
 632
 633static void add_scsi_controller(TestArgs *args,
 634                                const char *type,
 635                                const char *bus,
 636                                int addr)
 637{
 638    char part[300];
 639    int ret;
 640
 641    ret = snprintf(part, sizeof(part),
 642                   "-device %s,id=scsi%d,bus=%s,addr=%d",
 643                   type, args->n_scsi_controllers, bus, addr);
 644    g_assert((0 < ret) && (ret <= sizeof(part)));
 645    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
 646    args->n_scsi_controllers++;
 647}
 648
 649static void add_scsi_disk(TestArgs *args,
 650                          int drive_idx, int bus,
 651                          int channel, int scsi_id, int lun,
 652                          int c, int h, int s)
 653{
 654    char part[300];
 655    int ret;
 656
 657    ret = snprintf(part, sizeof(part),
 658                   "-device scsi-hd,id=scsi-disk%d,drive=disk%d,"
 659                   "bus=scsi%d.0,"
 660                   "channel=%d,scsi-id=%d,lun=%d,"
 661                   "lcyls=%d,lheads=%d,lsecs=%d",
 662                   args->n_scsi_disks, drive_idx, bus, channel, scsi_id, lun,
 663                   c, h, s);
 664    g_assert((0 < ret) && (ret <= sizeof(part)));
 665    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
 666    args->n_scsi_disks++;
 667}
 668
 669static void add_virtio_disk(TestArgs *args,
 670                            int drive_idx, const char *bus, int addr,
 671                            int c, int h, int s)
 672{
 673    char part[300];
 674    int ret;
 675
 676    ret = snprintf(part, sizeof(part),
 677                   "-device virtio-blk-pci,id=virtio-disk%d,"
 678                   "drive=disk%d,bus=%s,addr=%d,"
 679                   "lcyls=%d,lheads=%d,lsecs=%d",
 680                   args->n_virtio_disks, drive_idx, bus, addr, c, h, s);
 681    g_assert((0 < ret) && (ret <= sizeof(part)));
 682    args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
 683    args->n_virtio_disks++;
 684}
 685
 686static void test_override(TestArgs *args, CHSResult expected[])
 687{
 688    QTestState *qts;
 689    char *joined_args;
 690    QFWCFG *fw_cfg;
 691    int i;
 692
 693    joined_args = g_strjoinv(" ", args->argv);
 694
 695    qts = qtest_init(joined_args);
 696    fw_cfg = pc_fw_cfg_init(qts);
 697
 698    read_bootdevices(fw_cfg, expected);
 699
 700    g_free(joined_args);
 701    qtest_quit(qts);
 702
 703    g_free(fw_cfg);
 704
 705    for (i = 0; i < args->n_drives; i++) {
 706        unlink(args->drives[i]);
 707        free(args->drives[i]);
 708    }
 709    g_free(args->drives);
 710    g_strfreev(args->argv);
 711    g_free(args);
 712}
 713
 714static void test_override_ide(void)
 715{
 716    TestArgs *args = create_args();
 717    CHSResult expected[] = {
 718        {"/pci@i0cf8/ide@1,1/drive@0/disk@0", {10000, 120, 30} },
 719        {"/pci@i0cf8/ide@1,1/drive@0/disk@1", {9000, 120, 30} },
 720        {"/pci@i0cf8/ide@1,1/drive@1/disk@0", {0, 1, 1} },
 721        {"/pci@i0cf8/ide@1,1/drive@1/disk@1", {1, 0, 0} },
 722        {NULL, {0, 0, 0} }
 723    };
 724    add_drive_with_mbr(args, empty_mbr, 1);
 725    add_drive_with_mbr(args, empty_mbr, 1);
 726    add_drive_with_mbr(args, empty_mbr, 1);
 727    add_drive_with_mbr(args, empty_mbr, 1);
 728    add_ide_disk(args, 0, 0, 0, 10000, 120, 30);
 729    add_ide_disk(args, 1, 0, 1, 9000, 120, 30);
 730    add_ide_disk(args, 2, 1, 0, 0, 1, 1);
 731    add_ide_disk(args, 3, 1, 1, 1, 0, 0);
 732    test_override(args, expected);
 733}
 734
 735static void test_override_scsi(void)
 736{
 737    TestArgs *args = create_args();
 738    CHSResult expected[] = {
 739        {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
 740        {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
 741        {"/pci@i0cf8/scsi@3/channel@0/disk@2,0", {1, 0, 0} },
 742        {"/pci@i0cf8/scsi@3/channel@0/disk@3,0", {0, 1, 0} },
 743        {NULL, {0, 0, 0} }
 744    };
 745    add_drive_with_mbr(args, empty_mbr, 1);
 746    add_drive_with_mbr(args, empty_mbr, 1);
 747    add_drive_with_mbr(args, empty_mbr, 1);
 748    add_drive_with_mbr(args, empty_mbr, 1);
 749    add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
 750    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
 751    add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
 752    add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0);
 753    add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0);
 754    test_override(args, expected);
 755}
 756
 757static void test_override_scsi_2_controllers(void)
 758{
 759    TestArgs *args = create_args();
 760    CHSResult expected[] = {
 761        {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
 762        {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
 763        {"/pci@i0cf8/scsi@4/channel@0/disk@0,1", {1, 0, 0} },
 764        {"/pci@i0cf8/scsi@4/channel@0/disk@1,2", {0, 1, 0} },
 765        {NULL, {0, 0, 0} }
 766    };
 767    add_drive_with_mbr(args, empty_mbr, 1);
 768    add_drive_with_mbr(args, empty_mbr, 1);
 769    add_drive_with_mbr(args, empty_mbr, 1);
 770    add_drive_with_mbr(args, empty_mbr, 1);
 771    add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
 772    add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 4);
 773    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
 774    add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
 775    add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0);
 776    add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0);
 777    test_override(args, expected);
 778}
 779
 780static void test_override_virtio_blk(void)
 781{
 782    TestArgs *args = create_args();
 783    CHSResult expected[] = {
 784        {"/pci@i0cf8/scsi@3/disk@0,0", {10000, 120, 30} },
 785        {"/pci@i0cf8/scsi@4/disk@0,0", {9000, 120, 30} },
 786        {NULL, {0, 0, 0} }
 787    };
 788    add_drive_with_mbr(args, empty_mbr, 1);
 789    add_drive_with_mbr(args, empty_mbr, 1);
 790    add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30);
 791    add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30);
 792    test_override(args, expected);
 793}
 794
 795static void test_override_zero_chs(void)
 796{
 797    TestArgs *args = create_args();
 798    CHSResult expected[] = {
 799        {NULL, {0, 0, 0} }
 800    };
 801    add_drive_with_mbr(args, empty_mbr, 1);
 802    add_ide_disk(args, 0, 1, 1, 0, 0, 0);
 803    test_override(args, expected);
 804}
 805
 806static void test_override_scsi_hot_unplug(void)
 807{
 808    QTestState *qts;
 809    char *joined_args;
 810    QFWCFG *fw_cfg;
 811    QDict *response;
 812    int i;
 813    TestArgs *args = create_args();
 814    CHSResult expected[] = {
 815        {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} },
 816        {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
 817        {NULL, {0, 0, 0} }
 818    };
 819    CHSResult expected2[] = {
 820        {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
 821        {NULL, {0, 0, 0} }
 822    };
 823    add_drive_with_mbr(args, empty_mbr, 1);
 824    add_drive_with_mbr(args, empty_mbr, 1);
 825    add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2);
 826    add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
 827    add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20);
 828
 829    joined_args = g_strjoinv(" ", args->argv);
 830
 831    qts = qtest_init(joined_args);
 832    fw_cfg = pc_fw_cfg_init(qts);
 833
 834    read_bootdevices(fw_cfg, expected);
 835
 836    /* unplug device an restart */
 837    response = qtest_qmp(qts,
 838                         "{ 'execute': 'device_del',"
 839                         "  'arguments': {'id': 'scsi-disk0' }}");
 840    g_assert(response);
 841    g_assert(!qdict_haskey(response, "error"));
 842    qobject_unref(response);
 843    response = qtest_qmp(qts,
 844                         "{ 'execute': 'system_reset', 'arguments': { }}");
 845    g_assert(response);
 846    g_assert(!qdict_haskey(response, "error"));
 847    qobject_unref(response);
 848
 849    qtest_qmp_eventwait(qts, "RESET");
 850
 851    read_bootdevices(fw_cfg, expected2);
 852
 853    g_free(joined_args);
 854    qtest_quit(qts);
 855
 856    g_free(fw_cfg);
 857
 858    for (i = 0; i < args->n_drives; i++) {
 859        unlink(args->drives[i]);
 860        free(args->drives[i]);
 861    }
 862    g_free(args->drives);
 863    g_strfreev(args->argv);
 864    g_free(args);
 865}
 866
 867static void test_override_virtio_hot_unplug(void)
 868{
 869    QTestState *qts;
 870    char *joined_args;
 871    QFWCFG *fw_cfg;
 872    QDict *response;
 873    int i;
 874    TestArgs *args = create_args();
 875    CHSResult expected[] = {
 876        {"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} },
 877        {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
 878        {NULL, {0, 0, 0} }
 879    };
 880    CHSResult expected2[] = {
 881        {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
 882        {NULL, {0, 0, 0} }
 883    };
 884    add_drive_with_mbr(args, empty_mbr, 1);
 885    add_drive_with_mbr(args, empty_mbr, 1);
 886    add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30);
 887    add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20);
 888
 889    joined_args = g_strjoinv(" ", args->argv);
 890
 891    qts = qtest_init(joined_args);
 892    fw_cfg = pc_fw_cfg_init(qts);
 893
 894    read_bootdevices(fw_cfg, expected);
 895
 896    /* unplug device an restart */
 897    response = qtest_qmp(qts,
 898                         "{ 'execute': 'device_del',"
 899                         "  'arguments': {'id': 'virtio-disk0' }}");
 900    g_assert(response);
 901    g_assert(!qdict_haskey(response, "error"));
 902    qobject_unref(response);
 903    response = qtest_qmp(qts,
 904                         "{ 'execute': 'system_reset', 'arguments': { }}");
 905    g_assert(response);
 906    g_assert(!qdict_haskey(response, "error"));
 907    qobject_unref(response);
 908
 909    qtest_qmp_eventwait(qts, "RESET");
 910
 911    read_bootdevices(fw_cfg, expected2);
 912
 913    g_free(joined_args);
 914    qtest_quit(qts);
 915
 916    g_free(fw_cfg);
 917
 918    for (i = 0; i < args->n_drives; i++) {
 919        unlink(args->drives[i]);
 920        free(args->drives[i]);
 921    }
 922    g_free(args->drives);
 923    g_strfreev(args->argv);
 924    g_free(args);
 925}
 926
 927int main(int argc, char **argv)
 928{
 929    Backend i;
 930    int ret;
 931
 932    g_test_init(&argc, &argv, NULL);
 933
 934    for (i = 0; i < backend_last; i++) {
 935        if (img_secs[i] >= 0) {
 936            img_file_name[i] = create_test_img(img_secs[i]);
 937        } else {
 938            img_file_name[i] = NULL;
 939        }
 940    }
 941
 942    qtest_add_func("hd-geo/ide/none", test_ide_none);
 943    qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
 944    qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
 945    qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
 946    qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
 947    qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
 948    qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
 949    qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
 950    qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
 951    qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
 952    if (have_qemu_img()) {
 953        qtest_add_func("hd-geo/override/ide", test_override_ide);
 954        qtest_add_func("hd-geo/override/scsi", test_override_scsi);
 955        qtest_add_func("hd-geo/override/scsi_2_controllers",
 956                       test_override_scsi_2_controllers);
 957        qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk);
 958        qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs);
 959        qtest_add_func("hd-geo/override/scsi_hot_unplug",
 960                       test_override_scsi_hot_unplug);
 961        qtest_add_func("hd-geo/override/virtio_hot_unplug",
 962                       test_override_virtio_hot_unplug);
 963    } else {
 964        g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
 965                       "skipping hd-geo/override/* tests");
 966    }
 967
 968    ret = g_test_run();
 969
 970    for (i = 0; i < backend_last; i++) {
 971        if (img_file_name[i]) {
 972            unlink(img_file_name[i]);
 973            free(img_file_name[i]);
 974        }
 975    }
 976
 977    return ret;
 978}
 979