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