diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | QMP/README | 6 | ||||
-rw-r--r-- | QMP/qmp-events.txt | 21 | ||||
-rw-r--r-- | QMP/qmp-spec.txt | 52 | ||||
-rw-r--r-- | block-migration.c | 235 | ||||
-rw-r--r-- | block.c | 69 | ||||
-rw-r--r-- | block.h | 7 | ||||
-rw-r--r-- | block/curl.c | 4 | ||||
-rw-r--r-- | block/qcow2-cluster.c | 12 | ||||
-rw-r--r-- | block/qcow2.h | 6 | ||||
-rw-r--r-- | block/vvfat.c | 10 | ||||
-rw-r--r-- | block_int.h | 28 | ||||
-rwxr-xr-x | configure | 9 | ||||
-rw-r--r-- | cpu-all.h | 2 | ||||
-rw-r--r-- | cpu-common.h | 19 | ||||
-rw-r--r-- | cpu-defs.h | 3 | ||||
-rw-r--r-- | exec.c | 116 | ||||
-rw-r--r-- | hw/ide/core.c | 18 | ||||
-rw-r--r-- | hw/ide/internal.h | 7 | ||||
-rw-r--r-- | hw/ide/qdev.c | 7 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 1 | ||||
-rw-r--r-- | hw/r2d.c | 9 | ||||
-rw-r--r-- | hw/s390-virtio-bus.c | 4 | ||||
-rw-r--r-- | hw/s390-virtio-bus.h | 2 | ||||
-rw-r--r-- | hw/scsi-disk.c | 97 | ||||
-rw-r--r-- | hw/scsi-generic.c | 24 | ||||
-rw-r--r-- | hw/scsi.h | 3 | ||||
-rw-r--r-- | hw/sh7750.c | 7 | ||||
-rw-r--r-- | hw/usb-msd.c | 12 | ||||
-rw-r--r-- | hw/usb-serial.c | 28 | ||||
-rw-r--r-- | hw/usb-uhci.c | 67 | ||||
-rw-r--r-- | hw/virtio-blk.c | 77 | ||||
-rw-r--r-- | hw/virtio-blk.h | 12 | ||||
-rw-r--r-- | hw/virtio-net.c | 10 | ||||
-rw-r--r-- | hw/virtio-pci.c | 11 | ||||
-rw-r--r-- | hw/virtio.h | 3 | ||||
-rw-r--r-- | hw/vmport.c | 3 | ||||
-rw-r--r-- | json-lexer.c | 16 | ||||
-rw-r--r-- | json-parser.c | 3 | ||||
-rw-r--r-- | kvm-all.c | 355 | ||||
-rw-r--r-- | kvm.h | 9 | ||||
-rw-r--r-- | migration.c | 3 | ||||
-rw-r--r-- | monitor.c | 68 | ||||
-rw-r--r-- | monitor.h | 1 | ||||
-rw-r--r-- | net.c | 2 | ||||
-rw-r--r-- | osdep.c | 7 | ||||
-rw-r--r-- | qemu-char.c | 3 | ||||
-rw-r--r-- | qemu-doc.texi | 256 | ||||
-rw-r--r-- | qemu-img.c | 29 | ||||
-rw-r--r-- | qemu-monitor.hx | 76 | ||||
-rw-r--r-- | qemu-options.hx | 153 | ||||
-rw-r--r-- | qemu-sockets.c | 8 | ||||
-rw-r--r-- | qemu-tech.texi | 10 | ||||
-rw-r--r-- | qemu-timer.h | 1 | ||||
-rw-r--r-- | qjson.c | 5 | ||||
-rw-r--r-- | slirp/misc.c | 2 | ||||
-rw-r--r-- | target-i386/kvm.c | 11 | ||||
-rw-r--r-- | target-sh4/cpu.h | 25 | ||||
-rw-r--r-- | target-sh4/helper.c | 114 | ||||
-rw-r--r-- | target-sh4/translate.c | 54 | ||||
-rw-r--r-- | tcg/mips/tcg-target.c | 137 | ||||
-rw-r--r-- | tcg/tcg-op.h | 58 | ||||
-rw-r--r-- | vl.c | 42 | ||||
-rw-r--r-- | vnc.c | 74 | ||||
-rw-r--r-- | vnc.h | 7 |
66 files changed, 1805 insertions, 747 deletions
diff --git a/.gitignore b/.gitignore index d7d2146c07..dfc8e5b133 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ qemu-monitor.texi *.fn *.ky *.log +*.pdf *.pg *.toc *.tp @@ -22,7 +22,7 @@ Makefile: ; configure: ; .PHONY: all clean cscope distclean dvi html info install install-doc \ - recurse-all speed tar tarbin test build-all + pdf recurse-all speed tar tarbin test build-all $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) @@ -160,7 +160,7 @@ distclean: clean rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi rm -f config-all-devices.mak rm -f roms/seabios/config.mak roms/vgabios/config.mak - rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr} + rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pdf,pg,toc,tp,vr} for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \ rm -rf $$d || exit 1 ; \ done @@ -224,14 +224,18 @@ cscope: cscope -b # documentation +TEXIFLAG=$(if $(V),,--quiet) +%.dvi: %.texi + $(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<," GEN $@") + %.html: %.texi $(call quiet-command,texi2html -I=. -monolithic -number $<," GEN $@") %.info: %.texi $(call quiet-command,makeinfo -I . $< -o $@," GEN $@") -%.dvi: %.texi - $(call quiet-command,texi2dvi -I . $<," GEN $@") +%.pdf: %.texi + $(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<," GEN $@") qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@") @@ -260,13 +264,14 @@ qemu-nbd.8: qemu-nbd.texi pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \ " GEN $@") -info: qemu-doc.info qemu-tech.info - dvi: qemu-doc.dvi qemu-tech.dvi - html: qemu-doc.html qemu-tech.html +info: qemu-doc.info qemu-tech.info +pdf: qemu-doc.pdf qemu-tech.pdf -qemu-doc.dvi qemu-doc.html qemu-doc.info: qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-monitor.texi qemu-img-cmds.texi +qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \ + qemu-img.texi qemu-nbd.texi qemu-options.texi \ + qemu-monitor.texi qemu-img-cmds.texi VERSION ?= $(shell cat VERSION) FILE = qemu-$(VERSION) diff --git a/QMP/README b/QMP/README index 09e7053753..9334c25510 100644 --- a/QMP/README +++ b/QMP/README @@ -52,9 +52,11 @@ $ telnet localhost 4444 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. -{"QMP": {"capabilities": []}} +{"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}} +{ "execute": "qmp_capabilities" } +{"return": {}} { "execute": "query-version" } -{"return": {"qemu": "0.11.50", "package": ""}} +{"return": {"qemu": "0.12.50", "package": ""}} Contact ------- diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index dc48cccea1..d585a8d1b6 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -43,3 +43,24 @@ Data: 'server' and 'client' keys with the same keys as 'query-vnc'. Description: Issued when the VNC session is made active. Data: 'server' and 'client' keys with the same keys as 'query-vnc'. + +7 BLOCK_IO_ERROR +---------------- + +Description: Issued when a disk I/O error occurs +Data: + +- 'device': device name (json-string) +- 'operation': I/O operation (json-string, "read" or "write") +- 'action': action that has been taken, it's one of the following: + "ignore": error has been ignored + "report": error has been reported to the device + "stop": error caused VM to be stopped + +Example: + +{ "event": "BLOCK_IO_ERROR", + "data": { "device": "ide0-hd1", + "operation": "write", + "action": "stop" }, + "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt index 56f388c3b3..f3c0327703 100644 --- a/QMP/qmp-spec.txt +++ b/QMP/qmp-spec.txt @@ -44,14 +44,17 @@ they can be in ANY order, thus no particular order should be assumed. Right when connected the Server will issue a greeting message, which signals that the connection has been successfully established and that the Server is -waiting for commands. +ready for capabilities negotiation (for more information refer to section +'4. Capabilities Negotiation'). The format is: -{ "QMP": { "capabilities": json-array } } +{ "QMP": { "version": json-object, "capabilities": json-array } } Where, +- The "version" member contains the Server's version information (the format + is the same of the 'query-version' command) - The "capabilities" member specify the availability of features beyond the baseline specification @@ -152,7 +155,7 @@ This section provides some examples of real QMP usage, in all of them 3.1 Server greeting ------------------- -S: {"QMP": {"capabilities": []}} +S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}} 3.2 Simple 'stop' execution --------------------------- @@ -179,25 +182,36 @@ S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data": S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event": "POWERDOWN"} -4. Compatibility Considerations --------------------------------- +4. Capabilities Negotiation +---------------------------- -In order to achieve maximum compatibility between versions, Clients must not -assume any particular: +When a Client successfully establishes a connection, the Server is in +Capabilities Negotiation mode. -- Size of json-objects or length of json-arrays -- Order of json-object members or json-array elements -- Amount of errors generated by a command, that is, new errors can be added - to any existing command in newer versions of the Server +In this mode only the 'qmp_capabilities' command is allowed to run, all +other commands will return the CommandNotFound error. Asynchronous messages +are not delivered either. + +Clients should use the 'qmp_capabilities' command to enable capabilities +advertised in the Server's greeting (section '2.2 Server Greeting') they +support. -Additionally, Clients should always: +When the 'qmp_capabilities' command is issued, and if it does not return an +error, the Server enters in Command mode where capabilities changes take +effect, all commands (except 'qmp_capabilities') are allowed and asynchronous +messages are delivered. -- Check the capabilities json-array at connection time -- Check the availability of commands with 'query-commands' before issuing them +5 Compatibility Considerations +------------------------------ -5. Recommendations to Client implementors ------------------------------------------ +All protocol changes or new features which modify the protocol format in an +incompatible way are disabled by default and will be advertised by the +capabilities array (section '2.2 Server Greeting'). Thus, Clients can check +that array and enable the capabilities they support. -5.1 The Server should be always started in pause mode, thus the Client is - able to perform any setup procedure without the risk of race conditions - and related problems +Additionally, Clients must not assume any particular: + +- Size of json-objects or length of json-arrays +- Order of json-object members or json-array elements +- Amount of errors generated by a command, that is, new errors can be added + to any existing command in newer versions of the Server diff --git a/block-migration.c b/block-migration.c index 230d7ed59f..92349a2149 100644 --- a/block-migration.c +++ b/block-migration.c @@ -15,8 +15,10 @@ #include "block_int.h" #include "hw/hw.h" #include "qemu-queue.h" +#include "qemu-timer.h" #include "monitor.h" #include "block-migration.h" +#include "migration.h" #include <assert.h> #define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS) @@ -26,9 +28,6 @@ #define BLK_MIG_FLAG_PROGRESS 0x04 #define MAX_IS_ALLOCATED_SEARCH 65536 -#define MAX_BLOCKS_READ 10000 -#define BLOCKS_READ_CHANGE 100 -#define INITIAL_BLOCKS_READ 100 //#define DEBUG_BLK_MIGRATION @@ -45,6 +44,7 @@ typedef struct BlkMigDevState { int bulk_completed; int shared_base; int64_t cur_sector; + int64_t cur_dirty; int64_t completed_sectors; int64_t total_sectors; int64_t dirty; @@ -59,6 +59,7 @@ typedef struct BlkMigBlock { QEMUIOVector qiov; BlockDriverAIOCB *aiocb; int ret; + int64_t time; QSIMPLEQ_ENTRY(BlkMigBlock) entry; } BlkMigBlock; @@ -72,6 +73,9 @@ typedef struct BlkMigState { int transferred; int64_t total_sector_sum; int prev_progress; + int bulk_completed; + long double total_time; + int reads; } BlkMigState; static BlkMigState block_mig_state; @@ -124,12 +128,28 @@ uint64_t blk_mig_bytes_total(void) return sum << BDRV_SECTOR_BITS; } +static inline void add_avg_read_time(int64_t time) +{ + block_mig_state.reads++; + block_mig_state.total_time += time; +} + +static inline long double compute_read_bwidth(void) +{ + assert(block_mig_state.total_time != 0); + return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time; +} + static void blk_mig_read_cb(void *opaque, int ret) { BlkMigBlock *blk = opaque; blk->ret = ret; + blk->time = qemu_get_clock_ns(rt_clock) - blk->time; + + add_avg_read_time(blk->time); + QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); block_mig_state.submitted--; @@ -138,7 +158,7 @@ static void blk_mig_read_cb(void *opaque, int ret) } static int mig_save_device_bulk(Monitor *mon, QEMUFile *f, - BlkMigDevState *bmds, int is_async) + BlkMigDevState *bmds) { int64_t total_sectors = bmds->total_sectors; int64_t cur_sector = bmds->cur_sector; @@ -175,26 +195,18 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f, blk->bmds = bmds; blk->sector = cur_sector; - if (is_async) { - blk->iov.iov_base = blk->buf; - blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; - qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + blk->iov.iov_base = blk->buf; + blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; + qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, - nr_sectors, blk_mig_read_cb, blk); - if (!blk->aiocb) { - goto error; - } - block_mig_state.submitted++; - } else { - if (bdrv_read(bs, cur_sector, blk->buf, nr_sectors) < 0) { - goto error; - } - blk_send(f, blk); + blk->time = qemu_get_clock_ns(rt_clock); - qemu_free(blk->buf); - qemu_free(blk); + blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, + nr_sectors, blk_mig_read_cb, blk); + if (!blk->aiocb) { + goto error; } + block_mig_state.submitted++; bdrv_reset_dirty(bs, cur_sector, nr_sectors); bmds->cur_sector = cur_sector + nr_sectors; @@ -229,6 +241,9 @@ static void init_blk_migration(Monitor *mon, QEMUFile *f) block_mig_state.transferred = 0; block_mig_state.total_sector_sum = 0; block_mig_state.prev_progress = -1; + block_mig_state.bulk_completed = 0; + block_mig_state.total_time = 0; + block_mig_state.reads = 0; for (bs = bdrv_first; bs != NULL; bs = bs->next) { if (bs->type == BDRV_TYPE_HD) { @@ -260,7 +275,7 @@ static void init_blk_migration(Monitor *mon, QEMUFile *f) } } -static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async) +static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f) { int64_t completed_sector_sum = 0; BlkMigDevState *bmds; @@ -269,7 +284,7 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async) QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { if (bmds->bulk_completed == 0) { - if (mig_save_device_bulk(mon, f, bmds, is_async) == 1) { + if (mig_save_device_bulk(mon, f, bmds) == 1) { /* completed bulk section for this device */ bmds->bulk_completed = 1; } @@ -293,39 +308,90 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async) return ret; } -#define MAX_NUM_BLOCKS 4 - -static void blk_mig_save_dirty_blocks(Monitor *mon, QEMUFile *f) +static void blk_mig_reset_dirty_cursor(void) { BlkMigDevState *bmds; - BlkMigBlock blk; + + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + bmds->cur_dirty = 0; + } +} + +static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, + BlkMigDevState *bmds, int is_async) +{ + BlkMigBlock *blk; + int64_t total_sectors = bmds->total_sectors; int64_t sector; + int nr_sectors; - blk.buf = qemu_malloc(BLOCK_SIZE); + for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) { + if (bdrv_get_dirty(bmds->bs, sector)) { - QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { - for (sector = 0; sector < bmds->cur_sector;) { - if (bdrv_get_dirty(bmds->bs, sector)) { - if (bdrv_read(bmds->bs, sector, blk.buf, - BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) { - monitor_printf(mon, "Error reading sector %" PRId64 "\n", - sector); - qemu_file_set_error(f); - qemu_free(blk.buf); - return; + if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { + nr_sectors = total_sectors - sector; + } else { + nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; + } + blk = qemu_malloc(sizeof(BlkMigBlock)); + blk->buf = qemu_malloc(BLOCK_SIZE); + blk->bmds = bmds; + blk->sector = sector; + + if (is_async) { + blk->iov.iov_base = blk->buf; + blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; + qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + + blk->time = qemu_get_clock_ns(rt_clock); + + blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov, + nr_sectors, blk_mig_read_cb, blk); + if (!blk->aiocb) { + goto error; } - blk.bmds = bmds; - blk.sector = sector; - blk_send(f, &blk); + block_mig_state.submitted++; + } else { + if (bdrv_read(bmds->bs, sector, blk->buf, + nr_sectors) < 0) { + goto error; + } + blk_send(f, blk); - bdrv_reset_dirty(bmds->bs, sector, - BDRV_SECTORS_PER_DIRTY_CHUNK); + qemu_free(blk->buf); + qemu_free(blk); } - sector += BDRV_SECTORS_PER_DIRTY_CHUNK; + + bdrv_reset_dirty(bmds->bs, sector, nr_sectors); + break; + } + sector += BDRV_SECTORS_PER_DIRTY_CHUNK; + bmds->cur_dirty = sector; + } + + return (bmds->cur_dirty >= bmds->total_sectors); + +error: + monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector); + qemu_file_set_error(f); + qemu_free(blk->buf); + qemu_free(blk); + return 0; +} + +static int blk_mig_save_dirty_block(Monitor *mon, QEMUFile *f, int is_async) +{ + BlkMigDevState *bmds; + int ret = 0; + + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + if (mig_save_device_dirty(mon, f, bmds, is_async) == 0) { + ret = 1; + break; } } - qemu_free(blk.buf); + return ret; } static void flush_blks(QEMUFile* f) @@ -360,21 +426,42 @@ static void flush_blks(QEMUFile* f) block_mig_state.transferred); } -static int is_stage2_completed(void) +static int64_t get_remaining_dirty(void) { BlkMigDevState *bmds; + int64_t dirty = 0; - if (block_mig_state.submitted > 0) { - return 0; + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + dirty += bdrv_get_dirty_count(bmds->bs); } - QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { - if (bmds->bulk_completed == 0) { - return 0; + return dirty * BLOCK_SIZE; +} + +static int is_stage2_completed(void) +{ + int64_t remaining_dirty; + long double bwidth; + + if (block_mig_state.bulk_completed == 1) { + + remaining_dirty = get_remaining_dirty(); + if (remaining_dirty == 0) { + return 1; + } + + bwidth = compute_read_bwidth(); + + if ((remaining_dirty / bwidth) <= + migrate_max_downtime()) { + /* finish stage2 because we think that we can finish remaing work + below max_downtime */ + + return 1; } } - return 1; + return 0; } static void blk_mig_cleanup(Monitor *mon) @@ -428,29 +515,41 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) return 0; } - /* control the rate of transfer */ - while ((block_mig_state.submitted + - block_mig_state.read_done) * BLOCK_SIZE < - qemu_file_get_rate_limit(f)) { - if (blk_mig_save_bulked_block(mon, f, 1) == 0) { - /* no more bulk blocks for now */ - break; + blk_mig_reset_dirty_cursor(); + + if (stage == 2) { + /* control the rate of transfer */ + while ((block_mig_state.submitted + + block_mig_state.read_done) * BLOCK_SIZE < + qemu_file_get_rate_limit(f)) { + if (block_mig_state.bulk_completed == 0) { + /* first finish the bulk phase */ + if (blk_mig_save_bulked_block(mon, f) == 0) { + /* finished saving bulk on all devices */ + block_mig_state.bulk_completed = 1; + } + } else { + if (blk_mig_save_dirty_block(mon, f, 1) == 0) { + /* no more dirty blocks */ + break; + } + } } - } - flush_blks(f); + flush_blks(f); - if (qemu_file_has_error(f)) { - blk_mig_cleanup(mon); - return 0; + if (qemu_file_has_error(f)) { + blk_mig_cleanup(mon); + return 0; + } } if (stage == 3) { - while (blk_mig_save_bulked_block(mon, f, 0) != 0) { - /* empty */ - } + /* we know for sure that save bulk is completed and + all async read completed */ + assert(block_mig_state.submitted == 0); - blk_mig_save_dirty_blocks(mon, f); + while (blk_mig_save_dirty_block(mon, f, 0) != 0); blk_mig_cleanup(mon); /* report completion */ @@ -451,13 +451,20 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bs->enable_write_cache = 1; bs->read_only = (flags & BDRV_O_RDWR) == 0; - if (!(flags & BDRV_O_FILE)) { - open_flags = (flags & (BDRV_O_RDWR | BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO)); - if (bs->is_temporary) { /* snapshot should be writeable */ - open_flags |= BDRV_O_RDWR; - } - } else { - open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT); + + /* + * Clear flags that are internal to the block layer before opening the + * image. + */ + open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); + + /* + * Snapshots should be writeable. + * + * XXX(hch): and what is the point of a snapshot during a read-only open? + */ + if (!(flags & BDRV_O_FILE) && bs->is_temporary) { + open_flags |= BDRV_O_RDWR; } ret = drv->bdrv_open(bs, filename, open_flags); @@ -686,9 +693,15 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num, bit = start % (sizeof(unsigned long) * 8); val = bs->dirty_bitmap[idx]; if (dirty) { - val |= 1 << bit; + if (!(val & (1 << bit))) { + bs->dirty_count++; + val |= 1 << bit; + } } else { - val &= ~(1 << bit); + if (val & (1 << bit)) { + bs->dirty_count--; + val &= ~(1 << bit); + } } bs->dirty_bitmap[idx] = val; } @@ -1164,6 +1177,35 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum); } +void bdrv_mon_event(const BlockDriverState *bdrv, + BlockMonEventAction action, int is_read) +{ + QObject *data; + const char *action_str; + + switch (action) { + case BDRV_ACTION_REPORT: + action_str = "report"; + break; + case BDRV_ACTION_IGNORE: + action_str = "ignore"; + break; + case BDRV_ACTION_STOP: + action_str = "stop"; + break; + default: + abort(); + } + + data = qobject_from_jsonf("{ 'device': %s, 'action': %s, 'operation': %s }", + bdrv->device_name, + action_str, + is_read ? "read" : "write"); + monitor_protocol_event(QEVENT_BLOCK_IO_ERROR, data); + + qobject_decref(data); +} + static void bdrv_print_dict(QObject *obj, void *opaque) { QDict *bs_dict; @@ -1259,7 +1301,6 @@ void bdrv_info(Monitor *mon, QObject **ret_data) "'removable': %i, 'locked': %i }", bs->device_name, type, bs->removable, bs->locked); - assert(bs_obj != NULL); if (bs->drv) { QObject *obj; @@ -1270,7 +1311,6 @@ void bdrv_info(Monitor *mon, QObject **ret_data) bs->filename, bs->read_only, bs->drv->format_name, bdrv_is_encrypted(bs)); - assert(obj != NULL); if (bs->backing_file[0] != '\0') { QDict *qdict = qobject_to_qdict(obj); qdict_put(qdict, "backing_file", @@ -1356,7 +1396,6 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data) bs->device_name, bs->rd_bytes, bs->wr_bytes, bs->rd_ops, bs->wr_ops); - assert(obj != NULL); qlist_append_obj(devices, obj); } @@ -2139,6 +2178,7 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) { int64_t bitmap_size; + bs->dirty_count = 0; if (enable) { if (!bs->dirty_bitmap) { bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) + @@ -2173,3 +2213,8 @@ void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, { set_dirty_bitmap(bs, cur_sector, nr_sectors, 0); } + +int64_t bdrv_get_dirty_count(BlockDriverState *bs) +{ + return bs->dirty_count; +} @@ -44,6 +44,12 @@ typedef struct QEMUSnapshotInfo { #define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS) #define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1); +typedef enum { + BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP +} BlockMonEventAction; + +void bdrv_mon_event(const BlockDriverState *bdrv, + BlockMonEventAction action, int is_read); void bdrv_info_print(Monitor *mon, const QObject *data); void bdrv_info(Monitor *mon, QObject **ret_data); void bdrv_stats_print(Monitor *mon, const QObject *data); @@ -200,4 +206,5 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); +int64_t bdrv_get_dirty_count(BlockDriverState *bs); #endif diff --git a/block/curl.c b/block/curl.c index 86ac81b268..2cf72cb4e8 100644 --- a/block/curl.c +++ b/block/curl.c @@ -309,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags) static int inited = 0; - file = strdup(filename); + file = qemu_strdup(filename); s->readahead_size = READ_AHEAD_SIZE; /* Parse a trailing ":readahead=#:" param, if present. */ @@ -339,7 +339,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags) } if ((s->readahead_size & 0x1ff) != 0) { - fprintf(stderr, "HTTP_READAHEAD_SIZE %Zd is not a multiple of 512\n", + fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n", s->readahead_size); goto out_noclean; } diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4e30d161a7..3501a94296 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -219,7 +219,8 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) BDRVQcowState *s = bs->opaque; int min_index; uint64_t old_l2_offset; - uint64_t *l2_table, l2_offset; + uint64_t *l2_table; + int64_t l2_offset; old_l2_offset = s->l1_table[l1_index]; @@ -560,7 +561,8 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, { BDRVQcowState *s = bs->opaque; int l2_index, ret; - uint64_t l2_offset, *l2_table, cluster_offset; + uint64_t l2_offset, *l2_table; + int64_t cluster_offset; int nb_csectors; ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); @@ -704,10 +706,8 @@ err: * * Return 0 on success and -errno in error cases */ -uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int n_start, int n_end, - int *num, QCowL2Meta *m) +int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, + int n_start, int n_end, int *num, QCowL2Meta *m) { BDRVQcowState *s = bs->opaque; int l2_index, ret; diff --git a/block/qcow2.h b/block/qcow2.h index d9ea6abc50..de9397a3d3 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -192,10 +192,8 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int *num); -uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int n_start, int n_end, - int *num, QCowL2Meta *m); +int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, + int n_start, int n_end, int *num, QCowL2Meta *m); uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset, int compressed_size); diff --git a/block/vvfat.c b/block/vvfat.c index d2787b9e76..bb707c0008 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -883,7 +883,7 @@ static int init_directories(BDRVVVFATState* s, mapping->dir_index = 0; mapping->info.dir.parent_mapping_index = -1; mapping->first_mapping_index = -1; - mapping->path = strdup(dirname); + mapping->path = qemu_strdup(dirname); i = strlen(mapping->path); if (i > 0 && mapping->path[i - 1] == '/') mapping->path[i - 1] = '\0'; @@ -1633,10 +1633,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, /* rename */ if (strcmp(basename, basename2)) - schedule_rename(s, cluster_num, strdup(path)); + schedule_rename(s, cluster_num, qemu_strdup(path)); } else if (is_file(direntry)) /* new file */ - schedule_new_file(s, strdup(path), cluster_num); + schedule_new_file(s, qemu_strdup(path), cluster_num); else { assert(0); return 0; @@ -1753,10 +1753,10 @@ static int check_directory_consistency(BDRVVVFATState *s, mapping->mode &= ~MODE_DELETED; if (strcmp(basename, basename2)) - schedule_rename(s, cluster_num, strdup(path)); + schedule_rename(s, cluster_num, qemu_strdup(path)); } else /* new directory */ - schedule_mkdir(s, cluster_num, strdup(path)); + schedule_mkdir(s, cluster_num, qemu_strdup(path)); lfn_init(&lfn); do { diff --git a/block_int.h b/block_int.h index a0ebd90a0b..930a5a4d11 100644 --- a/block_int.h +++ b/block_int.h @@ -175,6 +175,7 @@ struct BlockDriverState { int type; char device_name[32]; unsigned long *dirty_bitmap; + int64_t dirty_count; BlockDriverState *next; void *private; }; @@ -201,4 +202,31 @@ extern BlockDriverState *bdrv_first; int is_windows_drive(const char *filename); #endif +struct DriveInfo; + +typedef struct BlockConf { + struct DriveInfo *dinfo; + uint16_t physical_block_size; + uint16_t min_io_size; + uint32_t opt_io_size; +} BlockConf; + +static inline unsigned int get_physical_block_exp(BlockConf *conf) +{ + unsigned int exp = 0, size; + + for (size = conf->physical_block_size; size > 512; size >>= 1) { + exp++; + } + + return exp; +} + +#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \ + DEFINE_PROP_DRIVE("drive", _state, _conf.dinfo), \ + DEFINE_PROP_UINT16("physical_block_size", _state, \ + _conf.physical_block_size, 512), \ + DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 512), \ + DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 512) + #endif /* BLOCK_INT_H */ @@ -796,6 +796,8 @@ echo " --enable-linux-aio enable Linux AIO support" echo " --enable-io-thread enable IO thread" echo " --disable-blobs disable installing provided firmware blobs" echo " --kerneldir=PATH look for kernel includes in PATH" +echo " --enable-docs enable documentation build" +echo " --disable-docs disable documentation build" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -1055,7 +1057,11 @@ if test "$sdl" != "no" ; then int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } EOF sdl_cflags=`$sdlconfig --cflags 2> /dev/null` - sdl_libs=`$sdlconfig --libs 2> /dev/null` + if test "$static" = "yes" ; then + sdl_libs=`$sdlconfig --static-libs 2>/dev/null` + else + sdl_libs=`$sdlconfig --libs 2> /dev/null` + fi if compile_prog "$sdl_cflags" "$sdl_libs" ; then if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes @@ -1067,7 +1073,6 @@ EOF # static link with sdl ? (note: sdl.pc's --static --libs is broken) if test "$sdl" = "yes" -a "$static" = "yes" ; then - sdl_libs=`sdl-config --static-libs 2>/dev/null` if test $? = 0 && echo $sdl_libs | grep -- -laa > /dev/null; then sdl_libs="$sdl_libs `aalib-config --static-libs >2 /dev/null`" sdl_cflags="$sdl_cflags `aalib-config --cflags >2 /dev/null`" @@ -915,6 +915,8 @@ void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); +void qemu_flush_coalesced_mmio_buffer(void); + /*******************************************/ /* host CPU ticks (if available) */ diff --git a/cpu-common.h b/cpu-common.h index 630237203d..0ec9b72a91 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -8,6 +8,7 @@ #endif #include "bswap.h" +#include "qemu-queue.h" /* address in the RAM (different from a physical address) */ typedef unsigned long ram_addr_t; @@ -61,6 +62,24 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)); void cpu_unregister_map_client(void *cookie); +struct CPUPhysMemoryClient; +typedef struct CPUPhysMemoryClient CPUPhysMemoryClient; +struct CPUPhysMemoryClient { + void (*set_memory)(struct CPUPhysMemoryClient *client, + target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset); + int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client, + target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + int (*migration_log)(struct CPUPhysMemoryClient *client, + int enable); + QLIST_ENTRY(CPUPhysMemoryClient) list; +}; + +void cpu_register_phys_memory_client(CPUPhysMemoryClient *); +void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *); + uint32_t ldub_phys(target_phys_addr_t addr); uint32_t lduw_phys(target_phys_addr_t addr); uint32_t ldl_phys(target_phys_addr_t addr); diff --git a/cpu-defs.h b/cpu-defs.h index 95068b5304..7fdbe97787 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -197,6 +197,7 @@ typedef struct CPUWatchpoint { const char *cpu_model_str; \ struct KVMState *kvm_state; \ struct kvm_run *kvm_run; \ - int kvm_fd; + int kvm_fd; \ + int kvm_vcpu_dirty; #endif @@ -1624,6 +1624,101 @@ const CPULogItem cpu_log_items[] = { { 0, NULL, NULL }, }; +#ifndef CONFIG_USER_ONLY +static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list + = QLIST_HEAD_INITIALIZER(memory_client_list); + +static void cpu_notify_set_memory(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset) +{ + CPUPhysMemoryClient *client; + QLIST_FOREACH(client, &memory_client_list, list) { + client->set_memory(client, start_addr, size, phys_offset); + } +} + +static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start, + target_phys_addr_t end) +{ + CPUPhysMemoryClient *client; + QLIST_FOREACH(client, &memory_client_list, list) { + int r = client->sync_dirty_bitmap(client, start, end); + if (r < 0) + return r; + } + return 0; +} + +static int cpu_notify_migration_log(int enable) +{ + CPUPhysMemoryClient *client; + QLIST_FOREACH(client, &memory_client_list, list) { + int r = client->migration_log(client, enable); + if (r < 0) + return r; + } + return 0; +} + +static void phys_page_for_each_in_l1_map(PhysPageDesc **phys_map, + CPUPhysMemoryClient *client) +{ + PhysPageDesc *pd; + int l1, l2; + + for (l1 = 0; l1 < L1_SIZE; ++l1) { + pd = phys_map[l1]; + if (!pd) { + continue; + } + for (l2 = 0; l2 < L2_SIZE; ++l2) { + if (pd[l2].phys_offset == IO_MEM_UNASSIGNED) { + continue; + } + client->set_memory(client, pd[l2].region_offset, + TARGET_PAGE_SIZE, pd[l2].phys_offset); + } + } +} + +static void phys_page_for_each(CPUPhysMemoryClient *client) +{ +#if TARGET_PHYS_ADDR_SPACE_BITS > 32 + +#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS) +#error unsupported TARGET_PHYS_ADDR_SPACE_BITS +#endif + void **phys_map = (void **)l1_phys_map; + int l1; + if (!l1_phys_map) { + return; + } + for (l1 = 0; l1 < L1_SIZE; ++l1) { + if (phys_map[l1]) { + phys_page_for_each_in_l1_map(phys_map[l1], client); + } + } +#else + if (!l1_phys_map) { + return; + } + phys_page_for_each_in_l1_map(l1_phys_map, client); +#endif +} + +void cpu_register_phys_memory_client(CPUPhysMemoryClient *client) +{ + QLIST_INSERT_HEAD(&memory_client_list, client, list); + phys_page_for_each(client); +} + +void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client) +{ + QLIST_REMOVE(client, list); +} +#endif + static int cmp1(const char *s1, int n, const char *s2) { if (strlen(s2) != n) @@ -1891,11 +1986,10 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, int cpu_physical_memory_set_dirty_tracking(int enable) { + int ret = 0; in_migration = enable; - if (kvm_enabled()) { - return kvm_set_migration_log(enable); - } - return 0; + ret = cpu_notify_migration_log(!!enable); + return ret; } int cpu_physical_memory_get_dirty_tracking(void) @@ -1906,10 +2000,9 @@ int cpu_physical_memory_get_dirty_tracking(void) int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr) { - int ret = 0; + int ret; - if (kvm_enabled()) - ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr); return ret; } @@ -2321,8 +2414,7 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, ram_addr_t orig_size = size; void *subpage; - if (kvm_enabled()) - kvm_set_phys_mem(start_addr, size, phys_offset); + cpu_notify_set_memory(start_addr, size, phys_offset); if (phys_offset == IO_MEM_UNASSIGNED) { region_offset = start_addr; @@ -2415,6 +2507,12 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) kvm_uncoalesce_mmio_region(addr, size); } +void qemu_flush_coalesced_mmio_buffer(void) +{ + if (kvm_enabled()) + kvm_flush_coalesced_mmio_buffer(); +} + ram_addr_t qemu_ram_alloc(ram_addr_t size) { RAMBlock *new_block; diff --git a/hw/ide/core.c b/hw/ide/core.c index b6643e8260..37a5151570 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -164,6 +164,8 @@ static void ide_identify(IDEState *s) put_le16(p + 101, s->nb_sectors >> 16); put_le16(p + 102, s->nb_sectors >> 32); put_le16(p + 103, s->nb_sectors >> 48); + if (s->conf && s->conf->physical_block_size) + put_le16(p + 106, 0x6000 | get_physical_block_exp(s->conf)); memcpy(s->identify_data, p, sizeof(s->identify_data)); s->identify_set = 1; @@ -480,14 +482,17 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) int is_read = (op & BM_STATUS_RETRY_READ); BlockInterfaceErrorAction action = drive_get_on_error(s->bs, is_read); - if (action == BLOCK_ERR_IGNORE) + if (action == BLOCK_ERR_IGNORE) { + bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read); return 0; + } if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) || action == BLOCK_ERR_STOP_ANY) { s->bus->bmdma->unit = s->unit; s->bus->bmdma->status |= op; vm_stop(0); + bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); } else { if (op & BM_STATUS_DMA_RETRY) { dma_buf_commit(s, 0); @@ -495,6 +500,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) } else { ide_rw_error(s); } + bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); } return 1; @@ -2590,7 +2596,8 @@ void ide_bus_reset(IDEBus *bus) ide_clear_hob(bus); } -void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version) +void ide_init_drive(IDEState *s, DriveInfo *dinfo, BlockConf *conf, + const char *version) { int cylinders, heads, secs; uint64_t nb_sectors; @@ -2615,6 +2622,9 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version) } strncpy(s->drive_serial_str, drive_get_serial(s->bs), sizeof(s->drive_serial_str)); + if (conf) { + s->conf = conf; + } } if (strlen(s->drive_serial_str) == 0) snprintf(s->drive_serial_str, sizeof(s->drive_serial_str), @@ -2644,9 +2654,9 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1, s->sector_write_timer = qemu_new_timer(vm_clock, ide_sector_write_timer_cb, s); if (i == 0) - ide_init_drive(s, hd0, NULL); + ide_init_drive(s, hd0, NULL, NULL); if (i == 1) - ide_init_drive(s, hd1, NULL); + ide_init_drive(s, hd1, NULL, NULL); } bus->irq = irq; } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 1cc4b550f7..9945993655 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -7,6 +7,7 @@ * non-internal declarations are in hw/ide.h */ #include <hw/ide.h> +#include "block_int.h" /* debug IDE devices */ //#define DEBUG_IDE @@ -397,6 +398,7 @@ struct IDEState { /* set for lba48 access */ uint8_t lba48; BlockDriverState *bs; + BlockConf *conf; char version[9]; /* ATAPI specific */ uint8_t sense_key; @@ -449,7 +451,7 @@ struct IDEBus { struct IDEDevice { DeviceState qdev; uint32_t unit; - DriveInfo *dinfo; + BlockConf conf; char *version; }; @@ -551,7 +553,8 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr); void ide_data_writel(void *opaque, uint32_t addr, uint32_t val); uint32_t ide_data_readl(void *opaque, uint32_t addr); -void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version); +void ide_init_drive(IDEState *s, DriveInfo *dinfo, BlockConf *conf, + const char *version); void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1, qemu_irq irq); void ide_init_ioport(IDEBus *bus, int iobase, int iobase2); diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 0b84a4f1d0..b18693d945 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -40,7 +40,7 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base) IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base); IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus); - if (!dev->dinfo) { + if (!dev->conf.dinfo) { fprintf(stderr, "%s: no drive specified\n", qdev->info->name); goto err; } @@ -99,7 +99,8 @@ typedef struct IDEDrive { static int ide_drive_initfn(IDEDevice *dev) { IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus); - ide_init_drive(bus->ifs + dev->unit, dev->dinfo, dev->version); + ide_init_drive(bus->ifs + dev->unit, dev->conf.dinfo, &dev->conf, + dev->version); return 0; } @@ -109,7 +110,7 @@ static IDEDeviceInfo ide_drive_info = { .init = ide_drive_initfn, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1), - DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo), + DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), DEFINE_PROP_STRING("ver", IDEDrive, dev.version), DEFINE_PROP_END_OF_LIST(), } diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index ba13d2bce0..0fb96f06fd 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -285,7 +285,6 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data) qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, " "'function': %d }", pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - assert(*ret_data != NULL); } else monitor_printf(mon, "failed to add %s\n", opts); } @@ -66,7 +66,6 @@ typedef struct { uint16_t keyctlclr; uint16_t pad0; uint16_t pad1; - uint16_t powoff; uint16_t verreg; uint16_t inport; uint16_t outport; @@ -128,7 +127,7 @@ static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr) case PA_OUTPORT: return s->outport; case PA_POWOFF: - return s->powoff; + return 0x00; case PA_VERREG: return 0x10; } @@ -150,8 +149,10 @@ r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value) s->outport = value; break; case PA_POWOFF: - s->powoff = value; - break; + if (value & 1) { + qemu_system_shutdown_request(); + } + break; case PA_VERREG: /* Discard writes */ break; diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 6b6dafc196..fa0a74fae4 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -123,7 +123,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev) { VirtIODevice *vdev; - vdev = virtio_blk_init((DeviceState *)dev, dev->dinfo); + vdev = virtio_blk_init((DeviceState *)dev, dev->block.dinfo); if (!vdev) { return -1; } @@ -337,7 +337,7 @@ static VirtIOS390DeviceInfo s390_virtio_blk = { .qdev.name = "virtio-blk-s390", .qdev.size = sizeof(VirtIOS390Device), .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", VirtIOS390Device, dinfo), + DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 8e4763a184..0ea8f54745 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -38,7 +38,7 @@ typedef struct VirtIOS390Device { ram_addr_t feat_offs; uint8_t feat_len; VirtIODevice *vdev; - DriveInfo *dinfo; + BlockConf block; NICConf nic; uint32_t host_features; /* Max. number of ports we can have for a the virtio-serial device */ diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index b34fbaa674..b2f61fea26 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -60,6 +60,7 @@ typedef struct SCSIDiskReq { struct SCSIDiskState { SCSIDevice qdev; + BlockDriverState *bs; /* The qemu block layer uses a fixed 512 byte sector size. This is the number of 512 byte blocks in a single scsi sector. */ int cluster_size; @@ -168,7 +169,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) r->iov.iov_len = n * 512; qemu_iovec_init_external(&r->qiov, &r->iov, 1); - r->req.aiocb = bdrv_aio_readv(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n, + r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n, scsi_read_complete, r); if (r->req.aiocb == NULL) scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); @@ -179,19 +180,22 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) static int scsi_handle_write_error(SCSIDiskReq *r, int error) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockInterfaceErrorAction action = - drive_get_on_error(s->qdev.dinfo->bdrv, 0); + BlockInterfaceErrorAction action = drive_get_on_error(s->bs, 0); - if (action == BLOCK_ERR_IGNORE) + if (action == BLOCK_ERR_IGNORE) { + bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0); return 0; + } if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) || action == BLOCK_ERR_STOP_ANY) { r->status |= SCSI_REQ_STATUS_RETRY; vm_stop(0); + bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0); } else { scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); + bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0); } return 1; @@ -234,7 +238,7 @@ static void scsi_write_request(SCSIDiskReq *r) n = r->iov.iov_len / 512; if (n) { qemu_iovec_init_external(&r->qiov, &r->iov, 1); - r->req.aiocb = bdrv_aio_writev(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n, + r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, scsi_write_complete, r); if (r->req.aiocb == NULL) scsi_command_complete(r, CHECK_CONDITION, @@ -315,7 +319,6 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) { - BlockDriverState *bdrv = req->dev->dinfo->bdrv; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int buflen = 0; @@ -334,7 +337,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) return -1; } - if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { outbuf[buflen++] = 5; } else { outbuf[buflen++] = 0; @@ -346,16 +349,17 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) case 0x00: /* Supported page codes, mandatory */ DPRINTF("Inquiry EVPD[Supported pages] " "buffer size %zd\n", req->cmd.xfer); - outbuf[buflen++] = 3; // number of pages + outbuf[buflen++] = 4; // number of pages outbuf[buflen++] = 0x00; // list of supported pages (this page) outbuf[buflen++] = 0x80; // unit serial number outbuf[buflen++] = 0x83; // device identification + outbuf[buflen++] = 0xb0; // block device characteristics break; case 0x80: /* Device serial number, optional */ { - const char *serial = req->dev->dinfo->serial ? - req->dev->dinfo->serial : "0"; + const char *serial = req->dev->conf.dinfo->serial ? + req->dev->conf.dinfo->serial : "0"; int l = strlen(serial); if (l > req->cmd.xfer) @@ -374,7 +378,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) case 0x83: /* Device identification page, mandatory */ { int max_len = 255 - 8; - int id_len = strlen(bdrv_get_device_name(bdrv)); + int id_len = strlen(bdrv_get_device_name(s->bs)); if (id_len > max_len) id_len = max_len; @@ -387,10 +391,31 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) outbuf[buflen++] = 0; // reserved outbuf[buflen++] = id_len; // length of data following - memcpy(outbuf+buflen, bdrv_get_device_name(bdrv), id_len); + memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len); buflen += id_len; break; } + case 0xb0: /* block device characteristics */ + { + unsigned int min_io_size = s->qdev.conf.min_io_size >> 9; + unsigned int opt_io_size = s->qdev.conf.opt_io_size >> 9; + + /* required VPD size with unmap support */ + outbuf[3] = buflen = 0x3c; + + memset(outbuf + 4, 0, buflen - 4); + + /* optimal transfer length granularity */ + outbuf[6] = (min_io_size >> 8) & 0xff; + outbuf[7] = min_io_size & 0xff; + + /* optimal transfer length */ + outbuf[12] = (opt_io_size >> 24) & 0xff; + outbuf[13] = (opt_io_size >> 16) & 0xff; + outbuf[14] = (opt_io_size >> 8) & 0xff; + outbuf[15] = opt_io_size & 0xff; + break; + } default: BADF("Error: unsupported Inquiry (EVPD[%02X]) " "buffer size %zd\n", page_code, req->cmd.xfer); @@ -425,7 +450,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) return buflen; } - if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { outbuf[0] = 5; outbuf[1] = 0x80; memcpy(&outbuf[16], "QEMU CD-ROM ", 16); @@ -437,7 +462,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4); /* Identify device as SCSI-3 rev 1. Some later commands are also implemented. */ - outbuf[2] = 3; + outbuf[2] = 5; outbuf[3] = 2; /* Format 2 */ if (buflen > 36) { @@ -456,7 +481,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - BlockDriverState *bdrv = req->dev->dinfo->bdrv; + BlockDriverState *bdrv = s->bs; int cylinders, heads, secs; switch (page) { @@ -528,7 +553,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p) case 8: /* Caching page. */ p[0] = 8; p[1] = 0x12; - if (bdrv_enable_write_cache(s->qdev.dinfo->bdrv)) { + if (bdrv_enable_write_cache(s->bs)) { p[2] = 4; /* WCE */ } return 20; @@ -545,7 +570,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p) p[5] = 0xff; /* CD DA, DA accurate, RW supported, RW corrected, C2 errors, ISRC, UPC, Bar code */ - p[6] = 0x2d | (bdrv_is_locked(s->qdev.dinfo->bdrv)? 2 : 0); + p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0); /* Locking supported, jumper present, eject, tray */ p[7] = 0; /* no volume & mute control, no changer */ @@ -571,7 +596,6 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p) static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - BlockDriverState *bdrv = req->dev->dinfo->bdrv; uint64_t nb_sectors; int page, dbd, buflen; uint8_t *p; @@ -584,13 +608,13 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) p[1] = 0; /* Default media type. */ p[3] = 0; /* Block descriptor length. */ - if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM || - bdrv_is_read_only(bdrv)) { + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM || + bdrv_is_read_only(s->bs)) { p[2] = 0x80; /* Readonly. */ } p += 4; - bdrv_get_geometry(bdrv, &nb_sectors); + bdrv_get_geometry(s->bs, &nb_sectors); if ((~dbd) & nb_sectors) { outbuf[3] = 8; /* Block descriptor length */ nb_sectors /= s->cluster_size; @@ -631,14 +655,13 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - BlockDriverState *bdrv = req->dev->dinfo->bdrv; int start_track, format, msf, toclen; uint64_t nb_sectors; msf = req->cmd.buf[1] & 2; format = req->cmd.buf[2] & 0xf; start_track = req->cmd.buf[6]; - bdrv_get_geometry(bdrv, &nb_sectors); + bdrv_get_geometry(s->bs, &nb_sectors); DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); nb_sectors /= s->cluster_size; switch (format) { @@ -667,13 +690,12 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - BlockDriverState *bdrv = req->dev->dinfo->bdrv; uint64_t nb_sectors; int buflen = 0; switch (req->cmd.buf[0]) { case TEST_UNIT_READY: - if (!bdrv_is_inserted(bdrv)) + if (!bdrv_is_inserted(s->bs)) goto not_ready; break; case REQUEST_SENSE: @@ -727,18 +749,18 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) goto illegal_request; break; case START_STOP: - if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM && (req->cmd.buf[4] & 2)) { + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM && (req->cmd.buf[4] & 2)) { /* load/eject medium */ - bdrv_eject(bdrv, !(req->cmd.buf[4] & 1)); + bdrv_eject(s->bs, !(req->cmd.buf[4] & 1)); } break; case ALLOW_MEDIUM_REMOVAL: - bdrv_set_locked(bdrv, req->cmd.buf[4] & 1); + bdrv_set_locked(s->bs, req->cmd.buf[4] & 1); break; case READ_CAPACITY: /* The normal LEN field for this command is zero. */ memset(outbuf, 0, 8); - bdrv_get_geometry(bdrv, &nb_sectors); + bdrv_get_geometry(s->bs, &nb_sectors); if (!nb_sectors) goto not_ready; nb_sectors /= s->cluster_size; @@ -760,7 +782,7 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) buflen = 8; break; case SYNCHRONIZE_CACHE: - bdrv_flush(bdrv); + bdrv_flush(s->bs); break; case GET_CONFIGURATION: memset(outbuf, 0, 8); @@ -774,7 +796,7 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) if ((req->cmd.buf[1] & 31) == 0x10) { DPRINTF("SAI READ CAPACITY(16)\n"); memset(outbuf, 0, req->cmd.xfer); - bdrv_get_geometry(bdrv, &nb_sectors); + bdrv_get_geometry(s->bs, &nb_sectors); if (!nb_sectors) goto not_ready; nb_sectors /= s->cluster_size; @@ -794,6 +816,8 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) outbuf[9] = 0; outbuf[10] = s->cluster_size * 2; outbuf[11] = 0; + outbuf[12] = 0; + outbuf[13] = get_physical_block_exp(&s->qdev.conf); /* Protection, exponent and lowest lba field left blank. */ buflen = req->cmd.xfer; break; @@ -989,7 +1013,7 @@ static void scsi_destroy(SCSIDevice *dev) r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests)); scsi_remove_request(r); } - drive_uninit(s->qdev.dinfo); + drive_uninit(s->qdev.conf.dinfo); } static int scsi_disk_initfn(SCSIDevice *dev) @@ -997,19 +1021,20 @@ static int scsi_disk_initfn(SCSIDevice *dev) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); uint64_t nb_sectors; - if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) { + if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) { qemu_error("scsi-disk: drive property not set\n"); return -1; } + s->bs = s->qdev.conf.dinfo->bdrv; - if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) { + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { s->cluster_size = 4; } else { s->cluster_size = 1; } s->qdev.blocksize = 512 * s->cluster_size; s->qdev.type = TYPE_DISK; - bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors); + bdrv_get_geometry(s->bs, &nb_sectors); nb_sectors /= s->cluster_size; if (nb_sectors) nb_sectors--; @@ -1030,7 +1055,7 @@ static SCSIDeviceInfo scsi_disk_info = { .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo), + DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_STRING("ver", SCSIDiskState, version), DEFINE_PROP_END_OF_LIST(), }, diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index f60ad96d79..de778efa3b 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -58,6 +58,7 @@ typedef struct SCSIGenericReq { struct SCSIGenericState { SCSIDevice qdev; + BlockDriverState *bs; int lun; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; @@ -212,7 +213,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) return; } - ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete); + ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return; @@ -263,7 +264,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) return 0; } - ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete); + ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return 1; @@ -357,7 +358,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, qemu_free(r->buf); r->buflen = 0; r->buf = NULL; - ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete); + ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return 0; @@ -452,7 +453,7 @@ static void scsi_destroy(SCSIDevice *d) r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests)); scsi_remove_request(r); } - drive_uninit(s->qdev.dinfo); + drive_uninit(s->qdev.conf.dinfo); } static int scsi_generic_initfn(SCSIDevice *dev) @@ -461,26 +462,27 @@ static int scsi_generic_initfn(SCSIDevice *dev) int sg_version; struct sg_scsi_id scsiid; - if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) { + if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) { qemu_error("scsi-generic: drive property not set\n"); return -1; } + s->bs = s->qdev.conf.dinfo->bdrv; /* check we are really using a /dev/sg* file */ - if (!bdrv_is_sg(s->qdev.dinfo->bdrv)) { + if (!bdrv_is_sg(s->bs)) { qemu_error("scsi-generic: not /dev/sg*\n"); return -1; } /* check we are using a driver managing SG_IO (version 3 and after */ - if (bdrv_ioctl(s->qdev.dinfo->bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 || + if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 || sg_version < 30000) { qemu_error("scsi-generic: scsi generic interface too old\n"); return -1; } /* get LUN of the /dev/sg? */ - if (bdrv_ioctl(s->qdev.dinfo->bdrv, SG_GET_SCSI_ID, &scsiid)) { + if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) { qemu_error("scsi-generic: SG_GET_SCSI_ID ioctl failed\n"); return -1; } @@ -491,11 +493,11 @@ static int scsi_generic_initfn(SCSIDevice *dev) s->qdev.type = scsiid.scsi_type; DPRINTF("device type %d\n", s->qdev.type); if (s->qdev.type == TYPE_TAPE) { - s->qdev.blocksize = get_stream_blocksize(s->qdev.dinfo->bdrv); + s->qdev.blocksize = get_stream_blocksize(s->bs); if (s->qdev.blocksize == -1) s->qdev.blocksize = 0; } else { - s->qdev.blocksize = get_blocksize(s->qdev.dinfo->bdrv); + s->qdev.blocksize = get_blocksize(s->bs); /* removable media returns 0 if not present */ if (s->qdev.blocksize <= 0) { if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) @@ -522,7 +524,7 @@ static SCSIDeviceInfo scsi_generic_info = { .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", SCSIGenericState, qdev.dinfo), + DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf), DEFINE_PROP_END_OF_LIST(), }, }; @@ -3,6 +3,7 @@ #include "qdev.h" #include "block.h" +#include "block_int.h" #define SCSI_CMD_BUF_SIZE 16 @@ -49,7 +50,7 @@ struct SCSIDevice { DeviceState qdev; uint32_t id; - DriveInfo *dinfo; + BlockConf conf; SCSIDeviceInfo *info; QTAILQ_HEAD(, SCSIRequest) requests; int blocksize; diff --git a/hw/sh7750.c b/hw/sh7750.c index 933bbc0c7a..9c39f4b68b 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -396,8 +396,11 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, portb_changed(s, temp); return; case SH7750_MMUCR_A7: - s->cpu->mmucr = mem_value; - return; + if (mem_value & MMUCR_TI) { + cpu_sh4_invalidate_tlb(s->cpu); + } + s->cpu->mmucr = mem_value & ~MMUCR_TI; + return; case SH7750_PTEH_A7: /* If asid changes, clear all registered tlb entries. */ if ((s->cpu->pteh & 0xff) != (mem_value & 0xff)) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 1fb62ad13c..36991f8833 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -47,7 +47,7 @@ typedef struct { uint32_t residue; uint32_t tag; SCSIBus bus; - DriveInfo *dinfo; + BlockConf conf; SCSIDevice *scsi_dev; int result; /* For async completion. */ @@ -523,20 +523,20 @@ static int usb_msd_initfn(USBDevice *dev) { MSDState *s = DO_UPCAST(MSDState, dev, dev); - if (!s->dinfo || !s->dinfo->bdrv) { + if (!s->conf.dinfo || !s->conf.dinfo->bdrv) { qemu_error("usb-msd: drive property not set\n"); return -1; } s->dev.speed = USB_SPEED_FULL; scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete); - s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, s->dinfo, 0); + s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, s->conf.dinfo, 0); s->bus.qbus.allow_hotplug = 0; usb_msd_handle_reset(dev); - if (bdrv_key_required(s->dinfo->bdrv)) { + if (bdrv_key_required(s->conf.dinfo->bdrv)) { if (s->dev.qdev.hotplugged) { - monitor_read_bdrv_key_start(cur_mon, s->dinfo->bdrv, + monitor_read_bdrv_key_start(cur_mon, s->conf.dinfo->bdrv, usb_msd_password_cb, s); s->dev.auto_attach = 0; } else { @@ -611,7 +611,7 @@ static struct USBDeviceInfo msd_info = { .usbdevice_name = "disk", .usbdevice_init = usb_msd_init, .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", MSDState, dinfo), + DEFINE_BLOCK_PROPERTIES(MSDState, conf), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 37293ea410..c3f3401370 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -497,12 +497,28 @@ static int usb_serial_can_read(void *opaque) static void usb_serial_read(void *opaque, const uint8_t *buf, int size) { USBSerialState *s = opaque; - int first_size = RECV_BUF - s->recv_ptr; - if (first_size > size) - first_size = size; - memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size); - if (size > first_size) - memcpy(s->recv_buf, buf + first_size, size - first_size); + int first_size, start; + + /* room in the buffer? */ + if (size > (RECV_BUF - s->recv_used)) + size = RECV_BUF - s->recv_used; + + start = s->recv_ptr + s->recv_used; + if (start < RECV_BUF) { + /* copy data to end of buffer */ + first_size = RECV_BUF - start; + if (first_size > size) + first_size = size; + + memcpy(s->recv_buf + start, buf, first_size); + + /* wrap around to front if needed */ + if (size > first_size) + memcpy(s->recv_buf, buf + first_size, size - first_size); + } else { + start -= RECV_BUF; + memcpy(s->recv_buf + start, buf, size); + } s->recv_used += size; } diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 434070eeb2..335b66887a 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -112,6 +112,7 @@ typedef struct UHCIAsync { uint32_t td; uint32_t token; int8_t valid; + uint8_t isoc; uint8_t done; uint8_t buffer[2048]; } UHCIAsync; @@ -131,6 +132,7 @@ typedef struct UHCIState { uint32_t fl_base_addr; /* frame list base address */ uint8_t sof_timing; uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ + int64_t expire_time; QEMUTimer *frame_timer; UHCIPort ports[NB_PORTS]; @@ -164,6 +166,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s) async->td = 0; async->token = 0; async->done = 0; + async->isoc = 0; async->next = NULL; return async; @@ -762,13 +765,25 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in { UHCIAsync *async; int len = 0, max_len; - uint8_t pid; + uint8_t pid, isoc; + uint32_t token; /* Is active ? */ if (!(td->ctrl & TD_CTRL_ACTIVE)) return 1; - async = uhci_async_find_td(s, addr, td->token); + /* token field is not unique for isochronous requests, + * so use the destination buffer + */ + if (td->ctrl & TD_CTRL_IOS) { + token = td->buffer; + isoc = 1; + } else { + token = td->token; + isoc = 0; + } + + async = uhci_async_find_td(s, addr, token); if (async) { /* Already submitted */ async->valid = 32; @@ -785,9 +800,13 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in if (!async) return 1; - async->valid = 10; + /* valid needs to be large enough to handle 10 frame delay + * for initial isochronous requests + */ + async->valid = 32; async->td = addr; - async->token = td->token; + async->token = token; + async->isoc = isoc; max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; @@ -841,9 +860,31 @@ static void uhci_async_complete(USBPacket *packet, void *opaque) DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token); - async->done = 1; + if (async->isoc) { + UHCI_TD td; + uint32_t link = async->td; + uint32_t int_mask = 0, val; + int len; + + cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td)); + le32_to_cpus(&td.link); + le32_to_cpus(&td.ctrl); + le32_to_cpus(&td.token); + le32_to_cpus(&td.buffer); + + uhci_async_unlink(s, async); + len = uhci_complete_td(s, &td, async, &int_mask); + s->pending_int_mask |= int_mask; - uhci_process_frame(s); + /* update the status bits of the TD */ + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); + uhci_async_free(s, async); + } else { + async->done = 1; + uhci_process_frame(s); + } } static int is_valid(uint32_t link) @@ -1005,13 +1046,15 @@ static void uhci_process_frame(UHCIState *s) /* go to the next entry */ } - s->pending_int_mask = int_mask; + s->pending_int_mask |= int_mask; } static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; - int64_t expire_time; + + /* prepare the timer for the next frame */ + s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); if (!(s->cmd & UHCI_CMD_RS)) { /* Full stop */ @@ -1029,6 +1072,7 @@ static void uhci_frame_timer(void *opaque) s->status |= UHCI_STS_USBINT; uhci_update_irq(s); } + s->pending_int_mask = 0; /* Start new frame */ s->frnum = (s->frnum + 1) & 0x7ff; @@ -1041,10 +1085,7 @@ static void uhci_frame_timer(void *opaque) uhci_async_validate_end(s); - /* prepare the timer for the next frame */ - expire_time = qemu_get_clock(vm_clock) + - (get_ticks_per_sec() / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, expire_time); + qemu_mod_timer(s->frame_timer, s->expire_time); } static void uhci_map(PCIDevice *pci_dev, int region_num, @@ -1078,6 +1119,8 @@ static int usb_uhci_common_initfn(UHCIState *s) usb_register_port(&s->bus, &s->ports[i].port, s, i, uhci_attach); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); + s->expire_time = qemu_get_clock(vm_clock) + + (get_ticks_per_sec() / FRAME_TIMER_FREQ); s->num_ports_vmstate = NB_PORTS; qemu_register_reset(uhci_reset, s); diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 037a79c5ff..b80402d0fd 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -25,9 +25,8 @@ typedef struct VirtIOBlock BlockDriverState *bs; VirtQueue *vq; void *rq; - char serial_str[BLOCK_SERIAL_STRLEN + 1]; QEMUBH *bh; - size_t config_size; + BlockConf *conf; } VirtIOBlock; static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) @@ -35,47 +34,6 @@ static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) return (VirtIOBlock *)vdev; } -/* store identify data in little endian format - */ -static inline void put_le16(uint16_t *p, unsigned int v) -{ - *p = cpu_to_le16(v); -} - -/* copy to *dst from *src, nul pad dst tail as needed to len bytes - */ -static inline void padstr(char *dst, const char *src, int len) -{ - while (len--) - *dst++ = *src ? *src++ : '\0'; -} - -/* setup simulated identify data as appropriate for virtio block device - * - * ref: AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) - */ -static inline void virtio_identify_template(struct virtio_blk_config *bc) -{ - uint16_t *p = &bc->identify[0]; - uint64_t lba_sectors = bc->capacity; - - memset(p, 0, sizeof(bc->identify)); - put_le16(p + 0, 0x0); /* ATA device */ - padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware revision */ - padstr((char *)(p + 27), "QEMU VIRT_BLK", 40); /* model# */ - put_le16(p + 47, 0x80ff); /* max xfer 255 sectors */ - put_le16(p + 49, 0x0b00); /* support IORDY/LBA/DMA */ - put_le16(p + 59, 0x1ff); /* cur xfer 255 sectors */ - put_le16(p + 80, 0x1f0); /* support ATA8/7/6/5/4 */ - put_le16(p + 81, 0x16); - put_le16(p + 82, 0x400); - put_le16(p + 83, 0x400); - put_le16(p + 100, lba_sectors); - put_le16(p + 101, lba_sectors >> 16); - put_le16(p + 102, lba_sectors >> 32); - put_le16(p + 103, lba_sectors >> 48); -} - typedef struct VirtIOBlockReq { VirtIOBlock *dev; @@ -105,16 +63,20 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, drive_get_on_error(req->dev->bs, is_read); VirtIOBlock *s = req->dev; - if (action == BLOCK_ERR_IGNORE) + if (action == BLOCK_ERR_IGNORE) { + bdrv_mon_event(req->dev->bs, BDRV_ACTION_IGNORE, is_read); return 0; + } if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) || action == BLOCK_ERR_STOP_ANY) { req->next = s->rq; s->rq = req; vm_stop(0); + bdrv_mon_event(req->dev->bs, BDRV_ACTION_STOP, is_read); } else { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); + bdrv_mon_event(req->dev->bs, BDRV_ACTION_REPORT, is_read); } return 1; @@ -444,10 +406,11 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) blkcfg.heads = heads; blkcfg.sectors = secs; blkcfg.size_max = 0; - virtio_identify_template(&blkcfg); - memcpy(&blkcfg.identify[VIRTIO_BLK_ID_SN], s->serial_str, - VIRTIO_BLK_ID_SN_BYTES); - memcpy(config, &blkcfg, s->config_size); + blkcfg.physical_block_exp = get_physical_block_exp(s->conf); + blkcfg.alignment_offset = 0; + blkcfg.min_io_size = s->conf->min_io_size / 512; + blkcfg.opt_io_size = s->conf->opt_io_size / 512; + memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); } static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) @@ -456,11 +419,10 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_SEG_MAX); features |= (1 << VIRTIO_BLK_F_GEOMETRY); + features |= (1 << VIRTIO_BLK_F_TOPOLOGY); if (bdrv_enable_write_cache(s->bs)) features |= (1 << VIRTIO_BLK_F_WCACHE); - if (strcmp(s->serial_str, "0")) - features |= 1 << VIRTIO_BLK_F_IDENTIFY; if (bdrv_is_read_only(s->bs)) features |= 1 << VIRTIO_BLK_F_RO; @@ -501,29 +463,22 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) return 0; } -VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo) +VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf) { VirtIOBlock *s; int cylinders, heads, secs; static int virtio_blk_id; - char *ps = (char *)drive_get_serial(dinfo->bdrv); - size_t size = strlen(ps) ? sizeof(struct virtio_blk_config) : - offsetof(struct virtio_blk_config, _blk_size); s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, - size, + sizeof(struct virtio_blk_config), sizeof(VirtIOBlock)); - s->config_size = size; s->vdev.get_config = virtio_blk_update_config; s->vdev.get_features = virtio_blk_get_features; s->vdev.reset = virtio_blk_reset; - s->bs = dinfo->bdrv; + s->bs = conf->dinfo->bdrv; + s->conf = conf; s->rq = NULL; - if (strlen(ps)) - strncpy(s->serial_str, ps, sizeof(s->serial_str)); - else - snprintf(s->serial_str, sizeof(s->serial_str), "0"); bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); bdrv_set_geometry_hint(s->bs, cylinders, heads, secs); diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index c28f776c2e..f675375399 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -30,12 +30,9 @@ #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ -#define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */ +/* #define VIRTIO_BLK_F_IDENTIFY 8 ATA IDENTIFY supported, DEPRECATED */ #define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */ - -#define VIRTIO_BLK_ID_LEN 256 /* length of identify u16 array */ -#define VIRTIO_BLK_ID_SN 10 /* start of char * serial# */ -#define VIRTIO_BLK_ID_SN_BYTES 20 /* length in bytes of serial# */ +#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ struct virtio_blk_config { @@ -46,7 +43,10 @@ struct virtio_blk_config uint8_t heads; uint8_t sectors; uint32_t _blk_size; /* structure pad, currently unused */ - uint16_t identify[VIRTIO_BLK_ID_LEN]; + uint8_t physical_block_exp; + uint8_t alignment_offset; + uint16_t min_io_size; + uint32_t opt_io_size; } __attribute__((packed)); /* These two define direction. */ diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 6e48997c0e..5c0093e879 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -379,7 +379,15 @@ static int virtio_net_has_buffers(VirtIONet *n, int bufsize) (n->mergeable_rx_bufs && !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) { virtio_queue_set_notification(n->rx_vq, 1); - return 0; + + /* To avoid a race condition where the guest has made some buffers + * available after the above check but before notification was + * enabled, check for available buffers again. + */ + if (virtio_queue_empty(n->rx_vq) || + (n->mergeable_rx_bufs && + !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) + return 0; } virtio_queue_set_notification(n->rx_vq, 0); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 709d13e4ce..f3373ae50e 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -22,6 +22,7 @@ #include "sysemu.h" #include "msix.h" #include "net.h" +#include "block_int.h" #include "loader.h" /* from Linux's linux/virtio_pci.h */ @@ -92,7 +93,7 @@ typedef struct { uint32_t addr; uint32_t class_code; uint32_t nvectors; - DriveInfo *dinfo; + BlockConf block; NICConf nic; uint32_t host_features; /* Max. number of ports we can have for a the virtio-serial device */ @@ -457,11 +458,11 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) proxy->class_code != PCI_CLASS_STORAGE_OTHER) proxy->class_code = PCI_CLASS_STORAGE_SCSI; - if (!proxy->dinfo) { + if (!proxy->block.dinfo) { qemu_error("virtio-blk-pci: drive property not set\n"); return -1; } - vdev = virtio_blk_init(&pci_dev->qdev, proxy->dinfo); + vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block); vdev->nvectors = proxy->nvectors; virtio_init_pci(proxy, vdev, PCI_VENDOR_ID_REDHAT_QUMRANET, @@ -481,7 +482,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); - drive_uninit(proxy->dinfo); + drive_uninit(proxy->block.dinfo); return virtio_exit_pci(pci_dev); } @@ -558,7 +559,7 @@ static PCIDeviceInfo virtio_info[] = { .exit = virtio_blk_exit_pci, .qdev.props = (Property[]) { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_DRIVE("drive", VirtIOPCIProxy, dinfo), + DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/virtio.h b/hw/virtio.h index 62e882bb67..3baa2a34da 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -18,6 +18,7 @@ #include "net.h" #include "qdev.h" #include "sysemu.h" +#include "block_int.h" /* from Linux's linux/virtio_config.h */ @@ -169,7 +170,7 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, void *opaque); /* Base devices. */ -VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo); +VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf); VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf); VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports); VirtIODevice *virtio_balloon_init(DeviceState *dev); diff --git a/hw/vmport.c b/hw/vmport.c index 884af3fd91..6c9d7c9651 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -25,6 +25,7 @@ #include "isa.h" #include "pc.h" #include "sysemu.h" +#include "kvm.h" //#define VMPORT_DEBUG @@ -58,6 +59,8 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) unsigned char command; uint32_t eax; + cpu_synchronize_state(env); + eax = env->regs[R_EAX]; if (eax != VMPORT_MAGIC) return eax; diff --git a/json-lexer.c b/json-lexer.c index 53697c5ffe..9d649205a7 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -54,6 +54,9 @@ enum json_lexer_state { IN_ESCAPE, IN_ESCAPE_L, IN_ESCAPE_LL, + IN_ESCAPE_I, + IN_ESCAPE_I6, + IN_ESCAPE_I64, IN_ESCAPE_DONE, IN_WHITESPACE, IN_OPERATOR_DONE, @@ -223,6 +226,18 @@ static const uint8_t json_lexer[][256] = { ['l'] = IN_ESCAPE_LL, }, + [IN_ESCAPE_I64] = { + ['d'] = IN_ESCAPE_DONE, + }, + + [IN_ESCAPE_I6] = { + ['4'] = IN_ESCAPE_I64, + }, + + [IN_ESCAPE_I] = { + ['6'] = IN_ESCAPE_I6, + }, + [IN_ESCAPE] = { ['d'] = IN_ESCAPE_DONE, ['i'] = IN_ESCAPE_DONE, @@ -230,6 +245,7 @@ static const uint8_t json_lexer[][256] = { ['s'] = IN_ESCAPE_DONE, ['f'] = IN_ESCAPE_DONE, ['l'] = IN_ESCAPE_L, + ['I'] = IN_ESCAPE_I, }, /* top level rule */ diff --git a/json-parser.c b/json-parser.c index e04932f907..f3debcb6ef 100644 --- a/json-parser.c +++ b/json-parser.c @@ -474,7 +474,8 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a obj = QOBJECT(qint_from_int(va_arg(*ap, int))); } else if (token_is_escape(token, "%ld")) { obj = QOBJECT(qint_from_int(va_arg(*ap, long))); - } else if (token_is_escape(token, "%lld")) { + } else if (token_is_escape(token, "%lld") || + token_is_escape(token, "%I64d")) { obj = QOBJECT(qint_from_int(va_arg(*ap, long long))); } else if (token_is_escape(token, "%s")) { obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *))); @@ -57,8 +57,10 @@ struct KVMState KVMSlot slots[32]; int fd; int vmfd; - int regs_modified; int coalesced_mmio; +#ifdef KVM_CAP_COALESCED_MMIO + struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; +#endif int broken_set_mem_region; int migration_log; int vcpu_events; @@ -200,6 +202,12 @@ int kvm_init_vcpu(CPUState *env) goto err; } +#ifdef KVM_CAP_COALESCED_MMIO + if (s->coalesced_mmio && !s->coalesced_mmio_ring) + s->coalesced_mmio_ring = (void *) env->kvm_run + + s->coalesced_mmio * PAGE_SIZE; +#endif + ret = kvm_arch_init_vcpu(env); if (ret == 0) { qemu_register_reset(kvm_reset_vcpu, env); @@ -257,7 +265,7 @@ int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size) KVM_MEM_LOG_DIRTY_PAGES); } -int kvm_set_migration_log(int enable) +static int kvm_set_migration_log(int enable) { KVMState *s = kvm_state; KVMSlot *mem; @@ -292,8 +300,8 @@ static int test_le_bit(unsigned long nr, unsigned char *addr) * @start_add: start of logged region. * @end_addr: end of logged region. */ -int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr) +static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr) { KVMState *s = kvm_state; unsigned long size, allocated_size = 0; @@ -394,6 +402,171 @@ int kvm_check_extension(KVMState *s, unsigned int extension) return ret; } +static void kvm_set_phys_mem(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset) +{ + KVMState *s = kvm_state; + ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; + KVMSlot *mem, old; + int err; + + if (start_addr & ~TARGET_PAGE_MASK) { + if (flags >= IO_MEM_UNASSIGNED) { + if (!kvm_lookup_overlapping_slot(s, start_addr, + start_addr + size)) { + return; + } + fprintf(stderr, "Unaligned split of a KVM memory slot\n"); + } else { + fprintf(stderr, "Only page-aligned memory slots supported\n"); + } + abort(); + } + + /* KVM does not support read-only slots */ + phys_offset &= ~IO_MEM_ROM; + + while (1) { + mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); + if (!mem) { + break; + } + + if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && + (start_addr + size <= mem->start_addr + mem->memory_size) && + (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { + /* The new slot fits into the existing one and comes with + * identical parameters - nothing to be done. */ + return; + } + + old = *mem; + + /* unregister the overlapping slot */ + mem->memory_size = 0; + err = kvm_set_user_memory_region(s, mem); + if (err) { + fprintf(stderr, "%s: error unregistering overlapping slot: %s\n", + __func__, strerror(-err)); + abort(); + } + + /* Workaround for older KVM versions: we can't join slots, even not by + * unregistering the previous ones and then registering the larger + * slot. We have to maintain the existing fragmentation. Sigh. + * + * This workaround assumes that the new slot starts at the same + * address as the first existing one. If not or if some overlapping + * slot comes around later, we will fail (not seen in practice so far) + * - and actually require a recent KVM version. */ + if (s->broken_set_mem_region && + old.start_addr == start_addr && old.memory_size < size && + flags < IO_MEM_UNASSIGNED) { + mem = kvm_alloc_slot(s); + mem->memory_size = old.memory_size; + mem->start_addr = old.start_addr; + mem->phys_offset = old.phys_offset; + mem->flags = 0; + + err = kvm_set_user_memory_region(s, mem); + if (err) { + fprintf(stderr, "%s: error updating slot: %s\n", __func__, + strerror(-err)); + abort(); + } + + start_addr += old.memory_size; + phys_offset += old.memory_size; + size -= old.memory_size; + continue; + } + + /* register prefix slot */ + if (old.start_addr < start_addr) { + mem = kvm_alloc_slot(s); + mem->memory_size = start_addr - old.start_addr; + mem->start_addr = old.start_addr; + mem->phys_offset = old.phys_offset; + mem->flags = 0; + + err = kvm_set_user_memory_region(s, mem); + if (err) { + fprintf(stderr, "%s: error registering prefix slot: %s\n", + __func__, strerror(-err)); + abort(); + } + } + + /* register suffix slot */ + if (old.start_addr + old.memory_size > start_addr + size) { + ram_addr_t size_delta; + + mem = kvm_alloc_slot(s); + mem->start_addr = start_addr + size; + size_delta = mem->start_addr - old.start_addr; + mem->memory_size = old.memory_size - size_delta; + mem->phys_offset = old.phys_offset + size_delta; + mem->flags = 0; + + err = kvm_set_user_memory_region(s, mem); + if (err) { + fprintf(stderr, "%s: error registering suffix slot: %s\n", + __func__, strerror(-err)); + abort(); + } + } + } + + /* in case the KVM bug workaround already "consumed" the new slot */ + if (!size) + return; + + /* KVM does not need to know about this memory */ + if (flags >= IO_MEM_UNASSIGNED) + return; + + mem = kvm_alloc_slot(s); + mem->memory_size = size; + mem->start_addr = start_addr; + mem->phys_offset = phys_offset; + mem->flags = 0; + + err = kvm_set_user_memory_region(s, mem); + if (err) { + fprintf(stderr, "%s: error registering slot: %s\n", __func__, + strerror(-err)); + abort(); + } +} + +static void kvm_client_set_memory(struct CPUPhysMemoryClient *client, + target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset) +{ + kvm_set_phys_mem(start_addr, size, phys_offset); +} + +static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client, + target_phys_addr_t start_addr, + target_phys_addr_t end_addr) +{ + return kvm_physical_sync_dirty_bitmap(start_addr, end_addr); +} + +static int kvm_client_migration_log(struct CPUPhysMemoryClient *client, + int enable) +{ + return kvm_set_migration_log(enable); +} + +static CPUPhysMemoryClient kvm_cpu_phys_memory_client = { + .set_memory = kvm_client_set_memory, + .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap, + .migration_log = kvm_client_migration_log, +}; + int kvm_init(int smp_cpus) { static const char upgrade_note[] = @@ -466,10 +639,10 @@ int kvm_init(int smp_cpus) goto err; } + s->coalesced_mmio = 0; #ifdef KVM_CAP_COALESCED_MMIO s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO); -#else - s->coalesced_mmio = 0; + s->coalesced_mmio_ring = NULL; #endif s->broken_set_mem_region = 1; @@ -490,6 +663,7 @@ int kvm_init(int smp_cpus) goto err; kvm_state = s; + cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client); return 0; @@ -544,14 +718,12 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size, return 1; } -static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run) +void kvm_flush_coalesced_mmio_buffer(void) { #ifdef KVM_CAP_COALESCED_MMIO KVMState *s = kvm_state; - if (s->coalesced_mmio) { - struct kvm_coalesced_mmio_ring *ring; - - ring = (void *)run + (s->coalesced_mmio * TARGET_PAGE_SIZE); + if (s->coalesced_mmio_ring) { + struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring; while (ring->first != ring->last) { struct kvm_coalesced_mmio *ent; @@ -567,9 +739,9 @@ static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run) void kvm_cpu_synchronize_state(CPUState *env) { - if (!env->kvm_state->regs_modified) { + if (!env->kvm_vcpu_dirty) { kvm_arch_get_registers(env); - env->kvm_state->regs_modified = 1; + env->kvm_vcpu_dirty = 1; } } @@ -587,9 +759,9 @@ int kvm_cpu_exec(CPUState *env) break; } - if (env->kvm_state->regs_modified) { + if (env->kvm_vcpu_dirty) { kvm_arch_put_registers(env); - env->kvm_state->regs_modified = 0; + env->kvm_vcpu_dirty = 0; } kvm_arch_pre_run(env, run); @@ -609,7 +781,7 @@ int kvm_cpu_exec(CPUState *env) abort(); } - kvm_run_coalesced_mmio(env, run); + kvm_flush_coalesced_mmio_buffer(); ret = 0; /* exit loop */ switch (run->exit_reason) { @@ -674,144 +846,6 @@ int kvm_cpu_exec(CPUState *env) return ret; } -void kvm_set_phys_mem(target_phys_addr_t start_addr, - ram_addr_t size, - ram_addr_t phys_offset) -{ - KVMState *s = kvm_state; - ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; - KVMSlot *mem, old; - int err; - - if (start_addr & ~TARGET_PAGE_MASK) { - if (flags >= IO_MEM_UNASSIGNED) { - if (!kvm_lookup_overlapping_slot(s, start_addr, - start_addr + size)) { - return; - } - fprintf(stderr, "Unaligned split of a KVM memory slot\n"); - } else { - fprintf(stderr, "Only page-aligned memory slots supported\n"); - } - abort(); - } - - /* KVM does not support read-only slots */ - phys_offset &= ~IO_MEM_ROM; - - while (1) { - mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); - if (!mem) { - break; - } - - if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && - (start_addr + size <= mem->start_addr + mem->memory_size) && - (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { - /* The new slot fits into the existing one and comes with - * identical parameters - nothing to be done. */ - return; - } - - old = *mem; - - /* unregister the overlapping slot */ - mem->memory_size = 0; - err = kvm_set_user_memory_region(s, mem); - if (err) { - fprintf(stderr, "%s: error unregistering overlapping slot: %s\n", - __func__, strerror(-err)); - abort(); - } - - /* Workaround for older KVM versions: we can't join slots, even not by - * unregistering the previous ones and then registering the larger - * slot. We have to maintain the existing fragmentation. Sigh. - * - * This workaround assumes that the new slot starts at the same - * address as the first existing one. If not or if some overlapping - * slot comes around later, we will fail (not seen in practice so far) - * - and actually require a recent KVM version. */ - if (s->broken_set_mem_region && - old.start_addr == start_addr && old.memory_size < size && - flags < IO_MEM_UNASSIGNED) { - mem = kvm_alloc_slot(s); - mem->memory_size = old.memory_size; - mem->start_addr = old.start_addr; - mem->phys_offset = old.phys_offset; - mem->flags = 0; - - err = kvm_set_user_memory_region(s, mem); - if (err) { - fprintf(stderr, "%s: error updating slot: %s\n", __func__, - strerror(-err)); - abort(); - } - - start_addr += old.memory_size; - phys_offset += old.memory_size; - size -= old.memory_size; - continue; - } - - /* register prefix slot */ - if (old.start_addr < start_addr) { - mem = kvm_alloc_slot(s); - mem->memory_size = start_addr - old.start_addr; - mem->start_addr = old.start_addr; - mem->phys_offset = old.phys_offset; - mem->flags = 0; - - err = kvm_set_user_memory_region(s, mem); - if (err) { - fprintf(stderr, "%s: error registering prefix slot: %s\n", - __func__, strerror(-err)); - abort(); - } - } - - /* register suffix slot */ - if (old.start_addr + old.memory_size > start_addr + size) { - ram_addr_t size_delta; - - mem = kvm_alloc_slot(s); - mem->start_addr = start_addr + size; - size_delta = mem->start_addr - old.start_addr; - mem->memory_size = old.memory_size - size_delta; - mem->phys_offset = old.phys_offset + size_delta; - mem->flags = 0; - - err = kvm_set_user_memory_region(s, mem); - if (err) { - fprintf(stderr, "%s: error registering suffix slot: %s\n", - __func__, strerror(-err)); - abort(); - } - } - } - - /* in case the KVM bug workaround already "consumed" the new slot */ - if (!size) - return; - - /* KVM does not need to know about this memory */ - if (flags >= IO_MEM_UNASSIGNED) - return; - - mem = kvm_alloc_slot(s); - mem->memory_size = size; - mem->start_addr = start_addr; - mem->phys_offset = phys_offset; - mem->flags = 0; - - err = kvm_set_user_memory_region(s, mem); - if (err) { - fprintf(stderr, "%s: error registering slot: %s\n", __func__, - strerror(-err)); - abort(); - } -} - int kvm_ioctl(KVMState *s, int type, ...) { int ret; @@ -901,14 +935,11 @@ void kvm_setup_guest_memory(void *start, size_t size) static void on_vcpu(CPUState *env, void (*func)(void *data), void *data) { #ifdef CONFIG_IOTHREAD - if (env == cpu_single_env) { - func(data); - return; + if (env != cpu_single_env) { + abort(); } - abort(); -#else - func(data); #endif + func(data); } struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, @@ -939,9 +970,9 @@ static void kvm_invoke_set_guest_debug(void *data) struct kvm_set_guest_debug_data *dbg_data = data; CPUState *env = dbg_data->env; - if (env->kvm_state->regs_modified) { + if (env->kvm_vcpu_dirty) { kvm_arch_put_registers(env); - env->kvm_state->regs_modified = 0; + env->kvm_vcpu_dirty = 0; } dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); } @@ -35,16 +35,8 @@ int kvm_init_vcpu(CPUState *env); int kvm_cpu_exec(CPUState *env); -void kvm_set_phys_mem(target_phys_addr_t start_addr, - ram_addr_t size, - ram_addr_t phys_offset); - -int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr); - int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size); int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); -int kvm_set_migration_log(int enable); int kvm_has_sync_mmu(void); int kvm_has_vcpu_events(void); @@ -53,6 +45,7 @@ void kvm_setup_guest_memory(void *start, size_t size); int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); +void kvm_flush_coalesced_mmio_buffer(void); int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, target_ulong len, int type); diff --git a/migration.c b/migration.c index f20315fcfd..2320c5fdf4 100644 --- a/migration.c +++ b/migration.c @@ -183,8 +183,6 @@ static void migrate_put_status(QDict *qdict, const char *name, obj = qobject_from_jsonf("{ 'transferred': %" PRId64 ", " "'remaining': %" PRId64 ", " "'total': %" PRId64 " }", trans, rem, total); - assert(obj != NULL); - qdict_put_obj(qdict, name, obj); } @@ -258,7 +256,6 @@ void do_info_migrate(Monitor *mon, QObject **ret_data) *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }"); break; } - assert(*ret_data != NULL); } } @@ -122,6 +122,7 @@ typedef struct MonitorControl { QObject *id; int print_enabled; JSONMessageParser parser; + int command_mode; } MonitorControl; struct Monitor { @@ -152,6 +153,11 @@ Monitor *cur_mon = NULL; static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque); +static inline int qmp_cmd_mode(const Monitor *mon) +{ + return (mon->mc ? mon->mc->command_mode : 0); +} + /* Return true if in control mode, false otherwise */ static inline int monitor_ctrl_mode(const Monitor *mon) { @@ -345,8 +351,6 @@ static void timestamp_put(QDict *qdict) obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", " "'microseconds': %" PRId64 " }", (int64_t) tv.tv_sec, (int64_t) tv.tv_usec); - assert(obj != NULL); - qdict_put_obj(qdict, "timestamp", obj); } @@ -388,6 +392,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) case QEVENT_VNC_DISCONNECTED: event_name = "VNC_DISCONNECTED"; break; + case QEVENT_BLOCK_IO_ERROR: + event_name = "BLOCK_IO_ERROR"; + break; default: abort(); break; @@ -402,13 +409,22 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) } QLIST_FOREACH(mon, &mon_list, entry) { - if (monitor_ctrl_mode(mon)) { + if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) { monitor_json_emitter(mon, QOBJECT(qmp)); } } QDECREF(qmp); } +static void do_qmp_capabilities(Monitor *mon, const QDict *params, + QObject **ret_data) +{ + /* Will setup QMP capabilities in the future */ + if (monitor_ctrl_mode(mon)) { + mon->mc->command_mode = 1; + } +} + static int compare_cmd(const char *name, const char *list) { const char *p, *pstart; @@ -882,7 +898,6 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data) obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }", env->cpu_index, env == mon->mon_cpu, env->halted); - assert(obj != NULL); cpu = qobject_to_qdict(obj); @@ -4219,6 +4234,12 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) return err; } +static int invalid_qmp_mode(const Monitor *mon, const char *cmd_name) +{ + int is_cap = compare_cmd(cmd_name, "qmp_capabilities"); + return (qmp_cmd_mode(mon) ? is_cap : !is_cap); +} + static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) { int err; @@ -4258,6 +4279,11 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) cmd_name = qstring_get_str(qobject_to_qstring(obj)); + if (invalid_qmp_mode(mon, cmd_name)) { + qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + goto err_input; + } + /* * XXX: We need this special case until we get info handlers * converted into 'query-' commands @@ -4365,22 +4391,33 @@ void monitor_resume(Monitor *mon) readline_show_prompt(mon->rs); } +static QObject *get_qmp_greeting(void) +{ + QObject *ver; + + do_info_version(NULL, &ver); + return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver); +} + /** * monitor_control_event(): Print QMP gretting */ static void monitor_control_event(void *opaque, int event) { - if (event == CHR_EVENT_OPENED) { - QObject *data; - Monitor *mon = opaque; + QObject *data; + Monitor *mon = opaque; + switch (event) { + case CHR_EVENT_OPENED: + mon->mc->command_mode = 0; json_message_parser_init(&mon->mc->parser, handle_qmp_command); - - data = qobject_from_jsonf("{ 'QMP': { 'capabilities': [] } }"); - assert(data != NULL); - + data = get_qmp_greeting(); monitor_json_emitter(mon, data); qobject_decref(data); + break; + case CHR_EVENT_CLOSED: + json_message_parser_destroy(&mon->mc->parser); + break; } } @@ -4595,8 +4632,13 @@ void qemu_error_internal(const char *file, int linenr, const char *func, QDECREF(qerror); break; case ERR_SINK_MONITOR: - assert(qemu_error_sink->mon->error == NULL); - qemu_error_sink->mon->error = qerror; + /* report only the first error */ + if (!qemu_error_sink->mon->error) { + qemu_error_sink->mon->error = qerror; + } else { + /* XXX: warn the programmer */ + QDECREF(qerror); + } break; } } @@ -23,6 +23,7 @@ typedef enum MonitorEvent { QEVENT_VNC_CONNECTED, QEVENT_VNC_INITIALIZED, QEVENT_VNC_DISCONNECTED, + QEVENT_BLOCK_IO_ERROR, QEVENT_MAX, } MonitorEvent; @@ -96,7 +96,7 @@ int parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *input_str) { - char *str = strdup(input_str); + char *str = qemu_strdup(input_str); char *host_str = str; char *src_str; const char *src_str2; @@ -28,14 +28,15 @@ #include <errno.h> #include <unistd.h> #include <fcntl.h> + +/* Needed early for CONFIG_BSD etc. */ +#include "config-host.h" + #ifdef CONFIG_SOLARIS #include <sys/types.h> #include <sys/statvfs.h> #endif -/* Needed early for CONFIG_BSD etc. */ -#include "config-host.h" - #ifdef _WIN32 #include <windows.h> #elif defined(CONFIG_BSD) diff --git a/qemu-char.c b/qemu-char.c index 800ee6c503..75dbf66858 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1180,6 +1180,9 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) int fd; TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); + if (fd < 0) { + return NULL; + } tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); if (!chr) { diff --git a/qemu-doc.texi b/qemu-doc.texi index 2fb5c0b249..1494757f25 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1,11 +1,21 @@ \input texinfo @c -*- texinfo -*- @c %**start of header @setfilename qemu-doc.info + +@documentlanguage en +@documentencoding UTF-8 + @settitle QEMU Emulator User Documentation @exampleindent 0 @paragraphindent 0 @c %**end of header +@ifinfo +@direntry +* QEMU: (qemu-doc). The QEMU Emulator User Documentation. +@end direntry +@end ifinfo + @iftex @titlepage @sp 7 @@ -27,6 +37,7 @@ * QEMU System emulator for non PC targets:: * QEMU User space emulator:: * compilation:: Compilation from the sources +* License:: * Index:: @end menu @end ifnottex @@ -48,15 +59,18 @@ achieve good emulation speed. QEMU has two operating modes: -@itemize @minus +@itemize +@cindex operating modes @item +@cindex system emulation Full system emulation. In this mode, QEMU emulates a full system (for example a PC), including one or several processors and various peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code. @item +@cindex user mode emulation User mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (@url{http://www.winehq.org}) or @@ -69,6 +83,8 @@ performance. For system emulation, the following hardware targets are supported: @itemize +@cindex emulated target systems +@cindex supported target systems @item PC (x86 or x86_64 processor) @item ISA PC (old style PC without PCI bus) @item PREP (PowerPC processor) @@ -96,7 +112,10 @@ For system emulation, the following hardware targets are supported: @item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze). @end itemize -For user emulation, x86, PowerPC, ARM, 32-bit MIPS, Sparc32/64, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported. +@cindex supported user mode targets +For user emulation, x86 (32 and 64 bit), PowerPC (32 and 64 bit), +ARM, MIPS (32 bit only), Sparc (32 and 64 bit), +Alpha, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported. @node Installation @chapter Installation @@ -111,24 +130,29 @@ If you want to compile QEMU yourself, see @ref{compilation}. @node install_linux @section Linux +@cindex installation (Linux) If a precompiled package is available for your distribution - you just have to install it. Otherwise, see @ref{compilation}. @node install_windows @section Windows +@cindex installation (Windows) Download the experimental binary installer at @url{http://www.free.oszoo.org/@/download.html}. +TODO (no longer available) @node install_mac @section Mac OS X Download the experimental binary installer at @url{http://www.free.oszoo.org/@/download.html}. +TODO (no longer available) @node QEMU PC System emulator @chapter QEMU PC System emulator +@cindex system emulation (PC) @menu * pcsys_introduction:: Introduction @@ -219,6 +243,7 @@ CS4231A is the chip used in Windows Sound System and GUSMAX products @node pcsys_quickstart @section Quick Start +@cindex quick start Download and uncompress the linux image (@file{linux.img}) and type: @@ -253,12 +278,15 @@ targets do not need a disk image. During the graphical emulation, you can use the following keys: @table @key @item Ctrl-Alt-f +@kindex Ctrl-Alt-f Toggle full screen @item Ctrl-Alt-u +@kindex Ctrl-Alt-u Restore the screen's un-scaled dimensions @item Ctrl-Alt-n +@kindex Ctrl-Alt-n Switch to virtual console 'n'. Standard console mappings are: @table @emph @item 1 @@ -270,30 +298,44 @@ Serial port @end table @item Ctrl-Alt +@kindex Ctrl-Alt Toggle mouse and keyboard grab. @end table +@kindex Ctrl-Up +@kindex Ctrl-Down +@kindex Ctrl-PageUp +@kindex Ctrl-PageDown In the virtual consoles, you can use @key{Ctrl-Up}, @key{Ctrl-Down}, @key{Ctrl-PageUp} and @key{Ctrl-PageDown} to move in the back log. +@kindex Ctrl-a h During emulation, if you are using the @option{-nographic} option, use @key{Ctrl-a h} to get terminal commands: @table @key @item Ctrl-a h +@kindex Ctrl-a h @item Ctrl-a ? +@kindex Ctrl-a ? Print this help @item Ctrl-a x +@kindex Ctrl-a x Exit emulator @item Ctrl-a s +@kindex Ctrl-a s Save disk data back to file (if -snapshot) @item Ctrl-a t +@kindex Ctrl-a t Toggle console timestamps @item Ctrl-a b +@kindex Ctrl-a b Send break (magic sysrq in Linux) @item Ctrl-a c +@kindex Ctrl-a c Switch between console and monitor @item Ctrl-a Ctrl-a +@kindex Ctrl-a a Send Ctrl-a @end table @c man end @@ -313,6 +355,7 @@ Fabrice Bellard @node pcsys_monitor @section QEMU Monitor +@cindex QEMU monitor The QEMU monitor is used to give complex commands to the QEMU emulator. You can use it to: @@ -1276,16 +1319,20 @@ machines. Most of the options are similar to the PC emulator. The differences are mentioned in the following sections. @menu -* QEMU PowerPC System emulator:: +* PowerPC System emulator:: * Sparc32 System emulator:: * Sparc64 System emulator:: * MIPS System emulator:: * ARM System emulator:: * ColdFire System emulator:: +* Cris System emulator:: +* Microblaze System emulator:: +* SH4 System emulator:: @end menu -@node QEMU PowerPC System emulator -@section QEMU PowerPC System emulator +@node PowerPC System emulator +@section PowerPC System emulator +@cindex system emulation (PowerPC) Use the executable @file{qemu-system-ppc} to simulate a complete PREP or PowerMac PowerPC system. @@ -1368,6 +1415,7 @@ More information is available at @node Sparc32 System emulator @section Sparc32 System emulator +@cindex system emulation (Sparc32) Use the executable @file{qemu-system-sparc} to simulate the following Sun4m architecture machines: @@ -1466,6 +1514,7 @@ Set the emulated machine type. Default is SS-5. @node Sparc64 System emulator @section Sparc64 System emulator +@cindex system emulation (Sparc64) Use the executable @file{qemu-system-sparc64} to simulate a Sun4u (UltraSPARC PC-like machine), Sun4v (T1 PC-like machine), or generic @@ -1515,6 +1564,7 @@ Set the emulated machine type. The default is sun4u. @node MIPS System emulator @section MIPS System emulator +@cindex system emulation (MIPS) Four executables cover simulation of 32 and 64-bit MIPS systems in both endian options, @file{qemu-system-mips}, @file{qemu-system-mipsel} @@ -1610,6 +1660,7 @@ G364 framebuffer @node ARM System emulator @section ARM System emulator +@cindex system emulation (ARM) Use the executable @file{qemu-system-arm} to simulate a ARM machine. The ARM Integrator/CP board is emulated with the following @@ -1825,7 +1876,7 @@ MV88W8xx8 Ethernet controller @item MV88W8618 audio controller, WM8750 CODEC and mixer @item -128×64 display with brightness control +128×64 display with brightness control @item 2 buttons, 2 navigation wheels with button function @end itemize @@ -1895,6 +1946,8 @@ so should only be used with trusted guest OS. @node ColdFire System emulator @section ColdFire System emulator +@cindex system emulation (ColdFire) +@cindex system emulation (M68K) Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine. The emulator is able to boot a uClinux kernel. @@ -1921,7 +1974,7 @@ Two on-chip UARTs. @c man begin OPTIONS -The following options are specific to the ARM emulation: +The following options are specific to the ColdFire emulation: @table @option @@ -1935,6 +1988,24 @@ so should only be used with trusted guest OS. @end table +@node Cris System emulator +@section Cris System emulator +@cindex system emulation (Cris) + +TODO + +@node Microblaze System emulator +@section Microblaze System emulator +@cindex system emulation (Microblaze) + +TODO + +@node SH4 System emulator +@section SH4 System emulator +@cindex system emulation (SH4) + +TODO + @node QEMU User space emulator @chapter QEMU User space emulator @@ -2099,16 +2170,49 @@ flag-style arguments don't have decoders and will show up as numbers. @node Other binaries @subsection Other binaries +@cindex user mode (Alpha) +@command{qemu-alpha} TODO. + +@cindex user mode (ARM) +@command{qemu-armeb} TODO. + +@cindex user mode (ARM) @command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB configurations), and arm-uclinux bFLT format binaries. +@cindex user mode (ColdFire) +@cindex user mode (M68K) @command{qemu-m68k} is capable of running semihosted binaries using the BDM (m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and coldfire uClinux bFLT format binaries. The binary format is detected automatically. +@cindex user mode (Cris) +@command{qemu-cris} TODO. + +@cindex user mode (i386) +@command{qemu-i386} TODO. +@command{qemu-x86_64} TODO. + +@cindex user mode (Microblaze) +@command{qemu-microblaze} TODO. + +@cindex user mode (MIPS) +@command{qemu-mips} TODO. +@command{qemu-mipsel} TODO. + +@cindex user mode (PowerPC) +@command{qemu-ppc64abi32} TODO. +@command{qemu-ppc64} TODO. +@command{qemu-ppc} TODO. + +@cindex user mode (SH4) +@command{qemu-sh4eb} TODO. +@command{qemu-sh4} TODO. + +@cindex user mode (SPARC) @command{qemu-sparc} can execute Sparc32 binaries (Sparc32 CPU, 32 bit ABI). @command{qemu-sparc32plus} can execute Sparc32 and SPARC32PLUS binaries @@ -2276,6 +2380,7 @@ Run the emulation in single step mode. * Windows:: * Cross compilation for Windows with Linux:: * Mac OS X:: +* Make targets:: @end menu @node Linux/Unix @@ -2313,11 +2418,14 @@ instructions in the download section and the FAQ. @item Download the MinGW development library of SDL 1.2.x (@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from -@url{http://www.libsdl.org}. Unpack it in a temporary place, and -unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool -directory. Edit the @file{sdl-config} script so that it gives the +@url{http://www.libsdl.org}. Unpack it in a temporary place and +edit the @file{sdl-config} script so that it gives the correct SDL directory when invoked. +@item Install the MinGW version of zlib and make sure +@file{zlib.h} and @file{libz.dll.a} are in +MingGW's default header and linker search paths. + @item Extract the current version of QEMU. @item Start the MSYS shell (file @file{msys.bat}). @@ -2340,29 +2448,43 @@ correct SDL directory when invoked. Install the MinGW cross compilation tools available at @url{http://www.mingw.org/}. -@item -Install the Win32 version of SDL (@url{http://www.libsdl.org}) by -unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment -variable so that @file{i386-mingw32msvc-sdl-config} can be launched by +@item Download +the MinGW development library of SDL 1.2.x +(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from +@url{http://www.libsdl.org}. Unpack it in a temporary place and +edit the @file{sdl-config} script so that it gives the +correct SDL directory when invoked. Set up the @code{PATH} environment +variable so that @file{sdl-config} can be launched by the QEMU configuration script. +@item Install the MinGW version of zlib and make sure +@file{zlib.h} and @file{libz.dll.a} are in +MingGW's default header and linker search paths. + @item Configure QEMU for Windows cross compilation: @example -./configure --enable-mingw32 +PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i686-pc-mingw32-' @end example -If necessary, you can change the cross-prefix according to the prefix -chosen for the MinGW tools with --cross-prefix. You can also use ---prefix to set the Win32 install path. +The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and +MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}. +We set the @code{PATH} environment variable to ensure the MingW version of @file{sdl-config} is used and +use --cross-prefix to specify the name of the cross compiler. +You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/Qemu}. + +Under Fedora Linux, you can run: +@example +yum -y install mingw32-gcc mingw32-SDL mingw32-zlib +@end example +to get a suitable cross compilation environment. @item You can install QEMU in the installation directory by typing -@file{make install}. Don't forget to copy @file{SDL.dll} in the +@code{make install}. Don't forget to copy @file{SDL.dll} and @file{zlib1.dll} into the installation directory. @end itemize -Note: Currently, Wine does not seem able to launch -QEMU for Win32. +Wine can be used to launch the resulting qemu.exe compiled for Win32. @node Mac OS X @section Mac OS X @@ -2371,8 +2493,98 @@ The Mac OS X patches are not fully merged in QEMU, so you should look at the QEMU mailing list archive to have all the necessary information. +@node Make targets +@section Make targets + +@table @code + +@item make +@item make all +Make everything which is typically needed. + +@item install +TODO + +@item install-doc +TODO + +@item make clean +Remove most files which were built during make. + +@item make distclean +Remove everything which was built during make. + +@item make dvi +@item make html +@item make info +@item make pdf +Create documentation in dvi, html, info or pdf format. + +@item make cscope +TODO + +@item make defconfig +(Re-)create some build configuration files. +User made changes will be overwritten. + +@item tar +@item tarbin +TODO + +@end table + +@node License +@appendix License + +QEMU is a trademark of Fabrice Bellard. + +QEMU is released under the GNU General Public License (TODO: add link). +Parts of QEMU have specific licenses, see file LICENSE. + +TODO (refer to file LICENSE, include it, include the GPL?) + @node Index -@chapter Index +@appendix Index +@menu +* Concept Index:: +* Function Index:: +* Keystroke Index:: +* Program Index:: +* Data Type Index:: +* Variable Index:: +@end menu + +@node Concept Index +@section Concept Index +This is the main index. Should we combine all keywords in one index? TODO @printindex cp +@node Function Index +@section Function Index +This index could be used for command line options and monitor functions. +@printindex fn + +@node Keystroke Index +@section Keystroke Index + +This is a list of all keystrokes which have a special function +in system emulation. + +@printindex ky + +@node Program Index +@section Program Index +@printindex pg + +@node Data Type Index +@section Data Type Index + +This index could be used for qdev device names and options. + +@printindex tp + +@node Variable Index +@section Variable Index +@printindex vr + @bye diff --git a/qemu-img.c b/qemu-img.c index eb5c0f0207..0db8d4f194 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -189,11 +189,13 @@ static int read_password(char *buf, int buf_size) #endif static BlockDriverState *bdrv_new_open(const char *filename, - const char *fmt) + const char *fmt, + int readonly) { BlockDriverState *bs; BlockDriver *drv; char password[256]; + int flags = BRDV_O_FLAGS; bs = bdrv_new(""); if (!bs) @@ -205,7 +207,10 @@ static BlockDriverState *bdrv_new_open(const char *filename, } else { drv = NULL; } - if (bdrv_open2(bs, filename, BRDV_O_FLAGS | BDRV_O_RDWR, drv) < 0) { + if (!readonly) { + flags |= BDRV_O_RDWR; + } + if (bdrv_open2(bs, filename, flags, drv) < 0) { error("Could not open '%s'", filename); } if (bdrv_is_encrypted(bs)) { @@ -344,7 +349,7 @@ static int img_create(int argc, char **argv) } } - bs = bdrv_new_open(backing_file->value.s, fmt); + bs = bdrv_new_open(backing_file->value.s, fmt, 1); bdrv_get_geometry(bs, &size); size *= 512; bdrv_delete(bs); @@ -572,7 +577,7 @@ static int img_convert(int argc, char **argv) BlockDriverState **bs, *out_bs; int64_t total_sectors, nb_sectors, sector_num, bs_offset; uint64_t bs_sectors; - uint8_t buf[IO_BUF_SIZE]; + uint8_t * buf; const uint8_t *buf1; BlockDriverInfo bdi; QEMUOptionParameter *param = NULL; @@ -628,7 +633,7 @@ static int img_convert(int argc, char **argv) total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt); + bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, 1); if (!bs[bs_i]) error("Could not open '%s'", argv[optind + bs_i]); bdrv_get_geometry(bs[bs_i], &bs_sectors); @@ -686,11 +691,12 @@ static int img_convert(int argc, char **argv) } } - out_bs = bdrv_new_open(out_filename, out_fmt); + out_bs = bdrv_new_open(out_filename, out_fmt, 0); bs_i = 0; bs_offset = 0; bdrv_get_geometry(bs[0], &bs_sectors); + buf = qemu_malloc(IO_BUF_SIZE); if (flags & BLOCK_FLAG_COMPRESS) { if (bdrv_get_info(out_bs, &bdi) < 0) @@ -823,6 +829,7 @@ static int img_convert(int argc, char **argv) } } } + qemu_free(buf); bdrv_delete(out_bs); for (bs_i = 0; bs_i < bs_n; bs_i++) bdrv_delete(bs[bs_i]); @@ -1179,8 +1186,11 @@ static int img_rebase(int argc, char **argv) uint64_t num_sectors; uint64_t sector; int n, n1; - uint8_t buf_old[IO_BUF_SIZE]; - uint8_t buf_new[IO_BUF_SIZE]; + uint8_t * buf_old; + uint8_t * buf_new; + + buf_old = qemu_malloc(IO_BUF_SIZE); + buf_new = qemu_malloc(IO_BUF_SIZE); bdrv_get_geometry(bs, &num_sectors); @@ -1227,6 +1237,9 @@ static int img_rebase(int argc, char **argv) written += pnum; } } + + qemu_free(buf_old); + qemu_free(buf_new); } /* diff --git a/qemu-monitor.hx b/qemu-monitor.hx index e5bff8e9f1..7f9d261cd9 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -19,6 +19,7 @@ ETEXI STEXI @item help or ? [@var{cmd}] +@findex help Show the help for all commands or just for command @var{cmd}. ETEXI @@ -32,6 +33,7 @@ ETEXI STEXI @item commit +@findex commit Commit changes to the disk images (if -snapshot is used) or backing files. ETEXI @@ -46,6 +48,7 @@ ETEXI STEXI @item info @var{subcommand} +@findex info Show various information about the system state. @table @option @@ -125,6 +128,7 @@ ETEXI STEXI @item q or quit +@findex quit Quit the emulator. ETEXI @@ -139,6 +143,7 @@ ETEXI STEXI @item eject [-f] @var{device} +@findex eject Eject a removable medium (use -f to force it). ETEXI @@ -153,6 +158,7 @@ ETEXI STEXI @item change @var{device} @var{setting} +@findex change Change the configuration of a device. @@ -198,6 +204,7 @@ ETEXI STEXI @item screendump @var{filename} +@findex screendump Save screen into PPM image @var{filename}. ETEXI @@ -211,6 +218,7 @@ ETEXI STEXI @item logfile @var{filename} +@findex logfile Output logs to @var{filename}. ETEXI @@ -224,6 +232,7 @@ ETEXI STEXI @item log @var{item1}[,...] +@findex log Activate logging of the specified items to @file{/tmp/qemu.log}. ETEXI @@ -237,6 +246,7 @@ ETEXI STEXI @item savevm [@var{tag}|@var{id}] +@findex savevm Create a snapshot of the whole virtual machine. If @var{tag} is provided, it is used as human readable identifier. If there is already a snapshot with the same tag or ID, it is replaced. More info at @@ -253,6 +263,7 @@ ETEXI STEXI @item loadvm @var{tag}|@var{id} +@findex loadvm Set the whole virtual machine to the snapshot identified by the tag @var{tag} or the unique snapshot ID @var{id}. ETEXI @@ -267,6 +278,7 @@ ETEXI STEXI @item delvm @var{tag}|@var{id} +@findex delvm Delete the snapshot identified by @var{tag} or @var{id}. ETEXI @@ -280,6 +292,7 @@ ETEXI STEXI @item singlestep [off] +@findex singlestep Run the emulation in single step mode. If called with option off, the emulation returns to normal mode. ETEXI @@ -295,6 +308,7 @@ ETEXI STEXI @item stop +@findex stop Stop emulation. ETEXI @@ -309,6 +323,7 @@ ETEXI STEXI @item c or cont +@findex cont Resume emulation. ETEXI @@ -322,6 +337,7 @@ ETEXI STEXI @item gdbserver [@var{port}] +@findex gdbserver Start gdbserver session (default @var{port}=1234) ETEXI @@ -335,6 +351,7 @@ ETEXI STEXI @item x/fmt @var{addr} +@findex x Virtual memory dump starting at @var{addr}. ETEXI @@ -348,6 +365,7 @@ ETEXI STEXI @item xp /@var{fmt} @var{addr} +@findex xp Physical memory dump starting at @var{addr}. @var{fmt} is a format which tells the command how to format the @@ -355,13 +373,16 @@ data. Its syntax is: @option{/@{count@}@{format@}@{size@}} @table @var @item count +@findex count is the number of items to be dumped. @item format +@findex format can be x (hex), d (signed decimal), u (unsigned decimal), o (octal), c (char) or i (asm instruction). @item size +@findex size can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86, @code{h} or @code{w} can be specified with the @code{i} format to respectively select 16 or 32 bit code instruction size. @@ -414,6 +435,7 @@ ETEXI STEXI @item p or print/@var{fmt} @var{expr} +@findex print Print expression value. Only the @var{format} part of @var{fmt} is used. @@ -453,6 +475,7 @@ ETEXI STEXI @item sendkey @var{keys} +@findex sendkey Send @var{keys} to the emulator. @var{keys} could be the name of the key or @code{#} followed by the raw value in either decimal or hexadecimal @@ -476,6 +499,7 @@ ETEXI STEXI @item system_reset +@findex system_reset Reset the system. ETEXI @@ -491,6 +515,7 @@ ETEXI STEXI @item system_powerdown +@findex system_powerdown Power down the system (if supported). ETEXI @@ -505,6 +530,7 @@ ETEXI STEXI @item sum @var{addr} @var{size} +@findex sum Compute the checksum of a memory region. ETEXI @@ -519,6 +545,7 @@ ETEXI STEXI @item usb_add @var{devname} +@findex usb_add Add the USB device @var{devname}. For details of available devices see @ref{usb_devices} @@ -534,6 +561,7 @@ ETEXI STEXI @item usb_del @var{devname} +@findex usb_del Remove the USB device @var{devname} from the QEMU virtual USB hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor @@ -550,6 +578,7 @@ ETEXI STEXI @item device_add @var{config} +@findex device_add Add device. ETEXI @@ -564,6 +593,7 @@ ETEXI STEXI @item device_del @var{id} +@findex device_del Remove device @var{id}. ETEXI @@ -591,6 +621,7 @@ ETEXI STEXI @item mouse_move @var{dx} @var{dy} [@var{dz}] +@findex mouse_move Move the active mouse to the specified coordinates @var{dx} @var{dy} with optional scroll axis @var{dz}. ETEXI @@ -605,6 +636,7 @@ ETEXI STEXI @item mouse_button @var{val} +@findex mouse_button Change the active mouse button state @var{val} (1=L, 2=M, 4=R). ETEXI @@ -618,6 +650,7 @@ ETEXI STEXI @item mouse_set @var{index} +@findex mouse_set Set which mouse device receives events at given @var{index}, index can be obtained with @example @@ -636,6 +669,7 @@ ETEXI #endif STEXI @item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]] +@findex wavcapture Capture audio into @var{filename}. Using sample rate @var{frequency} bits per sample @var{bits} and number of channels @var{channels}. @@ -658,6 +692,7 @@ ETEXI #endif STEXI @item stopcapture @var{index} +@findex stopcapture Stop capture with a given @var{index}, index can be obtained with @example info capture @@ -675,6 +710,7 @@ ETEXI STEXI @item memsave @var{addr} @var{size} @var{file} +@findex memsave save to disk virtual memory dump starting at @var{addr} of size @var{size}. ETEXI @@ -689,6 +725,7 @@ ETEXI STEXI @item pmemsave @var{addr} @var{size} @var{file} +@findex pmemsave save to disk physical memory dump starting at @var{addr} of size @var{size}. ETEXI @@ -702,6 +739,7 @@ ETEXI STEXI @item boot_set @var{bootdevicelist} +@findex boot_set Define new values for the boot device list. Those values will override the values specified on the command line through the @code{-boot} option. @@ -721,6 +759,7 @@ ETEXI #endif STEXI @item nmi @var{cpu} +@findex nmi Inject an NMI on the given CPU (x86 only). ETEXI @@ -740,6 +779,7 @@ ETEXI STEXI @item migrate [-d] [-b] [-i] @var{uri} +@findex migrate Migrate to @var{uri} (using -d to not wait for completion). -b for migration with full copy of disk -i for migration with incremental copy of disk (base image is shared) @@ -756,6 +796,7 @@ ETEXI STEXI @item migrate_cancel +@findex migrate_cancel Cancel the current VM migration. ETEXI @@ -770,6 +811,7 @@ ETEXI STEXI @item migrate_set_speed @var{value} +@findex migrate_set_speed Set maximum speed to @var{value} (in bytes) for migrations. ETEXI @@ -784,6 +826,7 @@ ETEXI STEXI @item migrate_set_downtime @var{second} +@findex migrate_set_downtime Set maximum tolerated downtime (in seconds) for migration. ETEXI @@ -803,6 +846,7 @@ ETEXI STEXI @item drive_add +@findex drive_add Add drive to PCI storage controller. ETEXI @@ -819,6 +863,7 @@ ETEXI STEXI @item pci_add +@findex pci_add Hot-add PCI device. ETEXI @@ -835,6 +880,7 @@ ETEXI STEXI @item pci_del +@findex pci_del Hot remove PCI device. ETEXI @@ -848,6 +894,7 @@ ETEXI STEXI @item host_net_add +@findex host_net_add Add host VLAN client. ETEXI @@ -861,6 +908,7 @@ ETEXI STEXI @item host_net_remove +@findex host_net_remove Remove host VLAN client. ETEXI @@ -884,6 +932,7 @@ ETEXI #endif STEXI @item host_net_redir +@findex host_net_redir Redirect TCP or UDP connections from host to guest (requires -net user). ETEXI @@ -899,6 +948,7 @@ ETEXI STEXI @item balloon @var{value} +@findex balloon Request VM to change its memory allocation to @var{value} (in MB). ETEXI @@ -912,6 +962,7 @@ ETEXI STEXI @item set_link @var{name} [up|down] +@findex set_link Set link @var{name} up or down. ETEXI @@ -925,6 +976,7 @@ ETEXI STEXI @item watchdog_action +@findex watchdog_action Change watchdog action. ETEXI @@ -938,6 +990,7 @@ ETEXI STEXI @item acl_show @var{aclname} +@findex acl_show List all the matching rules in the access control list, and the default policy. There are currently two named access control lists, @var{vnc.x509dname} and @var{vnc.username} matching on the x509 client @@ -954,6 +1007,7 @@ ETEXI STEXI @item acl_policy @var{aclname} @code{allow|deny} +@findex acl_policy Set the default access control list policy, used in the event that none of the explicit rules match. The default policy at startup is always @code{deny}. @@ -969,6 +1023,7 @@ ETEXI STEXI @item acl_allow @var{aclname} @var{match} @code{allow|deny} [@var{index}] +@findex acl_allow Add a match rule to the access control list, allowing or denying access. The match will normally be an exact username or x509 distinguished name, but can optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to @@ -987,6 +1042,7 @@ ETEXI STEXI @item acl_remove @var{aclname} @var{match} +@findex acl_remove Remove the specified match rule from the access control list. ETEXI @@ -999,7 +1055,7 @@ ETEXI }, STEXI -@item acl_remove @var{aclname} @var{match} +@item acl_remove @var{aclname} Remove all matches from the access control list, and set the default policy back to @code{deny}. ETEXI @@ -1017,6 +1073,7 @@ ETEXI #endif STEXI @item mce @var{cpu} @var{bank} @var{status} @var{mcgstatus} @var{addr} @var{misc} +@findex mce (x86) Inject an MCE on the given CPU (x86 only). ETEXI @@ -1031,6 +1088,7 @@ ETEXI STEXI @item getfd @var{fdname} +@findex getfd If a file descriptor is passed alongside this command using the SCM_RIGHTS mechanism on unix sockets, it is stored using the name @var{fdname} for later use by other monitor commands. @@ -1047,6 +1105,7 @@ ETEXI STEXI @item closefd @var{fdname} +@findex closefd Close the file descriptor previously assigned to @var{fdname} using the @code{getfd} command. This is only needed if the file descriptor was never used by another monitor command. @@ -1063,9 +1122,24 @@ ETEXI STEXI @item block_passwd @var{device} @var{password} +@findex block_passwd Set the encrypted device @var{device} password to @var{password} ETEXI + { + .name = "qmp_capabilities", + .args_type = "", + .params = "", + .help = "enable QMP capabilities", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_qmp_capabilities, + }, + +STEXI +@item qmp_capabilities +Enable the specified QMP capabilities +ETEXI + STEXI @end table ETEXI diff --git a/qemu-options.hx b/qemu-options.hx index bb2d4fa5be..f53922f3fe 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -14,6 +14,7 @@ DEF("help", 0, QEMU_OPTION_h, "-h or -help display this help and exit\n") STEXI @item -h +@findex -h Display help and exit ETEXI @@ -21,6 +22,7 @@ DEF("version", 0, QEMU_OPTION_version, "-version display version information and exit\n") STEXI @item -version +@findex -version Display version information and exit ETEXI @@ -28,6 +30,7 @@ DEF("M", HAS_ARG, QEMU_OPTION_M, "-M machine select emulated machine (-M ? for list)\n") STEXI @item -M @var{machine} +@findex -M Select the emulated @var{machine} (@code{-M ?} for list) ETEXI @@ -35,6 +38,7 @@ DEF("cpu", HAS_ARG, QEMU_OPTION_cpu, "-cpu cpu select CPU (-cpu ? for list)\n") STEXI @item -cpu @var{model} +@findex -cpu Select CPU model (-cpu ? for list and additional feature selection) ETEXI @@ -48,6 +52,7 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, " sockets= number of discrete sockets in the system\n") STEXI @item -smp @var{n}[,cores=@var{cores}][,threads=@var{threads}][,sockets=@var{sockets}][,maxcpus=@var{maxcpus}] +@findex -smp Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255 CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs to 4. @@ -62,6 +67,7 @@ DEF("numa", HAS_ARG, QEMU_OPTION_numa, "-numa node[,mem=size][,cpus=cpu[-cpu]][,nodeid=node]\n") STEXI @item -numa @var{opts} +@findex -numa Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally. ETEXI @@ -72,6 +78,8 @@ DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "") STEXI @item -fda @var{file} @item -fdb @var{file} +@findex -fda +@findex -fdb Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}). ETEXI @@ -87,6 +95,10 @@ STEXI @item -hdb @var{file} @item -hdc @var{file} @item -hdd @var{file} +@findex -hda +@findex -hdb +@findex -hdc +@findex -hdd Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}). ETEXI @@ -94,6 +106,7 @@ DEF("cdrom", HAS_ARG, QEMU_OPTION_cdrom, "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n") STEXI @item -cdrom @var{file} +@findex -cdrom Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and @option{-cdrom} at the same time). You can use the host CD-ROM by using @file{/dev/cdrom} as filename (@pxref{host_drives}). @@ -105,15 +118,9 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive, " [,cache=writethrough|writeback|none][,format=f][,serial=s]\n" " [,addr=A][,id=name][,aio=threads|native][,readonly=on|off]\n" " use 'file' as a drive image\n") -DEF("set", HAS_ARG, QEMU_OPTION_set, - "-set group.id.arg=value\n" - " set <arg> parameter for item <id> of type <group>\n" - " i.e. -set drive.$id.file=/path/to/image\n") -DEF("global", HAS_ARG, QEMU_OPTION_global, - "-global driver.property=value\n" - " set a global default for a driver property\n") STEXI @item -drive @var{option}[,@var{option}[,@var{option}[,...]]] +@findex -drive Define a new drive. Valid options are: @@ -216,11 +223,30 @@ qemu -hda a -hdb b @end example ETEXI +DEF("set", HAS_ARG, QEMU_OPTION_set, + "-set group.id.arg=value\n" + " set <arg> parameter for item <id> of type <group>\n" + " i.e. -set drive.$id.file=/path/to/image\n") +STEXI +@item -set +@findex -set +TODO +ETEXI + +DEF("global", HAS_ARG, QEMU_OPTION_global, + "-global driver.property=value\n" + " set a global default for a driver property\n") +STEXI +@item -global +@findex -global +TODO +ETEXI + DEF("mtdblock", HAS_ARG, QEMU_OPTION_mtdblock, "-mtdblock file use 'file' as on-board Flash memory image\n") STEXI - @item -mtdblock @var{file} +@findex -mtdblock Use @var{file} as on-board Flash memory image. ETEXI @@ -228,6 +254,7 @@ DEF("sd", HAS_ARG, QEMU_OPTION_sd, "-sd file use 'file' as SecureDigital card image\n") STEXI @item -sd @var{file} +@findex -sd Use @var{file} as SecureDigital card image. ETEXI @@ -235,6 +262,7 @@ DEF("pflash", HAS_ARG, QEMU_OPTION_pflash, "-pflash file use 'file' as a parallel flash image\n") STEXI @item -pflash @var{file} +@findex -pflash Use @var{file} as a parallel flash image. ETEXI @@ -243,7 +271,7 @@ DEF("boot", HAS_ARG, QEMU_OPTION_boot, " 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n") STEXI @item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off] - +@findex -boot Specify boot order @var{drives} as a string of drive letters. Valid drive letters depend on the target achitecture. The x86 PC uses: a, b (floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p (Etherboot @@ -269,6 +297,7 @@ DEF("snapshot", 0, QEMU_OPTION_snapshot, "-snapshot write to temporary files instead of disk image files\n") STEXI @item -snapshot +@findex -snapshot Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@pxref{disk_images}). @@ -279,6 +308,7 @@ DEF("m", HAS_ARG, QEMU_OPTION_m, stringify(DEFAULT_RAM_SIZE) "]\n") STEXI @item -m @var{megs} +@findex -m Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. Optionally, a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or gigabytes respectively. @@ -288,7 +318,7 @@ DEF("k", HAS_ARG, QEMU_OPTION_k, "-k language use keyboard layout (for example 'fr' for French)\n") STEXI @item -k @var{language} - +@findex -k Use keyboard layout @var{language} (for example @code{fr} for French). This option is only needed where it is not easy to get raw PC keycodes (e.g. on Macs, with some X11 servers or with a VNC @@ -312,7 +342,7 @@ DEF("audio-help", 0, QEMU_OPTION_audio_help, #endif STEXI @item -audio-help - +@findex -audio-help Will show the audio subsystem help: list of drivers, tunable parameters. ETEXI @@ -326,7 +356,7 @@ DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, #endif STEXI @item -soundhw @var{card1}[,@var{card2},...] or -soundhw all - +@findex -soundhw Enable audio and selected sound hardware. Use ? to print all available sound hardware. @@ -357,6 +387,7 @@ USB options: @table @option @item -usb +@findex -usb Enable the USB driver (will be the default soon) ETEXI @@ -365,6 +396,7 @@ DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice, STEXI @item -usbdevice @var{devname} +@findex -usbdevice Add the USB device @var{devname}. @xref{usb_devices}. @table @option @@ -408,13 +440,17 @@ DEF("device", HAS_ARG, QEMU_OPTION_device, " add device (based on driver)\n" " prop=value,... sets driver properties\n" " use -device ? to print all possible drivers\n" - " use -device driver,? to print all possible properties\n") + " use -device driver,? to print all possible options\n" + " use -device driver,option=? to print a help for value\n") STEXI -@item -device @var{driver}[,@var{prop}[=@var{value}][,...]] -Add device @var{driver}. @var{prop}=@var{value} sets driver -properties. Valid properties depend on the driver. To get help on -possible drivers and properties, use @code{-device ?} and -@code{-device @var{driver},?}. +@item -device @var{driver}[,@var{option}[=@var{value}][,...]] +@findex -device +Add device @var{driver}. Depending on the device type, +@var{option} (with default or given @var{value}) may be useful. +To get a help on possible @var{driver}s, @var{option}s or @var{value}s, use +@code{-device ?}, +@code{-device @var{driver},?} or +@code{-device @var{driver},@var{option}=?}. ETEXI DEF("name", HAS_ARG, QEMU_OPTION_name, @@ -423,6 +459,7 @@ DEF("name", HAS_ARG, QEMU_OPTION_name, " string1 sets the window title and string2 the process name (on Linux)\n") STEXI @item -name @var{name} +@findex -name Sets the @var{name} of the guest. This name will be displayed in the SDL window caption. The @var{name} will also be used for the VNC server. @@ -434,6 +471,7 @@ DEF("uuid", HAS_ARG, QEMU_OPTION_uuid, " specify machine UUID\n") STEXI @item -uuid @var{uuid} +@findex -uuid Set system UUID. ETEXI @@ -453,7 +491,7 @@ DEF("nographic", 0, QEMU_OPTION_nographic, "-nographic disable graphical output and redirect serial I/Os to console\n") STEXI @item -nographic - +@findex -nographic Normally, QEMU uses SDL to display the VGA output. With this option, you can totally disable graphical output so that QEMU is a simple command line application. The emulated serial port is redirected on @@ -467,7 +505,7 @@ DEF("curses", 0, QEMU_OPTION_curses, #endif STEXI @item -curses - +@findex curses Normally, QEMU uses SDL to display the VGA output. With this option, QEMU can display the VGA output when in text mode using a curses/ncurses interface. Nothing is displayed in graphical mode. @@ -479,7 +517,7 @@ DEF("no-frame", 0, QEMU_OPTION_no_frame, #endif STEXI @item -no-frame - +@findex -no-frame Do not use decorations for SDL windows and start them using the whole available screen space. This makes the using QEMU in a dedicated desktop workspace more convenient. @@ -491,7 +529,7 @@ DEF("alt-grab", 0, QEMU_OPTION_alt_grab, #endif STEXI @item -alt-grab - +@findex -alt-grab Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt). ETEXI @@ -501,7 +539,7 @@ DEF("ctrl-grab", 0, QEMU_OPTION_ctrl_grab, #endif STEXI @item -ctrl-grab - +@findex -ctrl-grab Use Right-Ctrl to grab mouse (instead of Ctrl-Alt). ETEXI @@ -511,7 +549,7 @@ DEF("no-quit", 0, QEMU_OPTION_no_quit, #endif STEXI @item -no-quit - +@findex -no-quit Disable SDL window close capability. ETEXI @@ -521,7 +559,7 @@ DEF("sdl", 0, QEMU_OPTION_sdl, #endif STEXI @item -sdl - +@findex -sdl Enable SDL. ETEXI @@ -529,7 +567,7 @@ DEF("portrait", 0, QEMU_OPTION_portrait, "-portrait rotate graphical output 90 deg left (only PXA LCD)\n") STEXI @item -portrait - +@findex -portrait Rotate graphical output 90 deg left (only PXA LCD). ETEXI @@ -538,6 +576,7 @@ DEF("vga", HAS_ARG, QEMU_OPTION_vga, " select video card type\n") STEXI @item -vga @var{type} +@findex -vga Select type of VGA card to emulate. Valid values for @var{type} are @table @option @item cirrus @@ -563,6 +602,7 @@ DEF("full-screen", 0, QEMU_OPTION_full_screen, "-full-screen start in full screen\n") STEXI @item -full-screen +@findex -full-screen Start in full screen. ETEXI @@ -572,6 +612,7 @@ DEF("g", 1, QEMU_OPTION_g , #endif STEXI @item -g @var{width}x@var{height}[x@var{depth}] +@findex -g Set the initial graphical resolution and depth (PPC, SPARC only). ETEXI @@ -579,7 +620,7 @@ DEF("vnc", HAS_ARG, QEMU_OPTION_vnc , "-vnc display start a VNC server on display\n") STEXI @item -vnc @var{display}[,@var{option}[,@var{option}[,...]]] - +@findex -vnc Normally, QEMU uses SDL to display the VGA output. With this option, you can have QEMU listen on VNC display @var{display} and redirect the VGA display over the VNC session. It is very useful to enable the usb @@ -705,6 +746,7 @@ DEF("win2k-hack", 0, QEMU_OPTION_win2k_hack, #endif STEXI @item -win2k-hack +@findex -win2k-hack Use it when installing Windows 2000 to avoid a disk full bug. After Windows 2000 is installed, you no longer need this option (this option slows down the IDE transfers). @@ -721,8 +763,10 @@ DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk, #endif STEXI @item -no-fd-bootchk +@findex -no-fd-bootchk Disable boot signature checking for floppy disks in Bochs BIOS. It may be needed to boot from old floppy disks. +TODO: check reference to Bochs BIOS. ETEXI #ifdef TARGET_I386 @@ -731,6 +775,7 @@ DEF("no-acpi", 0, QEMU_OPTION_no_acpi, #endif STEXI @item -no-acpi +@findex -no-acpi Disable ACPI (Advanced Configuration and Power Interface) support. Use it if your guest OS complains about ACPI problems (PC target machine only). @@ -742,6 +787,7 @@ DEF("no-hpet", 0, QEMU_OPTION_no_hpet, #endif STEXI @item -no-hpet +@findex -no-hpet Disable HPET support. ETEXI @@ -753,6 +799,7 @@ DEF("balloon", HAS_ARG, QEMU_OPTION_balloon, #endif STEXI @item -balloon none +@findex -balloon Disable balloon device. @item -balloon virtio[,addr=@var{addr}] Enable virtio balloon device (default), optionally with PCI address @@ -766,6 +813,7 @@ DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable, #endif STEXI @item -acpitable [sig=@var{str}][,rev=@var{n}][,oem_id=@var{str}][,oem_table_id=@var{str}][,oem_rev=@var{n}] [,asl_compiler_id=@var{str}][,asl_compiler_rev=@var{n}][,data=@var{file1}[:@var{file2}]...] +@findex -acpitable Add ACPI table with specified header fields and context from specified files. ETEXI @@ -781,9 +829,11 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, #endif STEXI @item -smbios file=@var{binary} +@findex -smbios Load SMBIOS entry from binary file. @item -smbios type=0[,vendor=@var{str}][,version=@var{str}][,date=@var{str}][,release=@var{%d.%d}] +@findex -smbios Specify SMBIOS type 0 fields @item -smbios type=1[,manufacturer=@var{str}][,product=@var{str}][,version=@var{str}][,serial=@var{str}][,uuid=@var{uuid}][,sku=@var{str}][,family=@var{str}] @@ -867,6 +917,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "socket],id=str[,option][,option][,...]\n") STEXI @item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}][,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}] +@findex -net Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} = 0 is the default). The NIC is an e1000 by default on the PC target. Optionally, the MAC address can be changed to @var{mac}, the @@ -1144,7 +1195,7 @@ The general form of a character device option is: @table @option @item -chardev @var{backend} ,id=@var{id} [,@var{options}] - +@findex -chardev Backend is one of: @option{null}, @option{socket}, @@ -1348,6 +1399,7 @@ STEXI @table @option @item -bt hci[...] +@findex -bt Defines the function of the corresponding Bluetooth HCI. -bt options are matched with the HCIs present in the chosen machine type. For example when emulating a machine with only one HCI built into it, only @@ -1416,6 +1468,7 @@ DEF("kernel", HAS_ARG, QEMU_OPTION_kernel, \ "-kernel bzImage use 'bzImage' as kernel image\n") STEXI @item -kernel @var{bzImage} +@findex -kernel Use @var{bzImage} as kernel image. The kernel can be either a Linux kernel or in multiboot format. ETEXI @@ -1424,6 +1477,7 @@ DEF("append", HAS_ARG, QEMU_OPTION_append, \ "-append cmdline use 'cmdline' as kernel command line\n") STEXI @item -append @var{cmdline} +@findex -append Use @var{cmdline} as kernel command line ETEXI @@ -1431,6 +1485,7 @@ DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \ "-initrd file use 'file' as initial ram disk\n") STEXI @item -initrd @var{file} +@findex -initrd Use @var{file} as initial ram disk. @item -initrd "@var{file1} arg=foo,@var{file2}" @@ -1457,6 +1512,7 @@ DEF("serial", HAS_ARG, QEMU_OPTION_serial, \ "-serial dev redirect the serial port to char device 'dev'\n") STEXI @item -serial @var{dev} +@findex -serial Redirect the virtual serial port to host character device @var{dev}. The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. @@ -1584,6 +1640,7 @@ DEF("parallel", HAS_ARG, QEMU_OPTION_parallel, \ "-parallel dev redirect the parallel port to char device 'dev'\n") STEXI @item -parallel @var{dev} +@findex -parallel Redirect the virtual parallel port to host device @var{dev} (same devices as the serial port). On Linux hosts, @file{/dev/parportN} can be used to use hardware devices connected on the corresponding host @@ -1599,6 +1656,7 @@ DEF("monitor", HAS_ARG, QEMU_OPTION_monitor, \ "-monitor dev redirect the monitor to char device 'dev'\n") STEXI @item -monitor @var{dev} +@findex -monitor Redirect the monitor to host device @var{dev} (same devices as the serial port). The default device is @code{vc} in graphical mode and @code{stdio} in @@ -1608,6 +1666,7 @@ DEF("qmp", HAS_ARG, QEMU_OPTION_qmp, \ "-qmp dev like -monitor but opens in 'control' mode\n") STEXI @item -qmp @var{dev} +@findex -qmp Like -monitor but opens in 'control' mode. ETEXI @@ -1615,6 +1674,7 @@ DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ "-mon chardev=[name][,mode=readline|control][,default]\n") STEXI @item -mon chardev=[name][,mode=readline|control][,default] +@findex -mon Setup monitor on chardev @var{name}. ETEXI @@ -1622,6 +1682,7 @@ DEF("debugcon", HAS_ARG, QEMU_OPTION_debugcon, \ "-debugcon dev redirect the debug console to char device 'dev'\n") STEXI @item -debugcon @var{dev} +@findex -debugcon Redirect the debug console to host device @var{dev} (same devices as the serial port). The debug console is an I/O port which is typically port 0xe9; writing to that I/O port sends output to this device. @@ -1633,6 +1694,7 @@ DEF("pidfile", HAS_ARG, QEMU_OPTION_pidfile, \ "-pidfile file write PID to 'file'\n") STEXI @item -pidfile @var{file} +@findex -pidfile Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. ETEXI @@ -1641,6 +1703,7 @@ DEF("singlestep", 0, QEMU_OPTION_singlestep, \ "-singlestep always run in singlestep mode\n") STEXI @item -singlestep +@findex -singlestep Run the emulation in single step mode. ETEXI @@ -1648,6 +1711,7 @@ DEF("S", 0, QEMU_OPTION_S, \ "-S freeze CPU at startup (use 'c' to start execution)\n") STEXI @item -S +@findex -S Do not start CPU at startup (you must type 'c' in the monitor). ETEXI @@ -1655,6 +1719,7 @@ DEF("gdb", HAS_ARG, QEMU_OPTION_gdb, \ "-gdb dev wait for gdb connection on 'dev'\n") STEXI @item -gdb @var{dev} +@findex -gdb Wait for gdb connection on device @var{dev} (@pxref{gdb_usage}). Typical connections will likely be TCP-based, but also UDP, pseudo TTY, or even stdio are reasonable use case. The latter is allowing to start qemu from @@ -1668,6 +1733,7 @@ DEF("s", 0, QEMU_OPTION_s, \ "-s shorthand for -gdb tcp::" DEFAULT_GDBSTUB_PORT "\n") STEXI @item -s +@findex -s Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234 (@pxref{gdb_usage}). ETEXI @@ -1676,6 +1742,7 @@ DEF("d", HAS_ARG, QEMU_OPTION_d, \ "-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items)\n") STEXI @item -d +@findex -d Output log in /tmp/qemu.log ETEXI @@ -1685,6 +1752,7 @@ DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \ " translation (t=none or lba) (usually qemu can guess them)\n") STEXI @item -hdachs @var{c},@var{h},@var{s},[,@var{t}] +@findex -hdachs Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= @var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS translation mode (@var{t}=none, lba or auto). Usually QEMU can guess @@ -1696,6 +1764,7 @@ DEF("L", HAS_ARG, QEMU_OPTION_L, \ "-L path set the directory for the BIOS, VGA BIOS and keymaps\n") STEXI @item -L @var{path} +@findex -L Set the directory for the BIOS, VGA BIOS and keymaps. ETEXI @@ -1703,6 +1772,7 @@ DEF("bios", HAS_ARG, QEMU_OPTION_bios, \ "-bios file set the filename for the BIOS\n") STEXI @item -bios @var{file} +@findex -bios Set the filename for the BIOS. ETEXI @@ -1712,6 +1782,7 @@ DEF("enable-kvm", 0, QEMU_OPTION_enable_kvm, \ #endif STEXI @item -enable-kvm +@findex -enable-kvm Enable KVM full virtualization support. This option is only available if KVM support is enabled when compiling. ETEXI @@ -1728,11 +1799,14 @@ DEF("xen-attach", 0, QEMU_OPTION_xen_attach, #endif STEXI @item -xen-domid @var{id} +@findex -xen-domid Specify xen guest domain @var{id} (XEN only). @item -xen-create +@findex -xen-create Create domain using xen hypercalls, bypassing xend. Warning: should not be used when xend is in use (XEN only). @item -xen-attach +@findex -xen-attach Attach to existing xen domain. xend will use this when starting qemu (XEN only). ETEXI @@ -1741,6 +1815,7 @@ DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \ "-no-reboot exit instead of rebooting\n") STEXI @item -no-reboot +@findex -no-reboot Exit instead of rebooting. ETEXI @@ -1748,6 +1823,7 @@ DEF("no-shutdown", 0, QEMU_OPTION_no_shutdown, \ "-no-shutdown stop before shutdown\n") STEXI @item -no-shutdown +@findex -no-shutdown Don't exit QEMU on guest shutdown, but instead only stop the emulation. This allows for instance switching to monitor to commit changes to the disk image. @@ -1758,6 +1834,7 @@ DEF("loadvm", HAS_ARG, QEMU_OPTION_loadvm, \ " start right away with a saved state (loadvm in monitor)\n") STEXI @item -loadvm @var{file} +@findex -loadvm Start right away with a saved state (@code{loadvm} in monitor) ETEXI @@ -1767,6 +1844,7 @@ DEF("daemonize", 0, QEMU_OPTION_daemonize, \ #endif STEXI @item -daemonize +@findex -daemonize Daemonize the QEMU process after initialization. QEMU will not detach from standard IO until it is ready to receive connections on any of its devices. This option is a useful way for external programs to launch QEMU without having @@ -1777,6 +1855,7 @@ DEF("option-rom", HAS_ARG, QEMU_OPTION_option_rom, \ "-option-rom rom load a file, rom, into the option ROM space\n") STEXI @item -option-rom @var{file} +@findex -option-rom Load the contents of @var{file} as an option ROM. This option is useful to load things like EtherBoot. ETEXI @@ -1786,6 +1865,7 @@ DEF("clock", HAS_ARG, QEMU_OPTION_clock, \ " To see what timers are available use -clock ?\n") STEXI @item -clock @var{method} +@findex -clock Force the use of the given methods for timer alarm. To see what timers are available use -clock ?. ETEXI @@ -1807,6 +1887,7 @@ DEF("rtc", HAS_ARG, QEMU_OPTION_rtc, \ STEXI @item -rtc [base=utc|localtime|@var{date}][,clock=host|vm][,driftfix=none|slew] +@findex -rtc Specify @option{base} as @code{utc} or @code{localtime} to let the RTC start at the current UTC or local time, respectively. @code{localtime} is required for correct date in MS-DOS or Windows. To start at a specific point in time, provide @var{date} in the @@ -1830,6 +1911,7 @@ DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ " instruction\n") STEXI @item -icount [@var{N}|auto] +@findex -icount Enable virtual instruction counter. The virtual cpu will execute one instruction every 2^@var{N} ns of virtual time. If @code{auto} is specified then the virtual cpu speed will be automatically adjusted to keep virtual @@ -1846,6 +1928,7 @@ DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \ " enable virtual hardware watchdog [default=none]\n") STEXI @item -watchdog @var{model} +@findex -watchdog Create a virtual hardware watchdog device. Once enabled (by a guest action), the watchdog must be periodically polled by an agent inside the guest or else the guest will be restarted. @@ -1895,6 +1978,7 @@ DEF("echr", HAS_ARG, QEMU_OPTION_echr, \ STEXI @item -echr @var{numeric_ascii_value} +@findex -echr Change the escape character used for switching to the monitor when using monitor and serial sharing. The default is @code{0x01} when using the @code{-nographic} option. @code{0x01} is equal to pressing @@ -1913,6 +1997,7 @@ DEF("virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon, \ " set virtio console\n") STEXI @item -virtioconsole @var{c} +@findex -virtioconsole Set virtio console. This option is maintained for backward compatibility. @@ -1924,6 +2009,7 @@ DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \ "-show-cursor show cursor\n") STEXI @item -show-cursor +@findex -show-cursor Show cursor. ETEXI @@ -1931,6 +2017,7 @@ DEF("tb-size", HAS_ARG, QEMU_OPTION_tb_size, \ "-tb-size n set TB size\n") STEXI @item -tb-size @var{n} +@findex -tb-size Set TB size. ETEXI @@ -1938,6 +2025,7 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \ "-incoming p prepare for incoming migration, listen on port p\n") STEXI @item -incoming @var{port} +@findex -incoming Prepare for incoming migration, listen on @var{port}. ETEXI @@ -1945,6 +2033,7 @@ DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \ "-nodefaults don't create default devices\n") STEXI @item -nodefaults +@findex -nodefaults Don't create default devices. ETEXI @@ -1954,6 +2043,7 @@ DEF("chroot", HAS_ARG, QEMU_OPTION_chroot, \ #endif STEXI @item -chroot @var{dir} +@findex -chroot Immediately before starting guest execution, chroot to the specified directory. Especially useful in combination with -runas. ETEXI @@ -1964,6 +2054,7 @@ DEF("runas", HAS_ARG, QEMU_OPTION_runas, \ #endif STEXI @item -runas @var{user} +@findex -runas Immediately before starting guest execution, drop root privileges, switching to the specified user. ETEXI @@ -1975,6 +2066,7 @@ DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env, #endif STEXI @item -prom-env @var{variable}=@var{value} +@findex -prom-env Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only). ETEXI #if defined(TARGET_ARM) || defined(TARGET_M68K) @@ -1983,6 +2075,7 @@ DEF("semihosting", 0, QEMU_OPTION_semihosting, #endif STEXI @item -semihosting +@findex -semihosting Semihosting mode (ARM, M68K only). ETEXI #if defined(TARGET_ARM) @@ -1991,6 +2084,7 @@ DEF("old-param", 0, QEMU_OPTION_old_param, #endif STEXI @item -old-param +@findex -old-param (ARM) Old param mode (ARM only). ETEXI @@ -1998,6 +2092,7 @@ DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig, "-readconfig <file>\n") STEXI @item -readconfig @var{file} +@findex -readconfig Read device configuration from @var{file}. ETEXI DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig, @@ -2005,6 +2100,7 @@ DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig, " read/write config file\n") STEXI @item -writeconfig @var{file} +@findex -writeconfig Write device configuration to @var{file}. ETEXI DEF("nodefconfig", 0, QEMU_OPTION_nodefconfig, @@ -2012,6 +2108,7 @@ DEF("nodefconfig", 0, QEMU_OPTION_nodefconfig, " do not load default config files at startup\n") STEXI @item -nodefconfig +@findex -nodefconfig Normally QEMU loads a configuration file from @var{sysconfdir}/qemu.conf and @var{sysconfdir}/target-@var{ARCH}.conf on startup. The @code{-nodefconfig} option will prevent QEMU from loading these configuration files at startup. diff --git a/qemu-sockets.c b/qemu-sockets.c index d912fed16b..23c3def2a4 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -424,7 +424,7 @@ static int inet_parse(QemuOpts *opts, const char *str) __FUNCTION__, str); return -1; } - qemu_opt_set(opts, "ipv6", "yes"); + qemu_opt_set(opts, "ipv6", "on"); } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { @@ -432,7 +432,7 @@ static int inet_parse(QemuOpts *opts, const char *str) __FUNCTION__, str); return -1; } - qemu_opt_set(opts, "ipv4", "yes"); + qemu_opt_set(opts, "ipv4", "on"); } else { /* hostname */ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { @@ -450,9 +450,9 @@ static int inet_parse(QemuOpts *opts, const char *str) if (h) qemu_opt_set(opts, "to", h+4); if (strstr(optstr, ",ipv4")) - qemu_opt_set(opts, "ipv4", "yes"); + qemu_opt_set(opts, "ipv4", "on"); if (strstr(optstr, ",ipv6")) - qemu_opt_set(opts, "ipv6", "yes"); + qemu_opt_set(opts, "ipv6", "on"); return 0; } diff --git a/qemu-tech.texi b/qemu-tech.texi index 97d8dea3bc..2e2a081d92 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -1,11 +1,21 @@ \input texinfo @c -*- texinfo -*- @c %**start of header @setfilename qemu-tech.info + +@documentlanguage en +@documentencoding UTF-8 + @settitle QEMU Internals @exampleindent 0 @paragraphindent 0 @c %**end of header +@ifinfo +@direntry +* QEMU Internals: (qemu-tech). The QEMU Emulator Internals. +@end direntry +@end ifinfo + @iftex @titlepage @sp 7 diff --git a/qemu-timer.h b/qemu-timer.h index e7eaa0436c..c17b4e6058 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -25,6 +25,7 @@ extern QEMUClock *vm_clock; extern QEMUClock *host_clock; int64_t qemu_get_clock(QEMUClock *clock); +int64_t qemu_get_clock_ns(QEMUClock *clock); QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); void qemu_free_timer(QEMUTimer *ts); @@ -53,6 +53,10 @@ QObject *qobject_from_json(const char *string) return qobject_from_jsonv(string, NULL); } +/* + * IMPORTANT: This function aborts on error, thus it must not + * be used with untrusted arguments. + */ QObject *qobject_from_jsonf(const char *string, ...) { QObject *obj; @@ -62,6 +66,7 @@ QObject *qobject_from_jsonf(const char *string, ...) obj = qobject_from_jsonv(string, &ap); va_end(ap); + assert(obj != NULL); return obj; } diff --git a/slirp/misc.c b/slirp/misc.c index 05f4fb329f..dcb1dc117b 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -179,7 +179,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty) close(s); i = 0; - bptr = strdup(ex); /* No need to free() this */ + bptr = qemu_strdup(ex); /* No need to free() this */ if (do_pty == 1) { /* Setup "slirp.telnetd -x" */ argv[i++] = "slirp.telnetd"; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5b093ce3bf..0d08cd532e 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -99,12 +99,18 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg) break; case R_EDX: ret = cpuid->entries[i].edx; - if (function == 0x80000001) { + switch (function) { + case 1: + /* KVM before 2.6.30 misreports the following features */ + ret |= CPUID_MTRR | CPUID_PAT | CPUID_MCE | CPUID_MCA; + break; + case 0x80000001: /* On Intel, kvm returns cpuid according to the Intel spec, * so add missing bits according to the AMD spec: */ cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, R_EDX); ret |= cpuid_1_edx & 0xdfeff7ff; + break; } break; } @@ -794,6 +800,9 @@ static int kvm_put_vcpu_events(CPUState *env) events.sipi_vector = env->sipi_vector; + events.flags = + KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR; + return kvm_vcpu_ioctl(env, KVM_SET_VCPU_EVENTS, &events); #else return 0; diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 366e7986ed..85f221d978 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -72,21 +72,20 @@ * The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification. */ -/* XXXXX The structure could be made more compact */ typedef struct tlb_t { - uint8_t asid; /* address space identifier */ uint32_t vpn; /* virtual page number */ - uint8_t v; /* validity */ uint32_t ppn; /* physical page number */ - uint8_t sz; /* page size */ - uint32_t size; /* cached page size in bytes */ - uint8_t sh; /* share status */ - uint8_t c; /* cacheability */ - uint8_t pr; /* protection key */ - uint8_t d; /* dirty */ - uint8_t wt; /* write through */ - uint8_t sa; /* space attribute (PCMCIA) */ - uint8_t tc; /* timing control */ + uint32_t size; /* mapped page size in bytes */ + uint8_t asid; /* address space identifier */ + uint8_t v:1; /* validity */ + uint8_t sz:2; /* page size */ + uint8_t sh:1; /* share status */ + uint8_t c:1; /* cacheability */ + uint8_t pr:2; /* protection key */ + uint8_t d:1; /* dirty */ + uint8_t wt:1; /* write through */ + uint8_t sa:3; /* space attribute (PCMCIA) */ + uint8_t tc:1; /* timing control */ } tlb_t; #define UTLB_SIZE 64 @@ -167,6 +166,7 @@ int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw, void do_interrupt(CPUSH4State * env); void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void cpu_sh4_invalidate_tlb(CPUSH4State *s); void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value); @@ -222,6 +222,7 @@ enum { /* MMU control register */ #define MMUCR 0x1F000010 #define MMUCR_AT (1<<0) +#define MMUCR_TI (1<<2) #define MMUCR_SV (1<<8) #define MMUCR_URC_BITS (6) #define MMUCR_URC_OFFSET (10) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 088d36a5f7..f38e6abdaf 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -261,24 +261,6 @@ static int find_tlb_entry(CPUState * env, target_ulong address, continue; /* Invalid entry */ if (!entries[i].sh && use_asid && entries[i].asid != asid) continue; /* Bad ASID */ -#if 0 - switch (entries[i].sz) { - case 0: - size = 1024; /* 1kB */ - break; - case 1: - size = 4 * 1024; /* 4kB */ - break; - case 2: - size = 64 * 1024; /* 64kB */ - break; - case 3: - size = 1024 * 1024; /* 1MB */ - break; - default: - assert(0); - } -#endif start = (entries[i].vpn << 10) & ~(entries[i].size - 1); end = start + entries[i].size - 1; if (address >= start && address <= end) { /* Match */ @@ -290,16 +272,6 @@ static int find_tlb_entry(CPUState * env, target_ulong address, return match; } -static int same_tlb_entry_exists(const tlb_t * haystack, uint8_t nbtlb, - const tlb_t * needle) -{ - int i; - for (i = 0; i < nbtlb; i++) - if (!memcmp(&haystack[i], needle, sizeof(tlb_t))) - return 1; - return 0; -} - static void increment_urc(CPUState * env) { uint8_t urb, urc; @@ -332,8 +304,7 @@ static int find_itlb_entry(CPUState * env, target_ulong address, n = itlb_replacement(env); ientry = &env->itlb[n]; if (ientry->v) { - if (!same_tlb_entry_exists(env->utlb, UTLB_SIZE, ientry)) - tlb_flush_page(env, ientry->vpn << 10); + tlb_flush_page(env, ientry->vpn << 10); } *ientry = env->utlb[e]; e = n; @@ -377,47 +348,37 @@ static int get_mmu_address(CPUState * env, target_ulong * physical, n = find_itlb_entry(env, address, use_asid, 1); if (n >= 0) { matching = &env->itlb[n]; - if ((env->sr & SR_MD) & !(matching->pr & 2)) + if (!(env->sr & SR_MD) && !(matching->pr & 2)) n = MMU_ITLB_VIOLATION; else - *prot = PAGE_READ; + *prot = PAGE_EXEC; } } else { n = find_utlb_entry(env, address, use_asid); if (n >= 0) { matching = &env->utlb[n]; - switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) { - case 0: /* 000 */ - case 2: /* 010 */ - n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE : - MMU_DTLB_VIOLATION_READ; - break; - case 1: /* 001 */ - case 4: /* 100 */ - case 5: /* 101 */ - if (rw == 1) - n = MMU_DTLB_VIOLATION_WRITE; - else - *prot = PAGE_READ; - break; - case 3: /* 011 */ - case 6: /* 110 */ - case 7: /* 111 */ - *prot = (rw == 1)? PAGE_WRITE : PAGE_READ; - break; - } + if (!(env->sr & SR_MD) && !(matching->pr & 2)) { + n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE : + MMU_DTLB_VIOLATION_READ; + } else if ((rw == 1) && !(matching->pr & 1)) { + n = MMU_DTLB_VIOLATION_WRITE; + } else if ((rw == 1) & !matching->d) { + n = MMU_DTLB_INITIAL_WRITE; + } else { + *prot = PAGE_READ; + if ((matching->pr & 1) && matching->d) { + *prot |= PAGE_WRITE; + } + } } else if (n == MMU_DTLB_MISS) { n = (rw == 1) ? MMU_DTLB_MISS_WRITE : MMU_DTLB_MISS_READ; } } if (n >= 0) { + n = MMU_OK; *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | (address & (matching->size - 1)); - if ((rw == 1) & !matching->d) - n = MMU_DTLB_INITIAL_WRITE; - else - n = MMU_OK; } return n; } @@ -430,7 +391,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical, if ((address >= 0x80000000 && address < 0xc0000000) || address >= 0xe0000000) { if (!(env->sr & SR_MD) - && (address < 0xe0000000 || address > 0xe4000000)) { + && (address < 0xe0000000 || address >= 0xe4000000)) { /* Unauthorized access in user mode (only store queues are available) */ fprintf(stderr, "Unauthorized access\n"); if (rw == 0) @@ -446,14 +407,14 @@ static int get_physical_address(CPUState * env, target_ulong * physical, } else { *physical = address; } - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return MMU_OK; } /* If MMU is disabled, return the corresponding physical page */ if (!env->mmucr & MMUCR_AT) { *physical = address & 0x1FFFFFFF; - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return MMU_OK; } @@ -464,7 +425,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical, int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { - target_ulong physical, page_offset, page_size; + target_ulong physical; int prot, ret, access_type; access_type = ACCESS_INT; @@ -511,11 +472,8 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, return 1; } - page_size = TARGET_PAGE_SIZE; - page_offset = - (address - (address & TARGET_PAGE_MASK)) & ~(page_size - 1); - address = (address & TARGET_PAGE_MASK) + page_offset; - physical = (physical & TARGET_PAGE_MASK) + page_offset; + address &= TARGET_PAGE_MASK; + physical &= TARGET_PAGE_MASK; return tlb_set_page(env, address, physical, prot, mmu_idx, is_softmmu); } @@ -537,9 +495,7 @@ void cpu_load_tlb(CPUSH4State * env) if (entry->v) { /* Overwriting valid entry in utlb. */ target_ulong address = entry->vpn << 10; - if (!same_tlb_entry_exists(env->itlb, ITLB_SIZE, entry)) { - tlb_flush_page(env, address); - } + tlb_flush_page(env, address); } /* Take values into cpu status from registers. */ @@ -574,6 +530,24 @@ void cpu_load_tlb(CPUSH4State * env) entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); } + void cpu_sh4_invalidate_tlb(CPUSH4State *s) +{ + int i; + + /* UTLB */ + for (i = 0; i < UTLB_SIZE; i++) { + tlb_t * entry = &s->utlb[i]; + entry->v = 0; + } + /* ITLB */ + for (i = 0; i < UTLB_SIZE; i++) { + tlb_t * entry = &s->utlb[i]; + entry->v = 0; + } + + tlb_flush(s, 1); +} + void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value) { @@ -636,9 +610,7 @@ void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, if (entry->v) { /* Overwriting valid entry in utlb. */ target_ulong address = entry->vpn << 10; - if (!same_tlb_entry_exists(s->itlb, ITLB_SIZE, entry)) { - tlb_flush_page(s, address); - } + tlb_flush_page(s, address); } entry->asid = asid; entry->vpn = vpn; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 895b978d38..bff3188575 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -664,7 +664,7 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 1); tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx); /* might cause re-execution */ - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1); /* modify register status */ + tcg_gen_mov_i32(REG(B11_8), addr); /* modify register status */ tcg_temp_free(addr); } return; @@ -673,7 +673,7 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 2); tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 2); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); } return; @@ -682,7 +682,7 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); + tcg_gen_mov_i32(REG(B11_8), addr); } return; case 0x6004: /* mov.b @Rm+,Rn */ @@ -750,17 +750,13 @@ static void _decode_opc(DisasContext * ctx) return; case 0x6008: /* swap.b Rm,Rn */ { - TCGv highw, high, low; - highw = tcg_temp_new(); - tcg_gen_andi_i32(highw, REG(B7_4), 0xffff0000); + TCGv high, low; high = tcg_temp_new(); - tcg_gen_ext8u_i32(high, REG(B7_4)); - tcg_gen_shli_i32(high, high, 8); + tcg_gen_andi_i32(high, REG(B7_4), 0xffff0000); low = tcg_temp_new(); - tcg_gen_shri_i32(low, REG(B7_4), 8); - tcg_gen_ext8u_i32(low, low); + tcg_gen_ext16u_i32(low, REG(B7_4)); + tcg_gen_bswap16_i32(low, low); tcg_gen_or_i32(REG(B11_8), high, low); - tcg_gen_or_i32(REG(B11_8), REG(B11_8), highw); tcg_temp_free(low); tcg_temp_free(high); } @@ -769,8 +765,7 @@ static void _decode_opc(DisasContext * ctx) { TCGv high, low; high = tcg_temp_new(); - tcg_gen_ext16u_i32(high, REG(B7_4)); - tcg_gen_shli_i32(high, high, 16); + tcg_gen_shli_i32(high, REG(B7_4), 16); low = tcg_temp_new(); tcg_gen_shri_i32(low, REG(B7_4), 16); tcg_gen_ext16u_i32(low, low); @@ -783,8 +778,7 @@ static void _decode_opc(DisasContext * ctx) { TCGv high, low; high = tcg_temp_new(); - tcg_gen_ext16u_i32(high, REG(B7_4)); - tcg_gen_shli_i32(high, high, 16); + tcg_gen_shli_i32(high, REG(B7_4), 16); low = tcg_temp_new(); tcg_gen_shri_i32(low, REG(B11_8), 16); tcg_gen_ext16u_i32(low, low); @@ -974,20 +968,24 @@ static void _decode_opc(DisasContext * ctx) int label2 = gen_new_label(); int label3 = gen_new_label(); int label4 = gen_new_label(); - TCGv shift = tcg_temp_local_new(); + TCGv shift; tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1); /* Rm positive, shift to the left */ + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label4); /* Rm negative, shift to the right */ gen_set_label(label1); + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2); tcg_gen_not_i32(shift, REG(B7_4)); tcg_gen_andi_i32(shift, shift, 0x1f); tcg_gen_addi_i32(shift, shift, 1); tcg_gen_sar_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label4); /* Rm = -32 */ gen_set_label(label2); @@ -997,7 +995,6 @@ static void _decode_opc(DisasContext * ctx) gen_set_label(label3); tcg_gen_movi_i32(REG(B11_8), 0xffffffff); gen_set_label(label4); - tcg_temp_free(shift); } return; case 0x400d: /* shld Rm,Rn */ @@ -1005,26 +1002,29 @@ static void _decode_opc(DisasContext * ctx) int label1 = gen_new_label(); int label2 = gen_new_label(); int label3 = gen_new_label(); - TCGv shift = tcg_temp_local_new(); + TCGv shift; tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1); /* Rm positive, shift to the left */ + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label3); /* Rm negative, shift to the right */ gen_set_label(label1); + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2); tcg_gen_not_i32(shift, REG(B7_4)); tcg_gen_andi_i32(shift, shift, 0x1f); tcg_gen_addi_i32(shift, shift, 1); tcg_gen_shr_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label3); /* Rm = -32 */ gen_set_label(label2); tcg_gen_movi_i32(REG(B11_8), 0); gen_set_label(label3); - tcg_temp_free(shift); } return; case 0x3008: /* sub Rm,Rn */ @@ -1106,7 +1106,7 @@ static void _decode_opc(DisasContext * ctx) int fr = XREG(B7_4); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(cpu_fregs[fr+1], addr, ctx->memidx); - tcg_gen_subi_i32(addr, REG(B11_8), 8); + tcg_gen_subi_i32(addr, addr, 4); tcg_gen_qemu_st32(cpu_fregs[fr ], addr, ctx->memidx); tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); @@ -1115,8 +1115,8 @@ static void _decode_opc(DisasContext * ctx) addr = tcg_temp_new_i32(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ @@ -1436,8 +1436,8 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(ALTREG(B6_4), addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; } @@ -1505,8 +1505,8 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(cpu_sr, addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; #define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \ @@ -1526,11 +1526,11 @@ static void _decode_opc(DisasContext * ctx) case stpnum: \ prechk \ { \ - TCGv addr = tcg_temp_new(); \ + TCGv addr = tcg_temp_new(); \ tcg_gen_subi_i32(addr, REG(B11_8), 4); \ tcg_gen_qemu_st32 (cpu_##reg, addr, ctx->memidx); \ + tcg_gen_mov_i32(REG(B11_8), addr); \ tcg_temp_free(addr); \ - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); \ } \ return; LDST(gbr, 0x401e, 0x4017, 0x0012, 0x4013, {}) @@ -1571,9 +1571,9 @@ static void _decode_opc(DisasContext * ctx) addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(val, addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); tcg_temp_free(val); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; case 0x00c3: /* movca.l R0,@Rm */ @@ -1905,7 +1905,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ctx.bstate = BS_NONE; ctx.sr = env->sr; ctx.fpscr = env->fpscr; - ctx.memidx = (env->sr & SR_MD) ? 1 : 0; + ctx.memidx = (env->sr & SR_MD) == 0 ? 1 : 0; /* We don't know if the delayed pc came from a dynamic or static branch, so assume it is a dynamic branch. */ ctx.delayed_pc = -1; /* use delayed pc from env pointer */ diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 8fcb5c99c3..ec687ad6f6 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -274,6 +274,8 @@ enum { OPC_BEQ = 0x04 << 26, OPC_BNE = 0x05 << 26, OPC_ADDIU = 0x09 << 26, + OPC_SLTI = 0x0A << 26, + OPC_SLTIU = 0x0B << 26, OPC_ANDI = 0x0C << 26, OPC_ORI = 0x0D << 26, OPC_XORI = 0x0E << 26, @@ -583,6 +585,128 @@ static void tcg_out_brcond2(TCGContext *s, int cond, int arg1, reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); } +static void tcg_out_setcond(TCGContext *s, int cond, int ret, + int arg1, int arg2) +{ + switch (cond) { + case TCG_COND_EQ: + if (arg1 == 0) { + tcg_out_opc_imm(s, OPC_SLTIU, ret, arg2, 1); + } else if (arg2 == 0) { + tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, 1); + } else { + tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2); + tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1); + } + break; + case TCG_COND_NE: + if (arg1 == 0) { + tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg2); + } else if (arg2 == 0) { + tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg1); + } else { + tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2); + tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret); + } + break; + case TCG_COND_LT: + tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2); + break; + case TCG_COND_LTU: + tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2); + break; + case TCG_COND_GE: + tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2); + tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); + break; + case TCG_COND_GEU: + tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2); + tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); + break; + case TCG_COND_LE: + tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1); + tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); + break; + case TCG_COND_LEU: + tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1); + tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); + break; + case TCG_COND_GT: + tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1); + break; + case TCG_COND_GTU: + tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1); + break; + default: + tcg_abort(); + break; + } +} + +/* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +static void tcg_out_setcond2(TCGContext *s, int cond, int ret, + int arg1, int arg2, int arg3, int arg4) +{ + switch (cond) { + case TCG_COND_EQ: + tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_AT, arg2, arg4); + tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg1, arg3); + tcg_out_opc_reg(s, OPC_AND, ret, TCG_REG_AT, TCG_REG_T0); + return; + case TCG_COND_NE: + tcg_out_setcond(s, TCG_COND_NE, TCG_REG_AT, arg2, arg4); + tcg_out_setcond(s, TCG_COND_NE, TCG_REG_T0, arg1, arg3); + tcg_out_opc_reg(s, OPC_OR, ret, TCG_REG_AT, TCG_REG_T0); + return; + case TCG_COND_LT: + case TCG_COND_LE: + tcg_out_setcond(s, TCG_COND_LT, TCG_REG_AT, arg2, arg4); + break; + case TCG_COND_GT: + case TCG_COND_GE: + tcg_out_setcond(s, TCG_COND_GT, TCG_REG_AT, arg2, arg4); + break; + case TCG_COND_LTU: + case TCG_COND_LEU: + tcg_out_setcond(s, TCG_COND_LTU, TCG_REG_AT, arg2, arg4); + break; + case TCG_COND_GTU: + case TCG_COND_GEU: + tcg_out_setcond(s, TCG_COND_GTU, TCG_REG_AT, arg2, arg4); + break; + default: + tcg_abort(); + break; + } + + tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg2, arg4); + + switch(cond) { + case TCG_COND_LT: + case TCG_COND_LTU: + tcg_out_setcond(s, TCG_COND_LTU, ret, arg1, arg3); + break; + case TCG_COND_LE: + case TCG_COND_LEU: + tcg_out_setcond(s, TCG_COND_LEU, ret, arg1, arg3); + break; + case TCG_COND_GT: + case TCG_COND_GTU: + tcg_out_setcond(s, TCG_COND_GTU, ret, arg1, arg3); + break; + case TCG_COND_GE: + case TCG_COND_GEU: + tcg_out_setcond(s, TCG_COND_GEU, ret, arg1, arg3); + break; + default: + tcg_abort(); + } + + tcg_out_opc_reg(s, OPC_AND, ret, ret, TCG_REG_T0); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); +} + #if defined(CONFIG_SOFTMMU) #include "../../softmmu_defs.h" @@ -731,9 +855,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, /* label1: fast path */ reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); - tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0, + tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); - tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl); addr_reg1 = TCG_REG_V0; #endif @@ -1155,6 +1279,13 @@ static inline void tcg_out_op(TCGContext *s, int opc, tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]); break; + case INDEX_op_setcond_i32: + tcg_out_setcond(s, args[3], args[0], args[1], args[2]); + break; + case INDEX_op_setcond2_i32: + tcg_out_setcond2(s, args[5], args[0], args[1], args[2], args[3], args[4]); + break; + case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); break; @@ -1228,6 +1359,8 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_sar_i32, { "r", "rZ", "riZ" } }, { INDEX_op_brcond_i32, { "rZ", "rZ" } }, + { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } }, { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 70a75a08f4..13eaa5a9e8 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -589,6 +589,20 @@ static inline void tcg_gen_brcondi_i32(int cond, TCGv_i32 arg1, int32_t arg2, tcg_temp_free_i32(t0); } +static inline void tcg_gen_setcond_i32(int cond, TCGv_i32 ret, + TCGv_i32 arg1, TCGv_i32 arg2) +{ + tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); +} + +static inline void tcg_gen_setcondi_i32(int cond, TCGv_i32 ret, TCGv_i32 arg1, + int32_t arg2) +{ + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_setcond_i32(cond, ret, arg1, t0); + tcg_temp_free_i32(t0); +} + static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2); @@ -851,6 +865,15 @@ static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGV_HIGH(arg2), cond, label_index); } +static inline void tcg_gen_setcond_i64(int cond, TCGv_i64 ret, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), + TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); +} + static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { TCGv_i64 t0; @@ -1081,6 +1104,12 @@ static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2, tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); } +static inline void tcg_gen_setcond_i64(int cond, TCGv_i64 ret, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); +} + static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2); @@ -1184,6 +1213,14 @@ static inline void tcg_gen_brcondi_i64(int cond, TCGv_i64 arg1, int64_t arg2, tcg_temp_free_i64(t0); } +static inline void tcg_gen_setcondi_i64(int cond, TCGv_i64 ret, TCGv_i64 arg1, + int64_t arg2) +{ + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_setcond_i64(cond, ret, arg1, t0); + tcg_temp_free_i64(t0); +} + static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) { TCGv_i64 t0 = tcg_const_i64(arg2); @@ -1821,25 +1858,6 @@ static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) } } -static inline void tcg_gen_setcond_i32(int cond, TCGv_i32 ret, - TCGv_i32 arg1, TCGv_i32 arg2) -{ - tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); -} - -static inline void tcg_gen_setcond_i64(int cond, TCGv_i64 ret, - TCGv_i64 arg1, TCGv_i64 arg2) -{ -#if TCG_TARGET_REG_BITS == 64 - tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); -#else - tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), - TCGV_LOW(arg1), TCGV_HIGH(arg1), - TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); - tcg_gen_movi_i32(TCGV_HIGH(ret), 0); -#endif -} - /***************************************/ /* QEMU specific operations. Their type depend on the QEMU CPU type. */ @@ -2113,6 +2131,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_gen_brcond_tl tcg_gen_brcond_i64 #define tcg_gen_brcondi_tl tcg_gen_brcondi_i64 #define tcg_gen_setcond_tl tcg_gen_setcond_i64 +#define tcg_gen_setcondi_tl tcg_gen_setcondi_i64 #define tcg_gen_mul_tl tcg_gen_mul_i64 #define tcg_gen_muli_tl tcg_gen_muli_i64 #define tcg_gen_div_tl tcg_gen_div_i64 @@ -2184,6 +2203,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_gen_brcond_tl tcg_gen_brcond_i32 #define tcg_gen_brcondi_tl tcg_gen_brcondi_i32 #define tcg_gen_setcond_tl tcg_gen_setcond_i32 +#define tcg_gen_setcondi_tl tcg_gen_setcondi_i32 #define tcg_gen_mul_tl tcg_gen_mul_i32 #define tcg_gen_muli_tl tcg_gen_muli_i32 #define tcg_gen_div_tl tcg_gen_div_i32 @@ -931,6 +931,23 @@ int64_t qemu_get_clock(QEMUClock *clock) } } +int64_t qemu_get_clock_ns(QEMUClock *clock) +{ + switch(clock->type) { + case QEMU_CLOCK_REALTIME: + return get_clock(); + default: + case QEMU_CLOCK_VIRTUAL: + if (use_icount) { + return cpu_get_icount(); + } else { + return cpu_get_clock(); + } + case QEMU_CLOCK_HOST: + return get_clock_realtime(); + } +} + static void init_clocks(void) { init_get_clock(); @@ -2866,7 +2883,7 @@ static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) } bytes_transferred_last = bytes_transferred; - bwidth = get_clock(); + bwidth = qemu_get_clock_ns(rt_clock); while (!qemu_file_rate_limit(f)) { int ret; @@ -2877,7 +2894,7 @@ static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) break; } - bwidth = get_clock() - bwidth; + bwidth = qemu_get_clock_ns(rt_clock) - bwidth; bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; /* if we haven't transferred anything this round, force expected_time to a @@ -2996,6 +3013,7 @@ static void gui_update(void *opaque) DisplayState *ds = opaque; DisplayChangeListener *dcl = ds->listeners; + qemu_flush_coalesced_mmio_buffer(); dpy_refresh(ds); while (dcl != NULL) { @@ -3011,6 +3029,7 @@ static void nographic_update(void *opaque) { uint64_t interval = GUI_REFRESH_INTERVAL; + qemu_flush_coalesced_mmio_buffer(); qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock)); } @@ -3198,8 +3217,12 @@ static void qemu_event_increment(void) if (io_thread_fd == -1) return; - ret = write(io_thread_fd, &byte, sizeof(byte)); - if (ret < 0 && (errno != EINTR && errno != EAGAIN)) { + do { + ret = write(io_thread_fd, &byte, sizeof(byte)); + } while (ret < 0 && errno == EINTR); + + /* EAGAIN is fine, a read must be pending. */ + if (ret < 0 && errno != EAGAIN) { fprintf(stderr, "qemu_event_increment: write() filed: %s\n", strerror(errno)); exit (1); @@ -3210,12 +3233,12 @@ static void qemu_event_read(void *opaque) { int fd = (unsigned long)opaque; ssize_t len; + char buffer[512]; /* Drain the notify pipe */ do { - char buffer[512]; len = read(fd, buffer, sizeof(buffer)); - } while ((len == -1 && errno == EINTR) || len > 0); + } while ((len == -1 && errno == EINTR) || len == sizeof(buffer)); } static int qemu_event_init(void) @@ -3280,6 +3303,8 @@ static int cpu_can_run(CPUState *env) return 0; if (env->stopped) return 0; + if (!vm_running) + return 0; return 1; } @@ -3851,14 +3876,15 @@ static void tcg_cpu_exec(void) for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) { CPUState *env = cur_cpu = next_cpu; - if (!vm_running) - break; if (timer_alarm_pending) { timer_alarm_pending = 0; break; } if (cpu_can_run(env)) ret = qemu_cpu_exec(env); + else if (env->stop) + break; + if (ret == EXCP_DEBUG) { gdb_set_stop_cpu(env); debug_requested = 1; @@ -356,17 +356,14 @@ void do_info_vnc(Monitor *mon, QObject **ret_data) *ret_data = qobject_from_jsonf("{ 'enabled': false }"); } else { QList *clist; + VncState *client; clist = qlist_new(); - if (vnc_display->clients) { - VncState *client = vnc_display->clients; - while (client) { - if (client->info) { - /* incref so that it's not freed by upper layers */ - qobject_incref(client->info); - qlist_append_obj(clist, client->info); - } - client = client->next; + QTAILQ_FOREACH(client, &vnc_display->clients, next) { + if (client->info) { + /* incref so that it's not freed by upper layers */ + qobject_incref(client->info); + qlist_append_obj(clist, client->info); } } @@ -519,7 +516,7 @@ static void vnc_dpy_resize(DisplayState *ds) { int size_changed; VncDisplay *vd = ds->opaque; - VncState *vs = vd->clients; + VncState *vs; /* server surface */ if (!vd->server) @@ -540,7 +537,7 @@ static void vnc_dpy_resize(DisplayState *ds) *(vd->guest.ds) = *(ds->surface); memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty)); - while (vs != NULL) { + QTAILQ_FOREACH(vs, &vd->clients, next) { vnc_colordepth(vs); if (size_changed) { if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { @@ -553,7 +550,6 @@ static void vnc_dpy_resize(DisplayState *ds) } } memset(vs->dirty, 0xFF, sizeof(vs->dirty)); - vs = vs->next; } } @@ -867,8 +863,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int int cmp_bytes; vnc_refresh_server_surface(vd); - for (vs = vd->clients; vs != NULL; vs = vn) { - vn = vs->next; + QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { vs->force_update = 1; vnc_update_client(vs, 1); @@ -912,11 +907,10 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int if (memcmp(src_row, dst_row, cmp_bytes) == 0) continue; memmove(dst_row, src_row, cmp_bytes); - vs = vd->clients; - while (vs != NULL) { - if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) + QTAILQ_FOREACH(vs, &vd->clients, next) { + if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16)); - vs = vs->next; + } } } src_row += pitch - w * depth; @@ -924,9 +918,10 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int y += inc; } - for (vs = vd->clients; vs != NULL; vs = vs->next) { - if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) + QTAILQ_FOREACH(vs, &vd->clients, next) { + if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h); + } } } @@ -1109,19 +1104,11 @@ static void vnc_disconnect_finish(VncState *vs) #endif /* CONFIG_VNC_SASL */ audio_del(vs); - VncState *p, *parent = NULL; - for (p = vs->vd->clients; p != NULL; p = p->next) { - if (p == vs) { - if (parent) - parent->next = p->next; - else - vs->vd->clients = p->next; - break; - } - parent = p; - } - if (!vs->vd->clients) + QTAILQ_REMOVE(&vs->vd->clients, vs, next); + + if (QTAILQ_EMPTY(&vs->vd->clients)) { dcl->idle = 1; + } vnc_remove_timer(vs->vd); qemu_free(vs); @@ -2299,7 +2286,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd) uint8_t *server_row; int cmp_bytes; uint32_t width_mask[VNC_DIRTY_WORDS]; - VncState *vs = NULL; + VncState *vs; int has_dirty = 0; /* @@ -2328,10 +2315,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd) if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) continue; memcpy(server_ptr, guest_ptr, cmp_bytes); - vs = vd->clients; - while (vs != NULL) { + QTAILQ_FOREACH(vs, &vd->clients, next) { vnc_set_bit(vs->dirty[y], (x / 16)); - vs = vs->next; } has_dirty++; } @@ -2345,19 +2330,16 @@ static int vnc_refresh_server_surface(VncDisplay *vd) static void vnc_refresh(void *opaque) { VncDisplay *vd = opaque; - VncState *vs = NULL, *vn = NULL; - int has_dirty = 0, rects = 0; + VncState *vs, *vn; + int has_dirty, rects = 0; vga_hw_update(); has_dirty = vnc_refresh_server_surface(vd); - vs = vd->clients; - while (vs != NULL) { - vn = vs->next; + QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { rects += vnc_update_client(vs, has_dirty); /* vs might be free()ed here */ - vs = vn; } /* vd->timer could be NULL now if the last client disconnected, * in this case don't update the timer */ @@ -2379,7 +2361,7 @@ static void vnc_refresh(void *opaque) static void vnc_init_timer(VncDisplay *vd) { vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; - if (vd->timer == NULL && vd->clients != NULL) { + if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) { vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd); vnc_refresh(vd); } @@ -2387,7 +2369,7 @@ static void vnc_init_timer(VncDisplay *vd) static void vnc_remove_timer(VncDisplay *vd) { - if (vd->timer != NULL && vd->clients == NULL) { + if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) { qemu_del_timer(vd->timer); qemu_free_timer(vd->timer); vd->timer = NULL; @@ -2417,8 +2399,7 @@ static void vnc_connect(VncDisplay *vd, int csock) vs->as.fmt = AUD_FMT_S16; vs->as.endianness = 0; - vs->next = vd->clients; - vd->clients = vs; + QTAILQ_INSERT_HEAD(&vd->clients, vs, next); vga_hw_update(); @@ -2460,6 +2441,7 @@ void vnc_display_init(DisplayState *ds) vs->lsock = -1; vs->ds = ds; + QTAILQ_INIT(&vs->clients); if (keyboard_layout) vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); @@ -28,6 +28,7 @@ #define __QEMU_VNC_H #include "qemu-common.h" +#include "qemu-queue.h" #include "console.h" #include "monitor.h" #include "audio/audio.h" @@ -68,7 +69,7 @@ typedef void VncSendHextileTile(VncState *vs, void *last_fg, int *has_bg, int *has_fg); -#define VNC_MAX_WIDTH 2048 +#define VNC_MAX_WIDTH 2560 #define VNC_MAX_HEIGHT 2048 #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) @@ -92,11 +93,11 @@ struct VncSurface struct VncDisplay { + QTAILQ_HEAD(, VncState) clients; QEMUTimer *timer; int timer_interval; int lsock; DisplayState *ds; - VncState *clients; kbd_layout_t *kbd_layout; struct VncSurface guest; /* guest visible surface (aka ds->surface) */ @@ -165,7 +166,7 @@ struct VncState Buffer zlib_tmp; z_stream zlib_stream[4]; - VncState *next; + QTAILQ_ENTRY(VncState) next; }; |