Commit fa879c641435bec4b79872ad14b9a90c8b7172f3
1 parent
ff4b91c2
add "serial" parameter to -drive flag (Gleb Natapov)
Windows calculates HW "uniqueness" based on a hard drive serial number among other things. The patch allows to specify drive serial number from a command line. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6214 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
44 additions
and
15 deletions
hw/ide.c
| @@ -386,6 +386,7 @@ typedef struct IDEState { | @@ -386,6 +386,7 @@ typedef struct IDEState { | ||
| 386 | PCIDevice *pci_dev; | 386 | PCIDevice *pci_dev; |
| 387 | struct BMDMAState *bmdma; | 387 | struct BMDMAState *bmdma; |
| 388 | int drive_serial; | 388 | int drive_serial; |
| 389 | + char drive_serial_str[21]; | ||
| 389 | /* ide regs */ | 390 | /* ide regs */ |
| 390 | uint8_t feature; | 391 | uint8_t feature; |
| 391 | uint8_t error; | 392 | uint8_t error; |
| @@ -531,7 +532,6 @@ static void ide_identify(IDEState *s) | @@ -531,7 +532,6 @@ static void ide_identify(IDEState *s) | ||
| 531 | { | 532 | { |
| 532 | uint16_t *p; | 533 | uint16_t *p; |
| 533 | unsigned int oldsize; | 534 | unsigned int oldsize; |
| 534 | - char buf[20]; | ||
| 535 | 535 | ||
| 536 | if (s->identify_set) { | 536 | if (s->identify_set) { |
| 537 | memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); | 537 | memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); |
| @@ -546,8 +546,7 @@ static void ide_identify(IDEState *s) | @@ -546,8 +546,7 @@ static void ide_identify(IDEState *s) | ||
| 546 | put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ | 546 | put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ |
| 547 | put_le16(p + 5, 512); /* XXX: retired, remove ? */ | 547 | put_le16(p + 5, 512); /* XXX: retired, remove ? */ |
| 548 | put_le16(p + 6, s->sectors); | 548 | put_le16(p + 6, s->sectors); |
| 549 | - snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); | ||
| 550 | - padstr((char *)(p + 10), buf, 20); /* serial number */ | 549 | + padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ |
| 551 | put_le16(p + 20, 3); /* XXX: retired, remove ? */ | 550 | put_le16(p + 20, 3); /* XXX: retired, remove ? */ |
| 552 | put_le16(p + 21, 512); /* cache size in sectors */ | 551 | put_le16(p + 21, 512); /* cache size in sectors */ |
| 553 | put_le16(p + 22, 4); /* ecc bytes */ | 552 | put_le16(p + 22, 4); /* ecc bytes */ |
| @@ -601,7 +600,6 @@ static void ide_identify(IDEState *s) | @@ -601,7 +600,6 @@ static void ide_identify(IDEState *s) | ||
| 601 | static void ide_atapi_identify(IDEState *s) | 600 | static void ide_atapi_identify(IDEState *s) |
| 602 | { | 601 | { |
| 603 | uint16_t *p; | 602 | uint16_t *p; |
| 604 | - char buf[20]; | ||
| 605 | 603 | ||
| 606 | if (s->identify_set) { | 604 | if (s->identify_set) { |
| 607 | memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); | 605 | memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); |
| @@ -612,8 +610,7 @@ static void ide_atapi_identify(IDEState *s) | @@ -612,8 +610,7 @@ static void ide_atapi_identify(IDEState *s) | ||
| 612 | p = (uint16_t *)s->io_buffer; | 610 | p = (uint16_t *)s->io_buffer; |
| 613 | /* Removable CDROM, 50us response, 12 byte packets */ | 611 | /* Removable CDROM, 50us response, 12 byte packets */ |
| 614 | put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); | 612 | put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); |
| 615 | - snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); | ||
| 616 | - padstr((char *)(p + 10), buf, 20); /* serial number */ | 613 | + padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ |
| 617 | put_le16(p + 20, 3); /* buffer type */ | 614 | put_le16(p + 20, 3); /* buffer type */ |
| 618 | put_le16(p + 21, 512); /* cache size in sectors */ | 615 | put_le16(p + 21, 512); /* cache size in sectors */ |
| 619 | put_le16(p + 22, 4); /* ecc bytes */ | 616 | put_le16(p + 22, 4); /* ecc bytes */ |
| @@ -652,7 +649,6 @@ static void ide_cfata_identify(IDEState *s) | @@ -652,7 +649,6 @@ static void ide_cfata_identify(IDEState *s) | ||
| 652 | { | 649 | { |
| 653 | uint16_t *p; | 650 | uint16_t *p; |
| 654 | uint32_t cur_sec; | 651 | uint32_t cur_sec; |
| 655 | - char buf[20]; | ||
| 656 | 652 | ||
| 657 | p = (uint16_t *) s->identify_data; | 653 | p = (uint16_t *) s->identify_data; |
| 658 | if (s->identify_set) | 654 | if (s->identify_set) |
| @@ -668,8 +664,7 @@ static void ide_cfata_identify(IDEState *s) | @@ -668,8 +664,7 @@ static void ide_cfata_identify(IDEState *s) | ||
| 668 | put_le16(p + 6, s->sectors); /* Default sectors per track */ | 664 | put_le16(p + 6, s->sectors); /* Default sectors per track */ |
| 669 | put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ | 665 | put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ |
| 670 | put_le16(p + 8, s->nb_sectors); /* Sectors per card */ | 666 | put_le16(p + 8, s->nb_sectors); /* Sectors per card */ |
| 671 | - snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); | ||
| 672 | - padstr((char *)(p + 10), buf, 20); /* Serial number in ASCII */ | 667 | + padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ |
| 673 | put_le16(p + 22, 0x0004); /* ECC bytes */ | 668 | put_le16(p + 22, 0x0004); /* ECC bytes */ |
| 674 | padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ | 669 | padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ |
| 675 | padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ | 670 | padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ |
| @@ -2714,6 +2709,11 @@ static void ide_init2(IDEState *ide_state, | @@ -2714,6 +2709,11 @@ static void ide_init2(IDEState *ide_state, | ||
| 2714 | } | 2709 | } |
| 2715 | } | 2710 | } |
| 2716 | s->drive_serial = drive_serial++; | 2711 | s->drive_serial = drive_serial++; |
| 2712 | + strncpy(s->drive_serial_str, drive_get_serial(s->bs), | ||
| 2713 | + sizeof(s->drive_serial_str)); | ||
| 2714 | + if (strlen(s->drive_serial_str) == 0) | ||
| 2715 | + snprintf(s->drive_serial_str, sizeof(s->drive_serial_str), | ||
| 2716 | + "QM%05d", s->drive_serial); | ||
| 2717 | s->irq = irq; | 2717 | s->irq = irq; |
| 2718 | s->sector_write_timer = qemu_new_timer(vm_clock, | 2718 | s->sector_write_timer = qemu_new_timer(vm_clock, |
| 2719 | ide_sector_write_timer_cb, s); | 2719 | ide_sector_write_timer_cb, s); |
hw/scsi-disk.c
| @@ -13,6 +13,8 @@ | @@ -13,6 +13,8 @@ | ||
| 13 | * the host adapter emulator. | 13 | * the host adapter emulator. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | +#include <qemu-common.h> | ||
| 17 | +#include <sysemu.h> | ||
| 16 | //#define DEBUG_SCSI | 18 | //#define DEBUG_SCSI |
| 17 | 19 | ||
| 18 | #ifdef DEBUG_SCSI | 20 | #ifdef DEBUG_SCSI |
| @@ -68,6 +70,7 @@ struct SCSIDeviceState | @@ -68,6 +70,7 @@ struct SCSIDeviceState | ||
| 68 | or from the AIO completion routines. */ | 70 | or from the AIO completion routines. */ |
| 69 | scsi_completionfn completion; | 71 | scsi_completionfn completion; |
| 70 | void *opaque; | 72 | void *opaque; |
| 73 | + char drive_serial_str[21]; | ||
| 71 | }; | 74 | }; |
| 72 | 75 | ||
| 73 | /* Global pool of SCSIRequest structures. */ | 76 | /* Global pool of SCSIRequest structures. */ |
| @@ -408,6 +411,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, | @@ -408,6 +411,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, | ||
| 408 | break; | 411 | break; |
| 409 | case 0x80: | 412 | case 0x80: |
| 410 | { | 413 | { |
| 414 | + int l; | ||
| 415 | + | ||
| 411 | /* Device serial number, optional */ | 416 | /* Device serial number, optional */ |
| 412 | if (len < 4) { | 417 | if (len < 4) { |
| 413 | BADF("Error: EVPD[Serial number] Inquiry buffer " | 418 | BADF("Error: EVPD[Serial number] Inquiry buffer " |
| @@ -416,6 +421,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, | @@ -416,6 +421,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, | ||
| 416 | } | 421 | } |
| 417 | 422 | ||
| 418 | DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); | 423 | DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); |
| 424 | + l = MIN(len, strlen(s->drive_serial_str)); | ||
| 419 | 425 | ||
| 420 | r->buf_len = 0; | 426 | r->buf_len = 0; |
| 421 | 427 | ||
| @@ -428,9 +434,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, | @@ -428,9 +434,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, | ||
| 428 | 434 | ||
| 429 | outbuf[r->buf_len++] = 0x80; // this page | 435 | outbuf[r->buf_len++] = 0x80; // this page |
| 430 | outbuf[r->buf_len++] = 0x00; | 436 | outbuf[r->buf_len++] = 0x00; |
| 431 | - outbuf[r->buf_len++] = 0x01; // 1 byte data follow | ||
| 432 | - | ||
| 433 | - outbuf[r->buf_len++] = '0'; // 1 byte data follow | 437 | + outbuf[r->buf_len++] = l; |
| 438 | + memcpy(&outbuf[r->buf_len], s->drive_serial_str, l); | ||
| 439 | + r->buf_len += l; | ||
| 434 | } | 440 | } |
| 435 | 441 | ||
| 436 | break; | 442 | break; |
| @@ -812,7 +818,10 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, | @@ -812,7 +818,10 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, | ||
| 812 | } else { | 818 | } else { |
| 813 | s->cluster_size = 1; | 819 | s->cluster_size = 1; |
| 814 | } | 820 | } |
| 815 | - | 821 | + strncpy(s->drive_serial_str, drive_get_serial(s->bdrv), |
| 822 | + sizeof(s->drive_serial_str)); | ||
| 823 | + if (strlen(s->drive_serial_str) == 0) | ||
| 824 | + strcpy(s->drive_serial_str, "0"); | ||
| 816 | d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); | 825 | d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); |
| 817 | d->state = s; | 826 | d->state = s; |
| 818 | d->destroy = scsi_destroy; | 827 | d->destroy = scsi_destroy; |
qemu-doc.texi
| @@ -274,6 +274,8 @@ These options have the same definition as they have in @option{-hdachs}. | @@ -274,6 +274,8 @@ These options have the same definition as they have in @option{-hdachs}. | ||
| 274 | Specify which disk @var{format} will be used rather than detecting | 274 | Specify which disk @var{format} will be used rather than detecting |
| 275 | the format. Can be used to specifiy format=raw to avoid interpreting | 275 | the format. Can be used to specifiy format=raw to avoid interpreting |
| 276 | an untrusted format header. | 276 | an untrusted format header. |
| 277 | +@item serial=@var{serial} | ||
| 278 | +This option specifies the serial number to assign to the device. | ||
| 277 | @end table | 279 | @end table |
| 278 | 280 | ||
| 279 | By default, writethrough caching is used for all block device. This means that | 281 | By default, writethrough caching is used for all block device. This means that |
sysemu.h
| @@ -131,6 +131,7 @@ typedef struct DriveInfo { | @@ -131,6 +131,7 @@ typedef struct DriveInfo { | ||
| 131 | BlockInterfaceType type; | 131 | BlockInterfaceType type; |
| 132 | int bus; | 132 | int bus; |
| 133 | int unit; | 133 | int unit; |
| 134 | + char serial[21]; | ||
| 134 | } DriveInfo; | 135 | } DriveInfo; |
| 135 | 136 | ||
| 136 | #define MAX_IDE_DEVS 2 | 137 | #define MAX_IDE_DEVS 2 |
| @@ -142,6 +143,7 @@ extern DriveInfo drives_table[MAX_DRIVES+1]; | @@ -142,6 +143,7 @@ extern DriveInfo drives_table[MAX_DRIVES+1]; | ||
| 142 | 143 | ||
| 143 | extern int drive_get_index(BlockInterfaceType type, int bus, int unit); | 144 | extern int drive_get_index(BlockInterfaceType type, int bus, int unit); |
| 144 | extern int drive_get_max_bus(BlockInterfaceType type); | 145 | extern int drive_get_max_bus(BlockInterfaceType type); |
| 146 | +extern const char *drive_get_serial(BlockDriverState *bdrv); | ||
| 145 | 147 | ||
| 146 | /* serial ports */ | 148 | /* serial ports */ |
| 147 | 149 |
vl.c
| @@ -2196,6 +2196,17 @@ int drive_get_max_bus(BlockInterfaceType type) | @@ -2196,6 +2196,17 @@ int drive_get_max_bus(BlockInterfaceType type) | ||
| 2196 | return max_bus; | 2196 | return max_bus; |
| 2197 | } | 2197 | } |
| 2198 | 2198 | ||
| 2199 | +const char *drive_get_serial(BlockDriverState *bdrv) | ||
| 2200 | +{ | ||
| 2201 | + int index; | ||
| 2202 | + | ||
| 2203 | + for (index = 0; index < nb_drives; index++) | ||
| 2204 | + if (drives_table[index].bdrv == bdrv) | ||
| 2205 | + return drives_table[index].serial; | ||
| 2206 | + | ||
| 2207 | + return "\0"; | ||
| 2208 | +} | ||
| 2209 | + | ||
| 2199 | static void bdrv_format_print(void *opaque, const char *name) | 2210 | static void bdrv_format_print(void *opaque, const char *name) |
| 2200 | { | 2211 | { |
| 2201 | fprintf(stderr, " %s", name); | 2212 | fprintf(stderr, " %s", name); |
| @@ -2207,6 +2218,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2207,6 +2218,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2207 | char buf[128]; | 2218 | char buf[128]; |
| 2208 | char file[1024]; | 2219 | char file[1024]; |
| 2209 | char devname[128]; | 2220 | char devname[128]; |
| 2221 | + char serial[21]; | ||
| 2210 | const char *mediastr = ""; | 2222 | const char *mediastr = ""; |
| 2211 | BlockInterfaceType type; | 2223 | BlockInterfaceType type; |
| 2212 | enum { MEDIA_DISK, MEDIA_CDROM } media; | 2224 | enum { MEDIA_DISK, MEDIA_CDROM } media; |
| @@ -2222,7 +2234,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2222,7 +2234,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2222 | static const char * const params[] = { "bus", "unit", "if", "index", | 2234 | static const char * const params[] = { "bus", "unit", "if", "index", |
| 2223 | "cyls", "heads", "secs", "trans", | 2235 | "cyls", "heads", "secs", "trans", |
| 2224 | "media", "snapshot", "file", | 2236 | "media", "snapshot", "file", |
| 2225 | - "cache", "format", NULL }; | 2237 | + "cache", "format", "serial", NULL }; |
| 2226 | 2238 | ||
| 2227 | if (check_params(buf, sizeof(buf), params, str) < 0) { | 2239 | if (check_params(buf, sizeof(buf), params, str) < 0) { |
| 2228 | fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", | 2240 | fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", |
| @@ -2409,6 +2421,9 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2409,6 +2421,9 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2409 | else | 2421 | else |
| 2410 | pstrcpy(file, sizeof(file), arg->file); | 2422 | pstrcpy(file, sizeof(file), arg->file); |
| 2411 | 2423 | ||
| 2424 | + if (!get_param_value(serial, sizeof(serial), "serial", str)) | ||
| 2425 | + memset(serial, 0, sizeof(serial)); | ||
| 2426 | + | ||
| 2412 | /* compute bus and unit according index */ | 2427 | /* compute bus and unit according index */ |
| 2413 | 2428 | ||
| 2414 | if (index != -1) { | 2429 | if (index != -1) { |
| @@ -2472,6 +2487,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2472,6 +2487,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2472 | drives_table[nb_drives].type = type; | 2487 | drives_table[nb_drives].type = type; |
| 2473 | drives_table[nb_drives].bus = bus_id; | 2488 | drives_table[nb_drives].bus = bus_id; |
| 2474 | drives_table[nb_drives].unit = unit_id; | 2489 | drives_table[nb_drives].unit = unit_id; |
| 2490 | + strncpy(drives_table[nb_drives].serial, serial, sizeof(serial)); | ||
| 2475 | nb_drives++; | 2491 | nb_drives++; |
| 2476 | 2492 | ||
| 2477 | switch(type) { | 2493 | switch(type) { |
| @@ -3826,7 +3842,7 @@ static void help(int exitcode) | @@ -3826,7 +3842,7 @@ static void help(int exitcode) | ||
| 3826 | "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" | 3842 | "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" |
| 3827 | "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n" | 3843 | "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n" |
| 3828 | " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n" | 3844 | " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n" |
| 3829 | - " [,cache=writethrough|writeback|none][,format=f]\n" | 3845 | + " [,cache=writethrough|writeback|none][,format=f][,serial=s]\n" |
| 3830 | " use 'file' as a drive image\n" | 3846 | " use 'file' as a drive image\n" |
| 3831 | "-mtdblock file use 'file' as on-board Flash memory image\n" | 3847 | "-mtdblock file use 'file' as on-board Flash memory image\n" |
| 3832 | "-sd file use 'file' as SecureDigital card image\n" | 3848 | "-sd file use 'file' as SecureDigital card image\n" |