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