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