diff -r 3ed325fa395b tools/ioemu/block.c --- a/tools/ioemu/block.c Fri May 26 13:53:49 2006 +0100 +++ b/tools/ioemu/block.c Fri May 26 12:27:16 2006 -0600 @@ -147,6 +147,7 @@ int bdrv_open2(BlockDriverState *bs, con } bs->inserted = 1; + shdev_set_media_instance(bs); /* call the change callback */ if (bs->change_cb) @@ -170,6 +171,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) @@ -387,7 +389,7 @@ void bdrv_iterate_format(void (*it)(void } } -BlockDriverState *bdrv_find(const char *name) +BlockDriverState *bdrv_find_by_device(const char *name) { BlockDriverState *bs; @@ -396,6 +398,15 @@ BlockDriverState *bdrv_find(const char * return bs; } 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) diff -r 3ed325fa395b tools/ioemu/block_int.h --- a/tools/ioemu/block_int.h Fri May 26 13:53:49 2006 +0100 +++ b/tools/ioemu/block_int.h Fri May 26 12:27:16 2006 -0600 @@ -24,36 +24,22 @@ #ifndef BLOCK_INT_H #define BLOCK_INT_H -struct BlockDriver { - const char *format_name; - int instance_size; - int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); - int (*bdrv_open)(BlockDriverState *bs, const char *filename); - int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); - int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); - void (*bdrv_close)(BlockDriverState *bs); - int (*bdrv_create)(const char *filename, int64_t total_sectors, - const char *backing_file, int flags); - int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, int *pnum); - int (*bdrv_set_key)(BlockDriverState *bs, const char *key); - struct BlockDriver *next; -}; +struct BlockDriver; -struct BlockDriverState { +typedef struct BlockDriverState { int64_t total_sectors; int read_only; /* if true, the media is read only */ int inserted; /* if true, the media is present */ 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; - BlockDriver *drv; + struct BlockDriver *drv; void *opaque; int boot_sector_enabled; @@ -63,15 +49,34 @@ struct BlockDriverState { char backing_file[1024]; /* if non zero, the image is a diff of this file image */ int is_temporary; - - BlockDriverState *backing_hd; - + + struct BlockDriverState *backing_hd; + /* NOTE: the following infos are only hints for real hardware drivers. They are not used by the block driver */ int cyls, heads, secs; int type; char device_name[32]; - BlockDriverState *next; -}; + struct BlockDriverState *next; +} BlockDriverState; + +typedef struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_open)(BlockDriverState *bs, const char *filename); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_close)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, int64_t total_sectors, + const char *backing_file, int flags); + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + struct BlockDriver *next; +} BlockDriver; + #endif /* BLOCK_INT_H */ diff -r 3ed325fa395b tools/ioemu/hw/ide.c --- a/tools/ioemu/hw/ide.c Fri May 26 13:53:49 2006 +0100 +++ b/tools/ioemu/hw/ide.c Fri May 26 12:27:16 2006 -0600 @@ -278,6 +278,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 +295,7 @@ typedef struct IDEState { typedef struct IDEState { /* ide config */ int is_cdrom; + int media_changed; int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; @@ -1132,11 +1134,34 @@ static int cdrom_read_toc_raw(IDEState * return len; } +static int cd_media_inserted(IDEState *s) +{ + int h, x = 0; + + if (s->bs->removable) { + h = open(s->bs->filename, O_NONBLOCK, O_RDONLY); + + if (h >= 0) { + x = fcntl(h, F_GETFL); + x &= ~O_NONBLOCK; + fcntl(h, F_SETFL, x); + + x = read(h, &x, sizeof(x)); + close(h); + } + } + else + x = sizeof( x ); + + return((x == sizeof(x))); +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; uint8_t *buf; int max_len; + packet = s->io_buffer; buf = s->io_buffer; @@ -1150,13 +1175,28 @@ static void ide_atapi_cmd(IDEState *s) printf("\n"); } #endif + 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); + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + + if (cd_media_inserted(s)) { + do_insert_request(); + } } break; case GPCMD_MODE_SENSE_10: @@ -1288,6 +1328,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) { @@ -1345,7 +1392,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); } @@ -1372,6 +1419,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; @@ -1444,9 +1498,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_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -1631,6 +1685,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) diff -r 3ed325fa395b tools/ioemu/monitor.c --- a/tools/ioemu/monitor.c Fri May 26 13:53:49 2006 +0100 +++ b/tools/ioemu/monitor.c Fri May 26 12:27:16 2006 -0600 @@ -1,8 +1,8 @@ /* * QEMU monitor - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * 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 @@ -23,6 +23,7 @@ */ #include "vl.h" #include +#include //#define DEBUG //#define DEBUG_COMPLETION @@ -33,7 +34,7 @@ /* * Supported types: - * + * * 'F' filename * 'B' block device name * 's' string (accept optional quote) @@ -66,7 +67,7 @@ void term_flush(void) { if (term_outbuf_index > 0) { if(monitor_hd) - qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); + qemu_chr_write(monitor_hd, (const uint8_t *)term_outbuf, term_outbuf_index); else fwrite(term_outbuf, term_outbuf_index, 1, stderr); term_outbuf_index = 0; @@ -240,7 +241,7 @@ static const KeyDef key_defs[] = { static const KeyDef key_defs[] = { { 0x2a, "shift" }, { 0x36, "shift_r" }, - + { 0x38, "alt" }, { 0xb8, "alt_r" }, { 0x1d, "ctrl" }, @@ -293,7 +294,7 @@ static const KeyDef key_defs[] = { { 0x30, "b" }, { 0x31, "n" }, { 0x32, "m" }, - + { 0x39, "spc" }, { 0x3a, "caps_lock" }, { 0x3b, "f1" }, @@ -348,7 +349,7 @@ static void do_send_key(const char *stri uint8_t keycodes[16]; const char *p; int nb_keycodes, keycode, i; - + nb_keycodes = 0; p = string; while (*p != '\0') { @@ -387,7 +388,7 @@ static void do_send_key(const char *stri } -static int eject_device(BlockDriverState *bs, int force) +static int eject_logical_device(BlockDriverState *bs, int force) { if (bdrv_is_inserted(bs)) { if (!force) { @@ -405,23 +406,57 @@ static int eject_device(BlockDriverState return 0; } -static void do_eject(int force, const char *filename) +void do_eject(int force, const char *device) { char cmd[1024]; BlockDriverState *bs; - bs = bdrv_find(filename); + bs = bdrv_find_by_device(device); + if (!bs) { - term_printf("device not found\n"); + term_printf("'%s' not found\n", device); return; } - eject_device(bs, force); - sprintf(cmd, "eject %s", filename); - system(cmd); - -} - -static void do_change(const char *device, const char *filename) + + if (eject_logical_device(bs, force) == 0) { + shdev_eject_notice(bs); + sprintf(cmd, "eject %s", bs->filename); + system(cmd); + } +} + +void do_insert(const char *device) +{ + BlockDriverState *bs; + + bs = bdrv_find_by_device(device); + + if (!bs) { + term_printf("'%s' not found\n", device); + return; + } + + if (!bs->removable) { + term_printf("'%s' 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) ); +} + +static void do_change_source(const char *device, const char *filename) { BlockDriverState *bs; #if 0 @@ -429,14 +464,18 @@ static void do_change(const char *device char password[256]; #endif - bs = bdrv_find(device); + bs = bdrv_find_by_device(device); + if (!bs) { term_printf("device not found\n"); return; } - if (eject_device(bs, 0) < 0) + + if (eject_logical_device(bs, 0) < 0) return; - bdrv_open(bs, filename, 0); + + do_insert(bs->device_name); + #if 0 if (bdrv_is_encrypted(bs)) { term_printf("%s is encrypted.\n", device); @@ -448,6 +487,20 @@ static void do_change(const char *device } } #endif +} + +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_source(bs->device_name, bs->filename); + } + else + term_printf("Did not find cdrom bs.\n"); } static void do_screen_dump(const char *filename) @@ -482,17 +535,19 @@ static term_cmd_t term_cmds[] = { "", "quit the emulator" }, { "eject", "-fB", do_eject, "[-f] device", "eject a removable media (use -f to force it)" }, - { "change", "BF", do_change, - "device filename", "change a removable media" }, + { "insert", "B", do_insert, + "device", "notifies qemu of inserted removable media." }, + { "change", "BF", do_change_source, + "device filename", "change source for virtual removable-media device." }, { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, { "log", "s", do_log, diff -r 3ed325fa395b tools/ioemu/vl.h --- a/tools/ioemu/vl.h Fri May 26 13:53:49 2006 +0100 +++ b/tools/ioemu/vl.h Fri May 26 12:27:16 2006 -0600 @@ -37,6 +37,7 @@ #include #include #include +#include #include "audio/audio.h" #include "xenctrl.h" #include "xs.h" @@ -84,6 +85,8 @@ static inline char *realpath(const char #endif /* vl.c */ +#define CDROM_DISK_POSITION 2 + uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); @@ -374,9 +377,6 @@ void port_e9_init(void); void port_e9_init(void); /* block.c */ -typedef struct BlockDriverState BlockDriverState; -typedef struct BlockDriver BlockDriver; - extern BlockDriver bdrv_raw; extern BlockDriver bdrv_cow; extern BlockDriver bdrv_qcow; @@ -421,7 +421,8 @@ 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(const char *name); +BlockDriverState *bdrv_find_bs(int (*it)(BlockDriverState *bs, void *opaque), void *opaque); +BlockDriverState *bdrv_find_by_device(const char *name); void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); int bdrv_is_encrypted(BlockDriverState *bs); int bdrv_set_key(BlockDriverState *bs, const char *key); @@ -797,6 +798,15 @@ int cuda_init(openpic_t *openpic, int ir #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); @@ -804,6 +814,9 @@ void term_printf(const char *fmt, ...) _ void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void term_flush(void); void term_print_help(void); +void do_insert_request(void); +void do_eject(int force, const char *device); + /* readline.c */ typedef void ReadLineFunc(void *opaque, const char *str); diff -r 3ed325fa395b tools/ioemu/shdev.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/tools/ioemu/shdev.c Fri May 26 12:36:54 2006 -0600 @@ -0,0 +1,137 @@ +/* + * 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 + +#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); + } + } +} + +