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