qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

hd-geo-test.c (33478B)


      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 
     28 static 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 
     46 typedef struct {
     47     int cyls, heads, secs, trans;
     48 } CHST;
     49 
     50 typedef enum {
     51     mbr_blank, mbr_lba, mbr_chs,
     52     mbr_last
     53 } MBRcontents;
     54 
     55 typedef enum {
     56     /* order is relevant */
     57     backend_small, backend_large, backend_empty,
     58     backend_last
     59 } Backend;
     60 
     61 static const int img_secs[backend_last] = {
     62     [backend_small] = 61440,
     63     [backend_large] = 8388608,
     64     [backend_empty] = -1,
     65 };
     66 
     67 static 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 
     80 static char *img_file_name[backend_last];
     81 
     82 static const CHST *cur_ide[4];
     83 
     84 static bool is_hd(const CHST *expected_chst)
     85 {
     86     return expected_chst && expected_chst->cyls;
     87 }
     88 
     89 static 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 
     99 static 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 
    109 static 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 
    116 static 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 
    137 static 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 
    143 static 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 
    149 static 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 
    162 static 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 
    170 static 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 
    178 static 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 
    191 static 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 
    219 static 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  */
    254 static 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 
    269 static 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  */
    295 static 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  */
    303 static 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  */
    311 static 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  */
    319 static 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  */
    327 static 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  */
    335 static void test_ide_device_mbr_chs(void)
    336 {
    337     test_ide_mbr(true, mbr_chs);
    338 }
    339 
    340 static 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  */
    368 static 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  */
    376 static 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  */
    384 static 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 
    406 typedef 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 
    418 static 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 
    423 static 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 
    514 typedef struct {
    515     uint32_t c;
    516     uint32_t h;
    517     uint32_t s;
    518 } CHS;
    519 
    520 typedef struct {
    521     const char *dev_path;
    522     CHS chs;
    523 } CHSResult;
    524 
    525 static 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 
    587 typedef 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 
    597 static 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 
    607 static 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 
    627 static 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 
    641 static 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 
    657 static 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 
    677 static 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 
    694 static 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 
    723 static 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 
    744 static 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 
    765 static 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 
    787 static 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 
    798 static 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 
    823 static 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 
    846 static 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 
    861 static 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 
    877 static 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 
    888 static 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 
    899 static 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 
    942 static 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 
    966 static 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 
   1002 static 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 
   1025 static 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 
   1060 int 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             qtest_add_func("hd-geo/override/scsi_2_controllers",
   1094                            test_override_scsi_2_controllers);
   1095         }
   1096         qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk);
   1097         qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs);
   1098         qtest_add_func("hd-geo/override/scsi_hot_unplug",
   1099                        test_override_scsi_hot_unplug);
   1100         qtest_add_func("hd-geo/override/virtio_hot_unplug",
   1101                        test_override_virtio_hot_unplug);
   1102 
   1103         if (qtest_has_machine("q35")) {
   1104             qtest_add_func("hd-geo/override/sata", test_override_sata);
   1105             qtest_add_func("hd-geo/override/virtio_blk_q35",
   1106                            test_override_virtio_blk_q35);
   1107             qtest_add_func("hd-geo/override/zero_chs_q35",
   1108                            test_override_zero_chs_q35);
   1109             if (qtest_has_device("lsi53c895a")) {
   1110                 qtest_add_func("hd-geo/override/scsi_q35",
   1111                                test_override_scsi_q35);
   1112             }
   1113             qtest_add_func("hd-geo/override/scsi_hot_unplug_q35",
   1114                            test_override_scsi_hot_unplug_q35);
   1115             qtest_add_func("hd-geo/override/virtio_hot_unplug_q35",
   1116                            test_override_virtio_hot_unplug_q35);
   1117         }
   1118     } else {
   1119         g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
   1120                        "skipping hd-geo/override/* tests");
   1121     }
   1122 
   1123 test_add_done:
   1124     ret = g_test_run();
   1125 
   1126     for (i = 0; i < backend_last; i++) {
   1127         if (img_file_name[i]) {
   1128             unlink(img_file_name[i]);
   1129             g_free(img_file_name[i]);
   1130         }
   1131     }
   1132 
   1133     return ret;
   1134 }