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