Index: xen-unstable/tools/ioemu/block.c =================================================================== --- xen-unstable.orig/tools/ioemu/block.c +++ xen-unstable/tools/ioemu/block.c @@ -332,6 +332,8 @@ int bdrv_open2(BlockDriverState *bs, con goto fail; } + shdev_set_media_instance(bs); + bs->inserted = 1; /* call the change callback */ @@ -356,6 +358,7 @@ void bdrv_close(BlockDriverState *bs) bs->opaque = NULL; bs->drv = NULL; bs->inserted = 0; + bs->media_instance = 0; /* call the change callback */ if (bs->change_cb) @@ -601,6 +604,15 @@ BlockDriverState *bdrv_find(const char * return NULL; } +BlockDriverState *bdrv_find_bs(int (*it)(BlockDriverState *, void *), void *opaque) +{ + BlockDriverState *bs; + + for (bs = bdrv_first; bs != NULL && !it(bs, opaque); bs = bs->next); + + return( bs ); +} + void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) { BlockDriverState *bs; Index: xen-unstable/tools/ioemu/block_int.h =================================================================== --- xen-unstable.orig/tools/ioemu/block_int.h +++ xen-unstable/tools/ioemu/block_int.h @@ -51,6 +51,8 @@ struct BlockDriverState { int removable; /* if true, the media can be removed */ int locked; /* if true, the media cannot temporarily be ejected */ int encrypted; /* if true, the media is encrypted */ + int media_instance; + int shdev_el; /* event callback when inserting/removing */ void (*change_cb)(void *opaque); void *change_opaque; Index: xen-unstable/tools/ioemu/hw/ide.c =================================================================== --- xen-unstable.orig/tools/ioemu/hw/ide.c +++ xen-unstable/tools/ioemu/hw/ide.c @@ -23,6 +23,9 @@ */ #include "vl.h" #include +#include +#include +#include /* debug IDE devices */ //#define DEBUG_IDE @@ -278,6 +281,7 @@ #define ASC_ILLEGAL_OPCODE 0x20 #define ASC_LOGICAL_BLOCK_OOR 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIA_CHANGED 0x28 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 @@ -294,6 +298,7 @@ typedef void EndTransferFunc(struct IDES typedef struct IDEState { /* ide config */ int is_cdrom; + int media_changed; int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; @@ -1141,6 +1146,51 @@ static void ide_atapi_cmd_read(IDEState } } +static int cd_media_inserted(IDEState *s) +{ + int inserted = 0; + + if (s->bs->removable) { + int h = open(s->bs->filename, O_NONBLOCK, O_RDONLY); + + if (h >= 0) { + struct stat statbuf; + if (fstat(h, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { + inserted = 1; + } else { + int status; + sg_io_hdr_t io_hdr; + unsigned char test_unit_ready_cmd[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; + unsigned char inqBuff[2]; + unsigned char sb[32]; + + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = 6; + io_hdr.mx_sb_len = sizeof(sb); + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.dxfer_len = 0; + io_hdr.dxferp = inqBuff; + io_hdr.sbp = (unsigned char *) sb; + io_hdr.timeout = 2000; + io_hdr.cmdp = test_unit_ready_cmd; + + sb[0] = 0xFF; + + status = ioctl(h, SG_IO, (void *)&io_hdr); + + if ( (status == 0) && (sb[0] == 0xFF)) + inserted = 1; + } + + close(h); + } + } else + inserted = 1; + + return inserted; +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1162,11 +1212,25 @@ static void ide_atapi_cmd(IDEState *s) switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: if (bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_ok(s); + if (s->media_changed) { + s->media_changed = 0; + ide_atapi_cmd_error(s, SENSE_UNIT_ATTENTION, ASC_MEDIA_CHANGED); + } + else { + if (!cd_media_inserted(s) || shdev_media_check(s->bs)) { + bdrv_close(s->bs); + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + } + else + ide_atapi_cmd_ok(s); + } } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - xenstore_check_new_media_present(1000); +// xenstore_check_new_media_present(1000); + if (cd_media_inserted(s)) { + do_insert_request(); + } } break; case GPCMD_MODE_SENSE_10: @@ -1298,6 +1362,13 @@ static void ide_atapi_cmd(IDEState *s) ASC_MEDIUM_NOT_PRESENT); break; } + + if (shdev_media_check(s->bs)) { + bdrv_close(s->bs); + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + break; + } + nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; lba = ube32_to_cpu(packet + 2); if (nb_sectors == 0) { @@ -1355,7 +1426,7 @@ static void ide_atapi_cmd(IDEState *s) if (eject && !start) { /* eject the disk */ - bdrv_close(s->bs); + do_eject(1, s->bs->device_name); } ide_atapi_cmd_ok(s); } @@ -1382,6 +1453,13 @@ static void ide_atapi_cmd(IDEState *s) ASC_MEDIUM_NOT_PRESENT); break; } + + if (shdev_media_check(s->bs)) { + bdrv_close(s->bs); + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + break; + } + max_len = ube16_to_cpu(packet + 7); format = packet[9] >> 6; msf = (packet[1] >> 1) & 1; @@ -1454,9 +1532,9 @@ static void cdrom_change_cb(void *opaque IDEState *s = opaque; int64_t nb_sectors; - /* XXX: send interrupt too */ bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; + s->media_changed = 1; } static void ide_cmd_lba48_transform(IDEState *s, int lba48) @@ -1756,6 +1834,7 @@ static void ide_ioport_write(void *opaqu ide_set_signature(s); s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; + s->media_changed = 0; break; case WIN_PACKETCMD: if (!s->is_cdrom) Index: xen-unstable/tools/ioemu/monitor.c =================================================================== --- xen-unstable.orig/tools/ioemu/monitor.c +++ xen-unstable/tools/ioemu/monitor.c @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" #include +#include #include "block_int.h" //#define DEBUG @@ -340,7 +341,44 @@ void do_eject(int force, const char *fil term_printf("device not found\n"); return; } - eject_device(bs, force); + + if (eject_device(bs, force) == 0) { + char cmd[strlen(bs->filename) + 16]; + shdev_eject_notice(bs); + sprintf(cmd, "eject %s", bs->filename); + system(cmd); + } +} + +void do_insert(const char *device) +{ + BlockDriverState *bs; + + bs = bdrv_find(device); + + if (!bs) { + term_printf("'%s' not found\n", device); + return; + } + + if (!bs->removable) { + term_printf("'%s' is not removable\n", device); + return; + } + + if (bs->inserted) { + term_printf("'%s' is already inserted\n", device); + return; + } + + bdrv_open(bs, bs->filename, 0); +} + +static int find_bs_by_type(BlockDriverState *bs, void *opaque) +{ + int *type = (int *)opaque; + + return( (bs->type == *type) ); } void do_change(const char *device, const char *filename) @@ -356,7 +394,8 @@ void do_change(const char *device, const } if (eject_device(bs, 0) < 0) return; - bdrv_open(bs, filename, 0); + pstrcpy(bs->filename, sizeof(bs->filename), filename); + do_insert(bs->device_name); if (bdrv_is_encrypted(bs)) { term_printf("%s is encrypted.\n", device); for(i = 0; i < 3; i++) { @@ -368,6 +407,19 @@ void do_change(const char *device, const } } +void do_insert_request() +{ + BlockDriverState *bs = NULL; + int type = BDRV_TYPE_CDROM; + + bs = bdrv_find_bs(find_bs_by_type, &type); + + if (bs) + do_change(bs->device_name, bs->filename); + else + term_printf("Did not find cdrom bs.\n"); +} + static void do_screen_dump(const char *filename) { vga_hw_screen_dump(filename); Index: xen-unstable/tools/ioemu/sdl.c =================================================================== --- xen-unstable.orig/tools/ioemu/sdl.c +++ xen-unstable/tools/ioemu/sdl.c @@ -544,7 +544,7 @@ void sdl_display_init(DisplayState *ds, #ifndef _WIN32 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */ signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); +// signal(SIGQUIT, SIG_DFL); #endif ds->dpy_update = sdl_update; Index: xen-unstable/tools/ioemu/vl.h =================================================================== --- xen-unstable.orig/tools/ioemu/vl.h +++ xen-unstable/tools/ioemu/vl.h @@ -180,6 +180,8 @@ extern int smp_cpus; #define BIOS_SIZE ((256 + 64) * 1024) #endif +#define CDROM_DISK_POSITION 2 + /* keyboard/mouse support */ #define MOUSE_EVENT_LBUTTON 0x01 @@ -561,6 +563,7 @@ void bdrv_set_change_cb(BlockDriverState void (*change_cb)(void *opaque), void *opaque); void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); void bdrv_info(void); +BlockDriverState *bdrv_find_bs(int (*it)(BlockDriverState *bs, void *opaque), void *opaque); BlockDriverState *bdrv_find(const char *name); void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); int bdrv_is_encrypted(BlockDriverState *bs); @@ -1180,6 +1183,15 @@ pflash_t *pflash_register (target_ulong #endif /* defined(QEMU_TOOL) */ +/* shdev.h */ + +int shdev_init(void); +int shdev_report_device(BlockDriverState *bs, const char *name); +void shdev_set_media_instance(BlockDriverState *bs); +void shdev_eject_notice(BlockDriverState *bs); +inline int shdev_media_check(BlockDriverState *bs); +void do_info_shdev(void); + /* monitor.c */ void monitor_init(CharDriverState *hd, int show_banner); void term_puts(const char *str); @@ -1189,6 +1201,7 @@ void term_flush(void); void term_print_help(void); void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size); +void do_insert_request(void); void do_eject(int force, const char *filename); void do_change(const char *device, const char *filename); Index: xen-unstable/tools/ioemu/shdev.c =================================================================== --- /dev/null +++ xen-unstable/tools/ioemu/shdev.c @@ -0,0 +1,138 @@ +/* + * Managment for Devices Shared Across Guests + * + * Copyright (c) 2006 Novell, Inc. + * + * - Author: Ross Maxfield (ross.maxfield@novell.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" +#include "block_int.h" +#include + +#define MAX_SHARED_DEVS 4 +#define SHDEV_NAME_LEN 128 +#define SHARED_DEVS_SIGNATURE "ShRdDeVs" +#define QEMU_KEY_PATH "/etc/xen" + +typedef struct SharedDevice { + char name[SHDEV_NAME_LEN]; + int media_instance; +} SharedDevice; + +typedef struct SharedDevices { + char signature[sizeof(SHARED_DEVS_SIGNATURE)]; + SharedDevice device[MAX_SHARED_DEVS]; +} SharedDevices; + +SharedDevices *shdevs; + +int shdev_init() +{ + key_t shm_key; + int shm_id; + + /* Alloc/Get shared device memory */ + shm_key = ftok(QEMU_KEY_PATH, 'X'); + + if (((shm_id = shmget(shm_key, + sizeof(SharedDevices), + IPC_CREAT|IPC_EXCL|0660)) != -1) + && ((shdevs = shmat(shm_id, 0, 0)) != (void *)-1)) { + memcpy(&shdevs->signature, SHARED_DEVS_SIGNATURE, + sizeof(SHARED_DEVS_SIGNATURE)); + } + else + if (errno == EEXIST) + { + if (((shm_id = shmget(shm_key, sizeof(SharedDevices), 0)) == -1) + || ((shdevs = shmat(shm_id, 0, 0)) == (void *)-1) + || (memcmp(shdevs->signature, SHARED_DEVS_SIGNATURE, + sizeof(SHARED_DEVS_SIGNATURE)) != 0)) { + shdevs = NULL; + fprintf(stderr, "Could not setup support for shared devices.\n"); + return 1; + } + } + + return 0; +} + +void shdev_set_media_instance(BlockDriverState *bs) +{ + bs->media_instance = shdevs->device[bs->shdev_el].media_instance; +} + +void shdev_eject_notice(BlockDriverState *bs) +{ + shdevs->device[bs->shdev_el].media_instance++; +} + +inline int shdev_media_check(BlockDriverState *bs) +{ + return(!(bs->media_instance == shdevs->device[bs->shdev_el].media_instance)); +} + +int shdev_report_device(BlockDriverState *bs, const char *name) +{ + int i; + + for (i = 0; + (i < MAX_SHARED_DEVS) && strcmp(shdevs->device[i].name, name); + i++); + + if (i == MAX_SHARED_DEVS) { + for (i = 0; + (i < MAX_SHARED_DEVS) && (shdevs->device[i].name[0] != '\0'); + i++); + + if (i < MAX_SHARED_DEVS) { + pstrcpy(shdevs->device[i].name, SHDEV_NAME_LEN, name); + shdevs->device[i].media_instance = 0; + } + else { + fprintf(stderr, "%s exceeds maximum of %d shared devices.\n", + name, MAX_SHARED_DEVS ); + return -1; + } + } + + bs->media_instance = shdevs->device[i].media_instance; + bs->shdev_el = i; + + return 0; +} + +void do_info_shdev(void) +{ + int i; + + /* Can this device be made availble to this domain? */ + for (i = 0; i < MAX_SHARED_DEVS; i++) { + if (shdevs->device[i].name[0] != '\0') { + term_printf("'%s' [%d]\n", + shdevs->device[i].name, + shdevs->device[i].media_instance); + } + } +} + + Index: xen-unstable/tools/ioemu/Makefile.target =================================================================== --- xen-unstable.orig/tools/ioemu/Makefile.target +++ xen-unstable/tools/ioemu/Makefile.target @@ -307,7 +307,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o +VL_OBJS=vl.o osdep.o block.o shdev.o readline.o monitor.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o Index: xen-unstable/tools/ioemu/vl.c =================================================================== --- xen-unstable.orig/tools/ioemu/vl.c +++ xen-unstable/tools/ioemu/vl.c @@ -5843,6 +5843,8 @@ int main(int argc, char **argv) int usb_devices_index; unsigned long nr_pages, tmp_nr_pages, shared_page_nr; xen_pfn_t *page_array; + int dev_type; + char buf[64]; extern void *shared_page; extern void *buffered_io_page; @@ -5073,7 +5073,7 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif - int i, has_cdrom; + int i, has_cdrom = 0; int snapshot, linux_boot; CPUState *env; const char *initrd_filename; @@ -5094,6 +5094,8 @@ int main(int argc, char **argv) const char *loadvm = NULL; unsigned long nr_pages, extra_pages, ram_pages, *page_array; xc_dominfo_t info; + int dev_type; + char buf[64]; extern void *shared_page; extern void *shared_vram; extern void *buffered_io_page; @@ -5122,7 +5124,6 @@ int main(int argc, char **argv) vncconnect=NULL; kernel_filename = NULL; kernel_cmdline = ""; - has_cdrom = 1; cyls = heads = secs = 0; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); @@ -5185,12 +5186,6 @@ int main(int argc, char **argv) case QEMU_OPTION_initrd: initrd_filename = optarg; break; - case QEMU_OPTION_hda: - hd_filename[0] = optarg; - break; - case QEMU_OPTION_hdb: - hd_filename[1] = optarg; - break; case QEMU_OPTION_snapshot: snapshot = 1; break; @@ -5263,15 +5258,56 @@ int main(int argc, char **argv) } } break; + case QEMU_OPTION_hda: + if (hd_filename[0]) { + fprintf(stderr, + "qemu: virtual device 'hd%c' already defined as %s\n", + 'a', + hd_filename[0] ); + break; + } + hd_filename[0] = optarg; + break; + case QEMU_OPTION_hdb: + if (hd_filename[1]) { + fprintf(stderr, + "qemu: virtual device 'hd%c' already defined as %s\n", + 'b', + hd_filename[1] ); + break; + } + hd_filename[1] = optarg; + break; case QEMU_OPTION_hdc: + if (hd_filename[2]) { + fprintf(stderr, + "qemu: virtual device 'hd%c' already defined as %s\n", + 'c', + hd_filename[2] ); + break; + } hd_filename[2] = optarg; - has_cdrom = 0; break; case QEMU_OPTION_hdd: + if (hd_filename[3]) { + fprintf(stderr, + "qemu: virtual device 'hd%c' already defined as %s\n", + 'd', + hd_filename[3] ); + break; + } hd_filename[3] = optarg; break; case QEMU_OPTION_cdrom: - hd_filename[2] = optarg; + if (hd_filename[CDROM_DISK_POSITION]) { + fprintf(stderr, + "qemu: virtual device 'hd%c' for cdrom " + "is already defined as %s\n", + 'a' + CDROM_DISK_POSITION, + hd_filename[CDROM_DISK_POSITION] ); + break; + } + hd_filename[CDROM_DISK_POSITION] = optarg; has_cdrom = 1; break; case QEMU_OPTION_boot: @@ -5487,7 +5523,7 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); if ( !linux_boot && hd_filename[0] == '\0' && - hd_filename[2] == '\0' && fd_filename[0] == '\0' ) + hd_filename[CDROM_DISK_POSITION] == '\0' && fd_filename[0] == '\0' ) help(); /* boot to cd by default if no hard disk */ @@ -5668,59 +5704,55 @@ int main(int argc, char **argv) fprintf(logfile, "shared page at pfn:%lx, mfn: %lx\n", (nr_pages-1), (page_array[nr_pages - 1])); - /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - if (has_cdrom) { - int fd; - if ( (fd = open(hd_filename[2], O_RDONLY | O_BINARY)) < 0) { - hd_filename[2]=NULL; - bs_table[2]=NULL; - fprintf(logfile, "Could not open CD %s.\n", hd_filename[i]); - } - else { - close(fd); - bs_table[2] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[2], BDRV_TYPE_CDROM); - } - } + + shdev_init(); /* open the virtual block devices */ for(i = 0; i < MAX_DISKS; i++) { if (hd_filename[i]) { - if (!bs_table[i]) { - char buf[64]; + if ((i == CDROM_DISK_POSITION) && has_cdrom) { + snprintf(buf, sizeof(buf), "cdrom"); + dev_type = BDRV_TYPE_CDROM; + } + else { snprintf(buf, sizeof(buf), "hd%c", i + 'a'); - bs_table[i] = bdrv_new(buf); + dev_type = BDRV_TYPE_HD; } + + bs_table[i] = bdrv_new(buf); + + bdrv_set_type_hint(bs_table[i], dev_type); + + if (bs_table[i]->removable) + shdev_report_device(bs_table[i], hd_filename[i]); + if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) { + if (bs_table[i]->removable) + continue; + fprintf(stderr, "qemu: could not open hard disk image '%s'\n", hd_filename[i]); exit(1); } + if (i == 0 && cyls != 0) bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); } } - /* we always create at least one floppy disk */ - fd_table[0] = bdrv_new("fda"); - bdrv_set_type_hint(fd_table[0], BDRV_TYPE_FLOPPY); - for(i = 0; i < MAX_FD; i++) { if (fd_filename[i]) { if (!fd_table[i]) { - char buf[64]; snprintf(buf, sizeof(buf), "fd%c", i + 'a'); fd_table[i] = bdrv_new(buf); bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY); + shdev_report_device(fd_table[i], fd_filename[i]); } - if (fd_filename[i] != '\0') { - if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) { - fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", + + if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) + fprintf(stderr, "qemu: could not open floppy disk '%s'\n", fd_filename[i]); - exit(1); - } - } } }