summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile21
-rw-r--r--QMP/README6
-rw-r--r--QMP/qmp-events.txt21
-rw-r--r--QMP/qmp-spec.txt52
-rw-r--r--block-migration.c235
-rw-r--r--block.c69
-rw-r--r--block.h7
-rw-r--r--block/curl.c4
-rw-r--r--block/qcow2-cluster.c12
-rw-r--r--block/qcow2.h6
-rw-r--r--block/vvfat.c10
-rw-r--r--block_int.h28
-rwxr-xr-xconfigure9
-rw-r--r--cpu-all.h2
-rw-r--r--cpu-common.h19
-rw-r--r--cpu-defs.h3
-rw-r--r--exec.c116
-rw-r--r--hw/ide/core.c18
-rw-r--r--hw/ide/internal.h7
-rw-r--r--hw/ide/qdev.c7
-rw-r--r--hw/pci-hotplug.c1
-rw-r--r--hw/r2d.c9
-rw-r--r--hw/s390-virtio-bus.c4
-rw-r--r--hw/s390-virtio-bus.h2
-rw-r--r--hw/scsi-disk.c97
-rw-r--r--hw/scsi-generic.c24
-rw-r--r--hw/scsi.h3
-rw-r--r--hw/sh7750.c7
-rw-r--r--hw/usb-msd.c12
-rw-r--r--hw/usb-serial.c28
-rw-r--r--hw/usb-uhci.c67
-rw-r--r--hw/virtio-blk.c77
-rw-r--r--hw/virtio-blk.h12
-rw-r--r--hw/virtio-net.c10
-rw-r--r--hw/virtio-pci.c11
-rw-r--r--hw/virtio.h3
-rw-r--r--hw/vmport.c3
-rw-r--r--json-lexer.c16
-rw-r--r--json-parser.c3
-rw-r--r--kvm-all.c355
-rw-r--r--kvm.h9
-rw-r--r--migration.c3
-rw-r--r--monitor.c68
-rw-r--r--monitor.h1
-rw-r--r--net.c2
-rw-r--r--osdep.c7
-rw-r--r--qemu-char.c3
-rw-r--r--qemu-doc.texi256
-rw-r--r--qemu-img.c29
-rw-r--r--qemu-monitor.hx76
-rw-r--r--qemu-options.hx153
-rw-r--r--qemu-sockets.c8
-rw-r--r--qemu-tech.texi10
-rw-r--r--qemu-timer.h1
-rw-r--r--qjson.c5
-rw-r--r--slirp/misc.c2
-rw-r--r--target-i386/kvm.c11
-rw-r--r--target-sh4/cpu.h25
-rw-r--r--target-sh4/helper.c114
-rw-r--r--target-sh4/translate.c54
-rw-r--r--tcg/mips/tcg-target.c137
-rw-r--r--tcg/tcg-op.h58
-rw-r--r--vl.c42
-rw-r--r--vnc.c74
-rw-r--r--vnc.h7
66 files changed, 1805 insertions, 747 deletions
diff --git a/.gitignore b/.gitignore
index d7d2146..dfc8e5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ qemu-monitor.texi
*.fn
*.ky
*.log
+*.pdf
*.pg
*.toc
*.tp
diff --git a/Makefile b/Makefile
index 24938db..c72a059 100644
--- a/Makefile
+++ b/Makefile
@@ -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 09e7053..9334c25 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 dc48ccc..d585a8d 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 56f388c..f3c0327 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 230d7ed..92349a2 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 */
diff --git a/block.c b/block.c
index 1919d19..af56ea7 100644
--- a/block.c
+++ b/block.c
@@ -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;
+}
diff --git a/block.h b/block.h
index ecf66c5..edf5704 100644
--- a/block.h
+++ b/block.h
@@ -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 86ac81b..2cf72cb 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 4e30d16..3501a94 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 d9ea6ab..de9397a 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 d2787b9..bb707c0 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 a0ebd90..930a5a4 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 */
diff --git a/configure b/configure
index dad3bb5..0a84b0e 100755
--- a/configure
+++ b/configure
@@ -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`"
diff --git a/cpu-all.h b/cpu-all.h
index 57b69f8..1ccc9a8 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -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 6302372..0ec9b72 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 95068b5..7fdbe97 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
diff --git a/exec.c b/exec.c
index b0caf7c..8389c54 100644
--- a/exec.c
+++ b/exec.c
@@ -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 b6643e8..37a5151 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 1cc4b55..9945993 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 0b84a4f..b18693d 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 ba13d2b..0fb96f0 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);
}
diff --git a/hw/r2d.c b/hw/r2d.c
index e4c02f0..8769a12 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -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 6b6dafc..fa0a74f 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 8e4763a..0ea8f54 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 b34fbaa..b2f61fe 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 f60ad96..de778ef 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(),
},
};
diff --git a/hw/scsi.h b/hw/scsi.h
index 8f0200d..b668e27 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -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 933bbc0..9c39f4b 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 1fb62ad..36991f8 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 37293ea..c3f3401 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 434070e..335b668 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 037a79c..b80402d 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 c28f776..f675375 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 6e48997..5c0093e 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 709d13e..f3373ae 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 62e882b..3baa2a3 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 884af3f..6c9d7c9 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 53697c5..9d64920 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 e04932f..f3debcb 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 *)));
diff --git a/kvm-all.c b/kvm-all.c
index 15ec38e..79345b2 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -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);
}
diff --git a/kvm.h b/kvm.h
index 1c93ac5..e24bbde 100644
--- a/kvm.h
+++ b/kvm.h
@@ -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 f20315f..2320c5f 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);
}
}
diff --git a/monitor.c b/monitor.c
index ff22123..ae125b8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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;
}
}
diff --git a/monitor.h b/monitor.h
index b0f9270..e35f1e4 100644
--- a/monitor.h
+++ b/monitor.h
@@ -23,6 +23,7 @@ typedef enum MonitorEvent {
QEVENT_VNC_CONNECTED,
QEVENT_VNC_INITIALIZED,
QEVENT_VNC_DISCONNECTED,
+ QEVENT_BLOCK_IO_ERROR,
QEVENT_MAX,
} MonitorEvent;
diff --git a/net.c b/net.c
index 6ef93e6..8e951ca 100644
--- a/net.c
+++ b/net.c
@@ -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;
diff --git a/osdep.c b/osdep.c
index cf3a2c6..9059f01 100644
--- a/osdep.c
+++ b/osdep.c
@@ -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 800ee6c..75dbf66 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 2fb5c0b..1494757 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 eb5c0f0..0db8d4f 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 e5bff8e..7f9d261 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 bb2d4fa..f53922f 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 d912fed..23c3def 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 97d8dea..2e2a081 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 e7eaa04..c17b4e6 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);
diff --git a/qjson.c b/qjson.c
index 9ad8a91..483c667 100644
--- a/qjson.c
+++ b/qjson.c
@@ -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 05f4fb3..dcb1dc1 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 5b093ce..0d08cd5 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 366e798..85f221d 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 088d36a..f38e6ab 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 895b978..bff3188 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 8fcb5c9..ec687ad 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 70a75a0..13eaa5a 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
diff --git a/vl.c b/vl.c
index 5ddf1fe..98918ac 100644
--- a/vl.c
+++ b/vl.c
@@ -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;
diff --git a/vnc.c b/vnc.c
index a49cff2..db34b0e 100644
--- a/vnc.c
+++ b/vnc.c
@@ -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);
diff --git a/vnc.h b/vnc.h
index 1210824..ff9a699 100644
--- a/vnc.h
+++ b/vnc.h
@@ -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;
};
OpenPOWER on IntegriCloud