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" |