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