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 = strdup("/tmp/qtest.XXXXXX"); 31 int fd, ret; 32 33 fd = mkstemp(template); 34 g_assert(fd >= 0); 35 ret = ftruncate(fd, (off_t)secs * 512); 36 close(fd); 37 38 if (ret) { 39 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 const char *template = "/tmp/qtest.XXXXXX"; 426 char *raw_path = strdup(template); 427 char *qcow2_path = strdup(template); 428 char cmd[100 + 2 * PATH_MAX]; 429 uint8_t buf[512] = {}; 430 int i, ret, fd, offset; 431 uint64_t qcow2_size = sectors * 512; 432 uint8_t status, parttype, head, sector, cyl; 433 char *qemu_img_path; 434 char *qemu_img_abs_path; 435 436 offset = 0xbe; 437 438 for (i = 0; i < 4; i++) { 439 status = mbr[i].active ? 0x80 : 0x00; 440 g_assert(mbr[i].head < 256); 441 g_assert(mbr[i].sector < 64); 442 g_assert(mbr[i].cyl < 1024); 443 head = mbr[i].head; 444 sector = mbr[i].sector + ((mbr[i].cyl & 0x300) >> 2); 445 cyl = mbr[i].cyl & 0xff; 446 447 buf[offset + 0x0] = status; 448 buf[offset + 0x1] = head; 449 buf[offset + 0x2] = sector; 450 buf[offset + 0x3] = cyl; 451 452 parttype = 0; 453 g_assert(mbr[i].end_head < 256); 454 g_assert(mbr[i].end_sector < 64); 455 g_assert(mbr[i].end_cyl < 1024); 456 head = mbr[i].end_head; 457 sector = mbr[i].end_sector + ((mbr[i].end_cyl & 0x300) >> 2); 458 cyl = mbr[i].end_cyl & 0xff; 459 460 buf[offset + 0x4] = parttype; 461 buf[offset + 0x5] = head; 462 buf[offset + 0x6] = sector; 463 buf[offset + 0x7] = cyl; 464 465 stl_le_p(&buf[offset + 0x8], mbr[i].start_sect); 466 stl_le_p(&buf[offset + 0xc], mbr[i].nr_sects); 467 468 offset += 0x10; 469 } 470 471 fd = mkstemp(raw_path); 472 g_assert(fd >= 0); 473 close(fd); 474 475 fd = open(raw_path, O_WRONLY); 476 g_assert(fd >= 0); 477 ret = write(fd, buf, sizeof(buf)); 478 g_assert(ret == sizeof(buf)); 479 close(fd); 480 481 fd = mkstemp(qcow2_path); 482 g_assert(fd >= 0); 483 close(fd); 484 485 qemu_img_path = getenv("QTEST_QEMU_IMG"); 486 g_assert(qemu_img_path); 487 qemu_img_abs_path = realpath(qemu_img_path, NULL); 488 g_assert(qemu_img_abs_path); 489 490 ret = snprintf(cmd, sizeof(cmd), 491 "%s convert -f raw -O qcow2 %s %s > /dev/null", 492 qemu_img_abs_path, 493 raw_path, qcow2_path); 494 g_assert((0 < ret) && (ret <= sizeof(cmd))); 495 ret = system(cmd); 496 g_assert(ret == 0); 497 498 ret = snprintf(cmd, sizeof(cmd), 499 "%s resize %s %" PRIu64 " > /dev/null", 500 qemu_img_abs_path, 501 qcow2_path, qcow2_size); 502 g_assert((0 < ret) && (ret <= sizeof(cmd))); 503 ret = system(cmd); 504 g_assert(ret == 0); 505 506 free(qemu_img_abs_path); 507 508 unlink(raw_path); 509 free(raw_path); 510 511 return qcow2_path; 512 } 513 514 #define BIOS_GEOMETRY_MAX_SIZE 10000 515 516 typedef struct { 517 uint32_t c; 518 uint32_t h; 519 uint32_t s; 520 } CHS; 521 522 typedef struct { 523 const char *dev_path; 524 CHS chs; 525 } CHSResult; 526 527 static void read_bootdevices(QFWCFG *fw_cfg, CHSResult expected[]) 528 { 529 char *buf = g_malloc0(BIOS_GEOMETRY_MAX_SIZE); 530 char *cur; 531 GList *results = NULL, *cur_result; 532 CHSResult *r; 533 int i; 534 int res; 535 bool found; 536 537 qfw_cfg_get_file(fw_cfg, "bios-geometry", buf, BIOS_GEOMETRY_MAX_SIZE); 538 539 for (cur = buf; *cur; cur++) { 540 if (*cur == '\n') { 541 *cur = '\0'; 542 } 543 } 544 cur = buf; 545 546 while (strlen(cur)) { 547 548 r = g_malloc0(sizeof(*r)); 549 r->dev_path = g_malloc0(strlen(cur) + 1); 550 res = sscanf(cur, "%s %" PRIu32 " %" PRIu32 " %" PRIu32, 551 (char *)r->dev_path, 552 &(r->chs.c), &(r->chs.h), &(r->chs.s)); 553 554 g_assert(res == 4); 555 556 results = g_list_prepend(results, r); 557 558 cur += strlen(cur) + 1; 559 } 560 561 i = 0; 562 563 while (expected[i].dev_path) { 564 found = false; 565 cur_result = results; 566 while (cur_result) { 567 r = cur_result->data; 568 if (!strcmp(r->dev_path, expected[i].dev_path) && 569 !memcmp(&(r->chs), &(expected[i].chs), sizeof(r->chs))) { 570 found = true; 571 break; 572 } 573 cur_result = g_list_next(cur_result); 574 } 575 g_assert(found); 576 g_free((char *)((CHSResult *)cur_result->data)->dev_path); 577 g_free(cur_result->data); 578 results = g_list_delete_link(results, cur_result); 579 i++; 580 } 581 582 g_assert(results == NULL); 583 584 g_free(buf); 585 } 586 587 #define MAX_DRIVES 30 588 589 typedef struct { 590 char **argv; 591 int argc; 592 char **drives; 593 int n_drives; 594 int n_scsi_disks; 595 int n_scsi_controllers; 596 int n_virtio_disks; 597 } TestArgs; 598 599 static TestArgs *create_args(void) 600 { 601 TestArgs *args = g_malloc0(sizeof(*args)); 602 args->argv = g_new0(char *, ARGV_SIZE); 603 args->argc = append_arg(args->argc, args->argv, 604 ARGV_SIZE, g_strdup("-nodefaults")); 605 args->drives = g_new0(char *, MAX_DRIVES); 606 return args; 607 } 608 609 static void add_drive_with_mbr(TestArgs *args, 610 MBRpartitions mbr, uint64_t sectors) 611 { 612 char *img_file_name; 613 char part[300]; 614 int ret; 615 616 g_assert(args->n_drives < MAX_DRIVES); 617 618 img_file_name = create_qcow2_with_mbr(mbr, sectors); 619 620 args->drives[args->n_drives] = img_file_name; 621 ret = snprintf(part, sizeof(part), 622 "-drive file=%s,if=none,format=qcow2,id=disk%d", 623 img_file_name, args->n_drives); 624 g_assert((0 < ret) && (ret <= sizeof(part))); 625 args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part)); 626 args->n_drives++; 627 } 628 629 static void add_ide_disk(TestArgs *args, 630 int drive_idx, int bus, int unit, int c, int h, int s) 631 { 632 char part[300]; 633 int ret; 634 635 ret = snprintf(part, sizeof(part), 636 "-device ide-hd,drive=disk%d,bus=ide.%d,unit=%d," 637 "lcyls=%d,lheads=%d,lsecs=%d", 638 drive_idx, bus, unit, c, h, s); 639 g_assert((0 < ret) && (ret <= sizeof(part))); 640 args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part)); 641 } 642 643 static void add_scsi_controller(TestArgs *args, 644 const char *type, 645 const char *bus, 646 int addr) 647 { 648 char part[300]; 649 int ret; 650 651 ret = snprintf(part, sizeof(part), 652 "-device %s,id=scsi%d,bus=%s,addr=%d", 653 type, args->n_scsi_controllers, bus, addr); 654 g_assert((0 < ret) && (ret <= sizeof(part))); 655 args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part)); 656 args->n_scsi_controllers++; 657 } 658 659 static void add_scsi_disk(TestArgs *args, 660 int drive_idx, int bus, 661 int channel, int scsi_id, int lun, 662 int c, int h, int s) 663 { 664 char part[300]; 665 int ret; 666 667 ret = snprintf(part, sizeof(part), 668 "-device scsi-hd,id=scsi-disk%d,drive=disk%d," 669 "bus=scsi%d.0," 670 "channel=%d,scsi-id=%d,lun=%d," 671 "lcyls=%d,lheads=%d,lsecs=%d", 672 args->n_scsi_disks, drive_idx, bus, channel, scsi_id, lun, 673 c, h, s); 674 g_assert((0 < ret) && (ret <= sizeof(part))); 675 args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part)); 676 args->n_scsi_disks++; 677 } 678 679 static void add_virtio_disk(TestArgs *args, 680 int drive_idx, const char *bus, int addr, 681 int c, int h, int s) 682 { 683 char part[300]; 684 int ret; 685 686 ret = snprintf(part, sizeof(part), 687 "-device virtio-blk-pci,id=virtio-disk%d," 688 "drive=disk%d,bus=%s,addr=%d," 689 "lcyls=%d,lheads=%d,lsecs=%d", 690 args->n_virtio_disks, drive_idx, bus, addr, c, h, s); 691 g_assert((0 < ret) && (ret <= sizeof(part))); 692 args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part)); 693 args->n_virtio_disks++; 694 } 695 696 static void test_override(TestArgs *args, CHSResult expected[]) 697 { 698 QTestState *qts; 699 char *joined_args; 700 QFWCFG *fw_cfg; 701 int i; 702 703 joined_args = g_strjoinv(" ", args->argv); 704 705 qts = qtest_initf("-machine pc %s", joined_args); 706 fw_cfg = pc_fw_cfg_init(qts); 707 708 read_bootdevices(fw_cfg, expected); 709 710 g_free(joined_args); 711 qtest_quit(qts); 712 713 g_free(fw_cfg); 714 715 for (i = 0; i < args->n_drives; i++) { 716 unlink(args->drives[i]); 717 free(args->drives[i]); 718 } 719 g_free(args->drives); 720 g_strfreev(args->argv); 721 g_free(args); 722 } 723 724 static void test_override_ide(void) 725 { 726 TestArgs *args = create_args(); 727 CHSResult expected[] = { 728 {"/pci@i0cf8/ide@1,1/drive@0/disk@0", {10000, 120, 30} }, 729 {"/pci@i0cf8/ide@1,1/drive@0/disk@1", {9000, 120, 30} }, 730 {"/pci@i0cf8/ide@1,1/drive@1/disk@0", {0, 1, 1} }, 731 {"/pci@i0cf8/ide@1,1/drive@1/disk@1", {1, 0, 0} }, 732 {NULL, {0, 0, 0} } 733 }; 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_drive_with_mbr(args, empty_mbr, 1); 738 add_ide_disk(args, 0, 0, 0, 10000, 120, 30); 739 add_ide_disk(args, 1, 0, 1, 9000, 120, 30); 740 add_ide_disk(args, 2, 1, 0, 0, 1, 1); 741 add_ide_disk(args, 3, 1, 1, 1, 0, 0); 742 test_override(args, expected); 743 } 744 745 static void test_override_scsi(void) 746 { 747 TestArgs *args = create_args(); 748 CHSResult expected[] = { 749 {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} }, 750 {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} }, 751 {"/pci@i0cf8/scsi@3/channel@0/disk@2,0", {1, 0, 0} }, 752 {"/pci@i0cf8/scsi@3/channel@0/disk@3,0", {0, 1, 0} }, 753 {NULL, {0, 0, 0} } 754 }; 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_drive_with_mbr(args, empty_mbr, 1); 759 add_scsi_controller(args, "lsi53c895a", "pci.0", 3); 760 add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); 761 add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30); 762 add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0); 763 add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0); 764 test_override(args, expected); 765 } 766 767 static void test_override_scsi_2_controllers(void) 768 { 769 TestArgs *args = create_args(); 770 CHSResult expected[] = { 771 {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} }, 772 {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} }, 773 {"/pci@i0cf8/scsi@4/channel@0/disk@0,1", {1, 0, 0} }, 774 {"/pci@i0cf8/scsi@4/channel@0/disk@1,2", {0, 1, 0} }, 775 {NULL, {0, 0, 0} } 776 }; 777 add_drive_with_mbr(args, empty_mbr, 1); 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_scsi_controller(args, "lsi53c895a", "pci.0", 3); 782 add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 4); 783 add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); 784 add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30); 785 add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0); 786 add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0); 787 test_override(args, expected); 788 } 789 790 static void test_override_virtio_blk(void) 791 { 792 TestArgs *args = create_args(); 793 CHSResult expected[] = { 794 {"/pci@i0cf8/scsi@3/disk@0,0", {10000, 120, 30} }, 795 {"/pci@i0cf8/scsi@4/disk@0,0", {9000, 120, 30} }, 796 {NULL, {0, 0, 0} } 797 }; 798 add_drive_with_mbr(args, empty_mbr, 1); 799 add_drive_with_mbr(args, empty_mbr, 1); 800 add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30); 801 add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30); 802 test_override(args, expected); 803 } 804 805 static void test_override_zero_chs(void) 806 { 807 TestArgs *args = create_args(); 808 CHSResult expected[] = { 809 {NULL, {0, 0, 0} } 810 }; 811 add_drive_with_mbr(args, empty_mbr, 1); 812 add_ide_disk(args, 0, 1, 1, 0, 0, 0); 813 test_override(args, expected); 814 } 815 816 static void test_override_scsi_hot_unplug(void) 817 { 818 QTestState *qts; 819 char *joined_args; 820 QFWCFG *fw_cfg; 821 QDict *response; 822 int i; 823 TestArgs *args = create_args(); 824 CHSResult expected[] = { 825 {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} }, 826 {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} }, 827 {NULL, {0, 0, 0} } 828 }; 829 CHSResult expected2[] = { 830 {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} }, 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_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2); 836 add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30); 837 add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20); 838 839 joined_args = g_strjoinv(" ", args->argv); 840 841 qts = qtest_initf("-machine pc %s", joined_args); 842 fw_cfg = pc_fw_cfg_init(qts); 843 844 read_bootdevices(fw_cfg, expected); 845 846 /* unplug device an restart */ 847 response = qtest_qmp(qts, 848 "{ 'execute': 'device_del'," 849 " 'arguments': {'id': 'scsi-disk0' }}"); 850 g_assert(response); 851 g_assert(!qdict_haskey(response, "error")); 852 qobject_unref(response); 853 response = qtest_qmp(qts, 854 "{ 'execute': 'system_reset', 'arguments': { }}"); 855 g_assert(response); 856 g_assert(!qdict_haskey(response, "error")); 857 qobject_unref(response); 858 859 qtest_qmp_eventwait(qts, "RESET"); 860 861 read_bootdevices(fw_cfg, expected2); 862 863 g_free(joined_args); 864 qtest_quit(qts); 865 866 g_free(fw_cfg); 867 868 for (i = 0; i < args->n_drives; i++) { 869 unlink(args->drives[i]); 870 free(args->drives[i]); 871 } 872 g_free(args->drives); 873 g_strfreev(args->argv); 874 g_free(args); 875 } 876 877 static void test_override_virtio_hot_unplug(void) 878 { 879 QTestState *qts; 880 char *joined_args; 881 QFWCFG *fw_cfg; 882 QDict *response; 883 int i; 884 TestArgs *args = create_args(); 885 CHSResult expected[] = { 886 {"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} }, 887 {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} }, 888 {NULL, {0, 0, 0} } 889 }; 890 CHSResult expected2[] = { 891 {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} }, 892 {NULL, {0, 0, 0} } 893 }; 894 add_drive_with_mbr(args, empty_mbr, 1); 895 add_drive_with_mbr(args, empty_mbr, 1); 896 add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30); 897 add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20); 898 899 joined_args = g_strjoinv(" ", args->argv); 900 901 qts = qtest_initf("-machine pc %s", joined_args); 902 fw_cfg = pc_fw_cfg_init(qts); 903 904 read_bootdevices(fw_cfg, expected); 905 906 /* unplug device an restart */ 907 response = qtest_qmp(qts, 908 "{ 'execute': 'device_del'," 909 " 'arguments': {'id': 'virtio-disk0' }}"); 910 g_assert(response); 911 g_assert(!qdict_haskey(response, "error")); 912 qobject_unref(response); 913 response = qtest_qmp(qts, 914 "{ 'execute': 'system_reset', 'arguments': { }}"); 915 g_assert(response); 916 g_assert(!qdict_haskey(response, "error")); 917 qobject_unref(response); 918 919 qtest_qmp_eventwait(qts, "RESET"); 920 921 read_bootdevices(fw_cfg, expected2); 922 923 g_free(joined_args); 924 qtest_quit(qts); 925 926 g_free(fw_cfg); 927 928 for (i = 0; i < args->n_drives; i++) { 929 unlink(args->drives[i]); 930 free(args->drives[i]); 931 } 932 g_free(args->drives); 933 g_strfreev(args->argv); 934 g_free(args); 935 } 936 937 int main(int argc, char **argv) 938 { 939 Backend i; 940 int ret; 941 942 g_test_init(&argc, &argv, NULL); 943 944 for (i = 0; i < backend_last; i++) { 945 if (img_secs[i] >= 0) { 946 img_file_name[i] = create_test_img(img_secs[i]); 947 if (!img_file_name[i]) { 948 g_test_message("Could not create test images."); 949 goto test_add_done; 950 } 951 } else { 952 img_file_name[i] = NULL; 953 } 954 } 955 956 qtest_add_func("hd-geo/ide/none", test_ide_none); 957 qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank); 958 qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba); 959 qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs); 960 qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0); 961 qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank); 962 qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba); 963 qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs); 964 qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs); 965 qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst); 966 if (have_qemu_img()) { 967 qtest_add_func("hd-geo/override/ide", test_override_ide); 968 if (qtest_has_device("lsi53c895a")) { 969 qtest_add_func("hd-geo/override/scsi", test_override_scsi); 970 qtest_add_func("hd-geo/override/scsi_2_controllers", 971 test_override_scsi_2_controllers); 972 } 973 qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk); 974 qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs); 975 qtest_add_func("hd-geo/override/scsi_hot_unplug", 976 test_override_scsi_hot_unplug); 977 qtest_add_func("hd-geo/override/virtio_hot_unplug", 978 test_override_virtio_hot_unplug); 979 } else { 980 g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; " 981 "skipping hd-geo/override/* tests"); 982 } 983 984 test_add_done: 985 ret = g_test_run(); 986 987 for (i = 0; i < backend_last; i++) { 988 if (img_file_name[i]) { 989 unlink(img_file_name[i]); 990 free(img_file_name[i]); 991 } 992 } 993 994 return ret; 995 } 996