Merge branch 'master' of git://git.qemu.org/qemu

This commit is contained in:
malc 2011-08-05 10:07:10 +04:00
commit a67a47d2b5
326 changed files with 10311 additions and 4186 deletions

3
.gitignore vendored
View File

@ -15,6 +15,7 @@ libdis*
libhw32
libhw64
libuser
qapi-generated
qemu-doc.html
qemu-tech.html
qemu-doc.info
@ -32,8 +33,10 @@ qemu-options.texi
qemu-img-cmds.texi
qemu-img-cmds.h
qemu-io
qemu-ga
qemu-monitor.texi
QMP/qmp-commands.txt
test-coroutine
.gdbinit
*.a
*.aux

View File

@ -68,6 +68,10 @@ keyword. Example:
printf("a was something else entirely.\n");
}
Note that 'else if' is considered a single statement; otherwise a long if/
else if/else if/.../else sequence would need an indent for every else
statement.
An exception is the opening brace for a function; for reasons of tradition
and clarity it comes on a line by itself:

View File

@ -431,9 +431,10 @@ S: Maintained
F: net/
SLIRP
M: qemu-devel@nongnu.org
S: Orphan
M: Jan Kiszka <jan.kiszka@siemens.com>
S: Maintained
F: slirp/
T: git://git.kiszka.org/qemu.git queues/slirp
Usermode Emulation
------------------

View File

@ -151,7 +151,7 @@ qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trac
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@")
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) qemu-tool.o
@ -161,6 +161,7 @@ check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(C
check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(CHECK_PROG_DEPS)
$(qapi-obj-y): $(GENERATED_HEADERS)
qapi-dir := qapi-generated
@ -168,22 +169,22 @@ test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-di
$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(qapi-dir)/qga-qapi-types.c: $(qapi-dir)/qga-qapi-types.h
$(qapi-dir)/qga-qapi-types.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
$(qapi-dir)/qga-qapi-visit.c: $(qapi-dir)/qga-qapi-visit.h
$(qapi-dir)/qga-qapi-visit.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
$(qapi-dir)/qga-qmp-marshal.c: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
@ -192,8 +193,10 @@ test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types
test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
QGALIB=qga/guest-agent-command-state.o qga/guest-agent-commands.o
QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c)
qemu-ga.o: $(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c) $(qapi-obj-y)
$(QGALIB_GEN): $(GENERATED_HEADERS)
$(QGALIB) qemu-ga.o: $(QGALIB_GEN) $(qapi-obj-y)
qemu-ga$(EXESUF): qemu-ga.o $(QGALIB) qemu-tool.o qemu-error.o error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) $(qapi-obj-y) qemu-timer-common.o qemu-sockets.o module.o qapi/qmp-dispatch.o qapi/qmp-registry.o $(qapi-dir)/qga-qapi-visit.o $(qapi-dir)/qga-qapi-types.o $(qapi-dir)/qga-qmp-marshal.o
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
@ -224,6 +227,7 @@ distclean: clean
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
rm -f qemu-doc.vr
rm -f config.log
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
for d in $(TARGET_DIRS) $(QEMULIBS); do \
rm -rf $$d || exit 1 ; \
@ -291,7 +295,7 @@ TAGS:
cscope:
rm -f ./cscope.*
find . -name "*.[ch]" -print | sed 's,^\./,,' > ./cscope.files
find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
cscope -b
# documentation

View File

@ -9,7 +9,7 @@ include $(SRC_PATH)/rules.mak
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
QEMU_CFLAGS+=-I..
include $(SRC_PATH)/Makefile.objs

View File

@ -10,11 +10,22 @@ oslib-obj-y = osdep.o
oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
#######################################################################
# coroutines
coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o
endif
coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
block-obj-y += $(coroutine-obj-y)
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
@ -89,6 +100,7 @@ common-obj-y += i2c.o smbus.o smbus_eeprom.o
common-obj-y += eeprom93xx.o
common-obj-y += scsi-disk.o cdrom.o
common-obj-y += scsi-generic.o scsi-bus.o
common-obj-y += hid.o
common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
common-obj-$(CONFIG_SSI) += ssi.o
@ -151,7 +163,7 @@ common-obj-y += qemu-timer.o qemu-timer-common.o
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
# xen backend driver support
@ -172,6 +184,7 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
hw-obj-y += usb-libhw.o
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o

View File

@ -72,7 +72,7 @@ all: $(PROGS) stap
#########################################################
# cpu emulator library
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
libobj-y += tcg/tcg.o
libobj-y += tcg/tcg.o tcg/optimize.o
libobj-y += fpu/softfloat.o
libobj-y += op_helper.o helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
@ -198,6 +198,7 @@ obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o
LIBS+=-lz
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
@ -351,6 +352,7 @@ obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
obj-arm-y += omap_sx1.o palm.o tsc210x.o
obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o

View File

@ -1 +1 @@
0.14.50
0.15.50

98
async.c
View File

@ -25,92 +25,8 @@
#include "qemu-common.h"
#include "qemu-aio.h"
/*
* An AsyncContext protects the callbacks of AIO requests and Bottom Halves
* against interfering with each other. A typical example is qcow2 that accepts
* asynchronous requests, but relies for manipulation of its metadata on
* synchronous bdrv_read/write that doesn't trigger any callbacks.
*
* However, these functions are often emulated using AIO which means that AIO
* callbacks must be run - but at the same time we must not run callbacks of
* other requests as they might start to modify metadata and corrupt the
* internal state of the caller of bdrv_read/write.
*
* To achieve the desired semantics we switch into a new AsyncContext.
* Callbacks must only be run if they belong to the current AsyncContext.
* Otherwise they need to be queued until their own context is active again.
* This is how you can make qemu_aio_wait() wait only for your own callbacks.
*
* The AsyncContexts form a stack. When you leave a AsyncContexts, you always
* return to the old ("parent") context.
*/
struct AsyncContext {
/* Consecutive number of the AsyncContext (position in the stack) */
int id;
/* Anchor of the list of Bottom Halves belonging to the context */
struct QEMUBH *first_bh;
/* Link to parent context */
struct AsyncContext *parent;
};
/* The currently active AsyncContext */
static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
/*
* Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
* won't be called until this context is left again.
*/
void async_context_push(void)
{
struct AsyncContext *new = qemu_mallocz(sizeof(*new));
new->parent = async_context;
new->id = async_context->id + 1;
async_context = new;
}
/* Run queued AIO completions and destroy Bottom Half */
static void bh_run_aio_completions(void *opaque)
{
QEMUBH **bh = opaque;
qemu_bh_delete(*bh);
qemu_free(bh);
qemu_aio_process_queue();
}
/*
* Leave the currently active AsyncContext. All Bottom Halves belonging to the
* old context are executed before changing the context.
*/
void async_context_pop(void)
{
struct AsyncContext *old = async_context;
QEMUBH **bh;
/* Flush the bottom halves, we don't want to lose them */
while (qemu_bh_poll());
/* Switch back to the parent context */
async_context = async_context->parent;
qemu_free(old);
if (async_context == NULL) {
abort();
}
/* Schedule BH to run any queued AIO completions as soon as possible */
bh = qemu_malloc(sizeof(*bh));
*bh = qemu_bh_new(bh_run_aio_completions, bh);
qemu_bh_schedule(*bh);
}
/*
* Returns the ID of the currently active AsyncContext
*/
int get_async_context_id(void)
{
return async_context->id;
}
/* Anchor of the list of Bottom Halves belonging to the context */
static struct QEMUBH *first_bh;
/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */
@ -130,8 +46,8 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
bh = qemu_mallocz(sizeof(QEMUBH));
bh->cb = cb;
bh->opaque = opaque;
bh->next = async_context->first_bh;
async_context->first_bh = bh;
bh->next = first_bh;
first_bh = bh;
return bh;
}
@ -141,7 +57,7 @@ int qemu_bh_poll(void)
int ret;
ret = 0;
for (bh = async_context->first_bh; bh; bh = next) {
for (bh = first_bh; bh; bh = next) {
next = bh->next;
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
@ -153,7 +69,7 @@ int qemu_bh_poll(void)
}
/* remove deleted bhs */
bhp = &async_context->first_bh;
bhp = &first_bh;
while (*bhp) {
bh = *bhp;
if (bh->deleted) {
@ -199,7 +115,7 @@ void qemu_bh_update_timeout(int *timeout)
{
QEMUBH *bh;
for (bh = async_context->first_bh; bh; bh = bh->next) {
for (bh = first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
if (bh->idle) {
/* idle bottom halves will be polled at least

View File

@ -1,7 +1,9 @@
/*
* QEMU System Emulator
* Generic Balloon handlers and management
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -30,44 +32,53 @@
#include "balloon.h"
#include "trace.h"
static QEMUBalloonEvent *balloon_event_fn;
static QEMUBalloonStatus *balloon_stat_fn;
static void *balloon_opaque;
static QEMUBalloonEvent *qemu_balloon_event;
void *qemu_balloon_event_opaque;
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque)
{
qemu_balloon_event = func;
qemu_balloon_event_opaque = opaque;
if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
/* We're already registered one balloon handler. How many can
* a guest really have?
*/
error_report("Another balloon device already registered");
return -1;
}
balloon_event_fn = event_func;
balloon_stat_fn = stat_func;
balloon_opaque = opaque;
return 0;
}
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
static int qemu_balloon(ram_addr_t target)
{
if (qemu_balloon_event) {
trace_balloon_event(qemu_balloon_event_opaque, target);
qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
return 1;
} else {
if (!balloon_event_fn) {
return 0;
}
trace_balloon_event(balloon_opaque, target);
balloon_event_fn(balloon_opaque, target);
return 1;
}
int qemu_balloon_status(MonitorCompletion cb, void *opaque)
static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
{
if (qemu_balloon_event) {
qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
return 1;
} else {
if (!balloon_stat_fn) {
return 0;
}
balloon_stat_fn(balloon_opaque, cb, opaque);
return 1;
}
static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
{
Monitor *mon = opaque;
if (strcmp(key, "actual"))
if (strcmp(key, "actual")) {
monitor_printf(mon, ",%s=%" PRId64, key,
qint_get_int(qobject_to_qint(obj)));
}
}
void monitor_print_balloon(Monitor *mon, const QObject *data)
@ -75,9 +86,9 @@ void monitor_print_balloon(Monitor *mon, const QObject *data)
QDict *qdict;
qdict = qobject_to_qdict(data);
if (!qdict_haskey(qdict, "actual"))
if (!qdict_haskey(qdict, "actual")) {
return;
}
monitor_printf(mon, "balloon: actual=%" PRId64,
qdict_get_int(qdict, "actual") >> 20);
qdict_iter(qdict, print_balloon_stat, mon);
@ -129,6 +140,7 @@ int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
int do_balloon(Monitor *mon, const QDict *params,
MonitorCompletion cb, void *opaque)
{
int64_t target;
int ret;
if (kvm_enabled() && !kvm_has_sync_mmu()) {
@ -136,7 +148,12 @@ int do_balloon(Monitor *mon, const QDict *params,
return -1;
}
ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
target = qdict_get_int(params, "value");
if (target <= 0) {
qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size");
return -1;
}
ret = qemu_balloon(target);
if (ret == 0) {
qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
return -1;

View File

@ -16,14 +16,12 @@
#include "monitor.h"
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
MonitorCompletion cb, void *cb_data);
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
void *cb_data);
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
int qemu_balloon_status(MonitorCompletion cb, void *opaque);
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque);
void monitor_print_balloon(Monitor *mon, const QObject *data);
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);

310
block.c
View File

@ -28,6 +28,7 @@
#include "block_int.h"
#include "module.h"
#include "qemu-objects.h"
#include "qemu-coroutine.h"
#ifdef CONFIG_BSD
#include <sys/types.h>
@ -57,6 +58,19 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs);
static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
QTAILQ_HEAD_INITIALIZER(bdrv_states);
@ -169,14 +183,25 @@ void path_combine(char *dest, int dest_size,
void bdrv_register(BlockDriver *bdrv)
{
if (!bdrv->bdrv_aio_readv) {
/* add AIO emulation layer */
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
} else if (!bdrv->bdrv_read) {
/* add synchronous IO emulation layer */
if (bdrv->bdrv_co_readv) {
/* Emulate AIO by coroutines, and sync by AIO */
bdrv->bdrv_aio_readv = bdrv_co_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_co_aio_writev_em;
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
} else {
bdrv->bdrv_co_readv = bdrv_co_readv_em;
bdrv->bdrv_co_writev = bdrv_co_writev_em;
if (!bdrv->bdrv_aio_readv) {
/* add AIO emulation layer */
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
} else if (!bdrv->bdrv_read) {
/* add synchronous IO emulation layer */
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
}
}
if (!bdrv->bdrv_aio_flush)
@ -730,6 +755,8 @@ void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
{
assert(bs->peer == qdev);
bs->peer = NULL;
bs->change_cb = NULL;
bs->change_opaque = NULL;
}
DeviceState *bdrv_get_attached(BlockDriverState *bs)
@ -920,6 +947,17 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
nb_sectors * BDRV_SECTOR_SIZE);
}
static inline bool bdrv_has_async_rw(BlockDriver *drv)
{
return drv->bdrv_co_readv != bdrv_co_readv_em
|| drv->bdrv_aio_readv != bdrv_aio_readv_em;
}
static inline bool bdrv_has_async_flush(BlockDriver *drv)
{
return drv->bdrv_aio_flush != bdrv_aio_flush_em;
}
/* return < 0 if error. See bdrv_write() for the return codes */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
@ -928,6 +966,18 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
if (!drv)
return -ENOMEDIUM;
if (bdrv_has_async_rw(drv) && qemu_in_coroutine()) {
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_co_readv(bs, sector_num, nb_sectors, &qiov);
}
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
@ -972,8 +1022,21 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BlockDriver *drv = bs->drv;
if (!bs->drv)
return -ENOMEDIUM;
if (bdrv_has_async_rw(drv) && qemu_in_coroutine()) {
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_co_writev(bs, sector_num, nb_sectors, &qiov);
}
if (bs->read_only)
return -EACCES;
if (bdrv_check_request(bs, sector_num, nb_sectors))
@ -1108,17 +1171,49 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
return 0;
}
/*
* Writes to the file and ensures that no writes are reordered across this
* request (acts as a barrier)
*
* Returns 0 on success, -errno in error cases.
*/
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
buf, BDRV_SECTOR_SIZE * nb_sectors);
BlockDriver *drv = bs->drv;
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
if (!drv) {
return -ENOMEDIUM;
}
if (bdrv_check_request(bs, sector_num, nb_sectors)) {
return -EIO;
}
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
}
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
BlockDriver *drv = bs->drv;
trace_bdrv_co_writev(bs, sector_num, nb_sectors);
if (!bs->drv) {
return -ENOMEDIUM;
}
if (bs->read_only) {
return -EACCES;
}
if (bdrv_check_request(bs, sector_num, nb_sectors)) {
return -EIO;
}
if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
}
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
bs->wr_highest_sector = sector_num + nb_sectors - 1;
}
return drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
}
/**
@ -1591,6 +1686,10 @@ int bdrv_flush(BlockDriverState *bs)
return 0;
}
if (bs->drv && bdrv_has_async_flush(bs->drv) && qemu_in_coroutine()) {
return bdrv_co_flush_em(bs);
}
if (bs->drv && bs->drv->bdrv_flush) {
return bs->drv->bdrv_flush(bs);
}
@ -2580,6 +2679,89 @@ static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
typedef struct BlockDriverAIOCBCoroutine {
BlockDriverAIOCB common;
BlockRequest req;
bool is_write;
QEMUBH* bh;
} BlockDriverAIOCBCoroutine;
static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
{
qemu_aio_flush();
}
static AIOPool bdrv_em_co_aio_pool = {
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
.cancel = bdrv_aio_co_cancel_em,
};
static void bdrv_co_rw_bh(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
acb->common.cb(acb->common.opaque, acb->req.error);
qemu_bh_delete(acb->bh);
qemu_aio_release(acb);
}
static void coroutine_fn bdrv_co_rw(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
BlockDriverState *bs = acb->common.bs;
if (!acb->is_write) {
acb->req.error = bs->drv->bdrv_co_readv(bs, acb->req.sector,
acb->req.nb_sectors, acb->req.qiov);
} else {
acb->req.error = bs->drv->bdrv_co_writev(bs, acb->req.sector,
acb->req.nb_sectors, acb->req.qiov);
}
acb->bh = qemu_bh_new(bdrv_co_rw_bh, acb);
qemu_bh_schedule(acb->bh);
}
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque,
bool is_write)
{
Coroutine *co;
BlockDriverAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
acb->req.sector = sector_num;
acb->req.nb_sectors = nb_sectors;
acb->req.qiov = qiov;
acb->is_write = is_write;
co = qemu_coroutine_create(bdrv_co_rw);
qemu_coroutine_enter(co, acb);
return &acb->common;
}
static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque,
false);
}
static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque,
true);
}
static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
@ -2636,8 +2818,6 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
struct iovec iov;
QEMUIOVector qiov;
async_context_push();
async_ret = NOT_DONE;
iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
@ -2655,7 +2835,6 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
fail:
async_context_pop();
return async_ret;
}
@ -2667,8 +2846,6 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
struct iovec iov;
QEMUIOVector qiov;
async_context_push();
async_ret = NOT_DONE;
iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
@ -2684,7 +2861,6 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
}
fail:
async_context_pop();
return async_ret;
}
@ -2725,6 +2901,77 @@ void qemu_aio_release(void *p)
pool->free_aiocb = acb;
}
/**************************************************************/
/* Coroutine block device emulation */
typedef struct CoroutineIOCompletion {
Coroutine *coroutine;
int ret;
} CoroutineIOCompletion;
static void bdrv_co_io_em_complete(void *opaque, int ret)
{
CoroutineIOCompletion *co = opaque;
co->ret = ret;
qemu_coroutine_enter(co->coroutine, NULL);
}
static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *iov,
bool is_write)
{
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
BlockDriverAIOCB *acb;
if (is_write) {
acb = bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
} else {
acb = bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
}
trace_bdrv_co_io(is_write, acb);
if (!acb) {
return -EIO;
}
qemu_coroutine_yield();
return co.ret;
}
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{
return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, false);
}
static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{
return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
}
static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs)
{
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
BlockDriverAIOCB *acb;
acb = bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
if (!acb) {
return -EIO;
}
qemu_coroutine_yield();
return co.ret;
}
/**************************************************************/
/* removable device support */
@ -2768,25 +3015,16 @@ int bdrv_media_changed(BlockDriverState *bs)
int bdrv_eject(BlockDriverState *bs, int eject_flag)
{
BlockDriver *drv = bs->drv;
int ret;
if (bs->locked) {
if (eject_flag && bs->locked) {
return -EBUSY;
}
if (!drv || !drv->bdrv_eject) {
ret = -ENOTSUP;
} else {
ret = drv->bdrv_eject(bs, eject_flag);
if (drv && drv->bdrv_eject) {
drv->bdrv_eject(bs, eject_flag);
}
if (ret == -ENOTSUP) {
ret = 0;
}
if (ret >= 0) {
bs->tray_open = eject_flag;
}
return ret;
bs->tray_open = eject_flag;
return 0;
}
int bdrv_is_locked(BlockDriverState *bs)

View File

@ -4,6 +4,7 @@
#include "qemu-aio.h"
#include "qemu-common.h"
#include "qemu-option.h"
#include "qemu-coroutine.h"
#include "qobject.h"
/* block.c */
@ -85,8 +86,10 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);

View File

@ -73,6 +73,7 @@ typedef struct BDRVQcowState {
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
CoMutex lock;
} BDRVQcowState;
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
@ -517,11 +518,11 @@ static AIOPool qcow_aio_pool = {
static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int is_write)
int is_write)
{
QCowAIOCB *acb;
acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&qcow_aio_pool, bs, NULL, NULL);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
@ -542,48 +543,15 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
return acb;
}
static void qcow_aio_read_cb(void *opaque, int ret);
static void qcow_aio_write_cb(void *opaque, int ret);
static void qcow_aio_rw_bh(void *opaque)
{
QCowAIOCB *acb = opaque;
qemu_bh_delete(acb->bh);
acb->bh = NULL;
if (acb->is_write) {
qcow_aio_write_cb(opaque, 0);
} else {
qcow_aio_read_cb(opaque, 0);
}
}
static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
{
if (acb->bh) {
return -EIO;
}
acb->bh = qemu_bh_new(cb, acb);
if (!acb->bh) {
return -EIO;
}
qemu_bh_schedule(acb->bh);
return 0;
}
static void qcow_aio_read_cb(void *opaque, int ret)
static int qcow_aio_read_cb(void *opaque)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
int ret;
acb->hd_aiocb = NULL;
if (ret < 0)
goto done;
redo:
/* post process the read buffer */
@ -605,8 +573,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
if (acb->nb_sectors == 0) {
/* request completed */
ret = 0;
goto done;
return 0;
}
/* prepare next AIO request */
@ -623,11 +590,12 @@ static void qcow_aio_read_cb(void *opaque, int ret)
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_readv(bs->backing_hd, acb->sector_num,
acb->n, &acb->hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return -EIO;
}
} else {
/* Note: in this case, no need to wait */
@ -637,64 +605,56 @@ static void qcow_aio_read_cb(void *opaque, int ret)
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* add AIO support for compressed blocks ? */
if (decompress_cluster(bs, acb->cluster_offset) < 0) {
ret = -EIO;
goto done;
return -EIO;
}
memcpy(acb->buf,
s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
goto redo;
} else {
if ((acb->cluster_offset & 511) != 0) {
ret = -EIO;
goto done;
return -EIO;
}
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(bs->file,
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_readv(bs->file,
(acb->cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
acb->n, &acb->hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return ret;
}
}
return;
return 1;
}
static int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
int ret;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, 0);
qemu_co_mutex_lock(&s->lock);
do {
ret = qcow_aio_read_cb(acb);
} while (ret > 0);
qemu_co_mutex_unlock(&s->lock);
done:
if (acb->qiov->niov > 1) {
qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
qemu_vfree(acb->orig_buf);
}
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
return ret;
}
static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
QCowAIOCB *acb;
int ret;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
if (ret < 0) {
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
return NULL;
}
return &acb->common;
}
static void qcow_aio_write_cb(void *opaque, int ret)
static int qcow_aio_write_cb(void *opaque)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
@ -702,20 +662,17 @@ static void qcow_aio_write_cb(void *opaque, int ret)
int index_in_cluster;
uint64_t cluster_offset;
const uint8_t *src_buf;
int ret;
acb->hd_aiocb = NULL;
if (ret < 0)
goto done;
acb->nb_sectors -= acb->n;
acb->sector_num += acb->n;
acb->buf += acb->n * 512;
if (acb->nb_sectors == 0) {
/* request completed */
ret = 0;
goto done;
return 0;
}
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@ -726,16 +683,11 @@ static void qcow_aio_write_cb(void *opaque, int ret)
index_in_cluster,
index_in_cluster + acb->n);
if (!cluster_offset || (cluster_offset & 511) != 0) {
ret = -EIO;
goto done;
return -EIO;
}
if (s->crypt_method) {
if (!acb->cluster_data) {
acb->cluster_data = qemu_mallocz(s->cluster_size);
if (!acb->cluster_data) {
ret = -ENOMEM;
goto done;
}
}
encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
acb->n, 1, &s->aes_encrypt_key);
@ -747,26 +699,19 @@ static void qcow_aio_write_cb(void *opaque, int ret)
acb->hd_iov.iov_base = (void *)src_buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_writev(bs->file,
(cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->n,
qcow_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_writev(bs->file,
(cluster_offset >> 9) + index_in_cluster,
acb->n, &acb->hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return ret;
}
return;
done:
if (acb->qiov->niov > 1)
qemu_vfree(acb->orig_buf);
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
return 1;
}
static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
static int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
@ -774,21 +719,20 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
s->cluster_cache_offset = -1; /* disable compressed cache */
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
if (!acb)
return NULL;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, 1);
qemu_co_mutex_lock(&s->lock);
do {
ret = qcow_aio_write_cb(acb);
} while (ret > 0);
qemu_co_mutex_unlock(&s->lock);
ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
if (ret < 0) {
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
return NULL;
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
qemu_aio_release(acb);
return &acb->common;
return ret;
}
static void qcow_close(BlockDriverState *bs)
@ -1020,8 +964,8 @@ static BlockDriver bdrv_qcow = {
.bdrv_is_allocated = qcow_is_allocated,
.bdrv_set_key = qcow_set_key,
.bdrv_make_empty = qcow_make_empty,
.bdrv_aio_readv = qcow_aio_readv,
.bdrv_aio_writev = qcow_aio_writev,
.bdrv_co_readv = qcow_co_readv,
.bdrv_co_writev = qcow_co_writev,
.bdrv_aio_flush = qcow_aio_flush,
.bdrv_write_compressed = qcow_write_compressed,
.bdrv_get_info = qcow_get_info,

View File

@ -697,12 +697,12 @@ err:
* m->depends_on is set to NULL and the other fields in m are meaningless.
*
* If the cluster is newly allocated, m->nb_clusters is set to the number of
* contiguous clusters that have been allocated. This may be 0 if the request
* conflict with another write request in flight; in this case, m->depends_on
* is set and the remaining fields of m are meaningless.
* contiguous clusters that have been allocated. In this case, the other
* fields of m are valid and contain information about the first allocated
* cluster.
*
* If m->nb_clusters is non-zero, the other fields of m are valid and contain
* information about the first allocated cluster.
* If the request conflicts with another write request in flight, the coroutine
* is queued and will be reentered when the dependency has completed.
*
* Return 0 on success and -errno in error cases
*/
@ -721,6 +721,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
return ret;
}
again:
nb_clusters = size_to_clusters(s, n_end << 9);
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
@ -792,12 +793,12 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
}
if (nb_clusters == 0) {
/* Set dependency and wait for a callback */
m->depends_on = old_alloc;
m->nb_clusters = 0;
*num = 0;
goto out_wait_dependency;
/* Wait for the dependency to complete. We need to recheck
* the free/allocated clusters when we continue. */
qemu_co_mutex_unlock(&s->lock);
qemu_co_queue_wait(&old_alloc->dependent_requests);
qemu_co_mutex_lock(&s->lock);
goto again;
}
}
}
@ -834,9 +835,6 @@ out:
return 0;
out_wait_dependency:
return qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
fail:
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
fail_put:

View File

@ -276,6 +276,9 @@ static int qcow2_open(BlockDriverState *bs, int flags)
goto fail;
}
/* Initialise locks */
qemu_co_mutex_init(&s->lock);
#ifdef DEBUG_ALLOC
qcow2_check_refcounts(bs);
#endif
@ -379,7 +382,6 @@ typedef struct QCowAIOCB {
uint64_t cluster_offset;
uint8_t *cluster_data;
bool is_write;
BlockDriverAIOCB *hd_aiocb;
QEMUIOVector hd_qiov;
QEMUBH *bh;
QCowL2Meta l2meta;
@ -389,8 +391,6 @@ typedef struct QCowAIOCB {
static void qcow2_aio_cancel(BlockDriverAIOCB *blockacb)
{
QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
if (acb->hd_aiocb)
bdrv_aio_cancel(acb->hd_aiocb);
qemu_aio_release(acb);
}
@ -399,46 +399,16 @@ static AIOPool qcow2_aio_pool = {
.cancel = qcow2_aio_cancel,
};
static void qcow2_aio_read_cb(void *opaque, int ret);
static void qcow2_aio_write_cb(void *opaque, int ret);
static void qcow2_aio_rw_bh(void *opaque)
/*
* Returns 0 when the request is completed successfully, 1 when there is still
* a part left to do and -errno in error cases.
*/
static int qcow2_aio_read_cb(QCowAIOCB *acb)
{
QCowAIOCB *acb = opaque;
qemu_bh_delete(acb->bh);
acb->bh = NULL;
if (acb->is_write) {
qcow2_aio_write_cb(opaque, 0);
} else {
qcow2_aio_read_cb(opaque, 0);
}
}
static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
{
if (acb->bh)
return -EIO;
acb->bh = qemu_bh_new(cb, acb);
if (!acb->bh)
return -EIO;
qemu_bh_schedule(acb->bh);
return 0;
}
static void qcow2_aio_read_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster, n1;
acb->hd_aiocb = NULL;
if (ret < 0)
goto done;
int ret;
/* post process the read buffer */
if (!acb->cluster_offset) {
@ -463,8 +433,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
if (acb->remaining_sectors == 0) {
/* request completed */
ret = 0;
goto done;
return 0;
}
/* prepare next AIO request */
@ -477,7 +446,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
&acb->cur_nr_sectors, &acb->cluster_offset);
if (ret < 0) {
goto done;
return ret;
}
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@ -494,42 +463,35 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
acb->sector_num, acb->cur_nr_sectors);
if (n1 > 0) {
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
&acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_readv(bs->backing_hd, acb->sector_num,
n1, &acb->hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return ret;
}
} else {
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
}
return 1;
} else {
/* Note: in this case, no need to wait */
qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
return 1;
}
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* add AIO support for compressed blocks ? */
ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
if (ret < 0) {
goto done;
return ret;
}
qemu_iovec_from_buffer(&acb->hd_qiov,
s->cluster_cache + index_in_cluster * 512,
512 * acb->cur_nr_sectors);
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
return 1;
} else {
if ((acb->cluster_offset & 511) != 0) {
ret = -EIO;
goto done;
return -EIO;
}
if (s->crypt_method) {
@ -550,21 +512,17 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
}
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
acb->hd_aiocb = bdrv_aio_readv(bs->file,
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_readv(bs->file,
(acb->cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->cur_nr_sectors,
qcow2_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
acb->cur_nr_sectors, &acb->hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return ret;
}
}
return;
done:
acb->common.cb(acb->common.opaque, ret);
qemu_iovec_destroy(&acb->hd_qiov);
qemu_aio_release(acb);
return 1;
}
static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
@ -577,7 +535,6 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
acb = qemu_aio_get(&qcow2_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
acb->is_write = is_write;
@ -589,79 +546,73 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
acb->cur_nr_sectors = 0;
acb->cluster_offset = 0;
acb->l2meta.nb_clusters = 0;
QLIST_INIT(&acb->l2meta.dependent_requests);
qemu_co_queue_init(&acb->l2meta.dependent_requests);
return acb;
}
static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
int ret;
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, NULL, NULL, 0);
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0) {
qemu_iovec_destroy(&acb->hd_qiov);
qemu_aio_release(acb);
return NULL;
}
qemu_co_mutex_lock(&s->lock);
do {
ret = qcow2_aio_read_cb(acb);
} while (ret > 0);
qemu_co_mutex_unlock(&s->lock);
return &acb->common;
qemu_iovec_destroy(&acb->hd_qiov);
qemu_aio_release(acb);
return ret;
}
static void run_dependent_requests(QCowL2Meta *m)
static void run_dependent_requests(BDRVQcowState *s, QCowL2Meta *m)
{
QCowAIOCB *req;
QCowAIOCB *next;
/* Take the request off the list of running requests */
if (m->nb_clusters != 0) {
QLIST_REMOVE(m, next_in_flight);
}
/* Restart all dependent requests */
QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) {
qcow2_aio_write_cb(req, 0);
if (!qemu_co_queue_empty(&m->dependent_requests)) {
qemu_co_mutex_unlock(&s->lock);
while(qemu_co_queue_next(&m->dependent_requests));
qemu_co_mutex_lock(&s->lock);
}
/* Empty the list for the next part of the request */
QLIST_INIT(&m->dependent_requests);
}
static void qcow2_aio_write_cb(void *opaque, int ret)
/*
* Returns 0 when the request is completed successfully, 1 when there is still
* a part left to do and -errno in error cases.
*/
static int qcow2_aio_write_cb(QCowAIOCB *acb)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
int n_end;
int ret;
acb->hd_aiocb = NULL;
ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
if (ret >= 0) {
ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
run_dependent_requests(s, &acb->l2meta);
if (ret < 0) {
return ret;
}
run_dependent_requests(&acb->l2meta);
if (ret < 0)
goto done;
acb->remaining_sectors -= acb->cur_nr_sectors;
acb->sector_num += acb->cur_nr_sectors;
acb->bytes_done += acb->cur_nr_sectors * 512;
if (acb->remaining_sectors == 0) {
/* request completed */
ret = 0;
goto done;
return 0;
}
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@ -673,18 +624,10 @@ static void qcow2_aio_write_cb(void *opaque, int ret)
ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
index_in_cluster, n_end, &acb->cur_nr_sectors, &acb->l2meta);
if (ret < 0) {
goto done;
return ret;
}
acb->cluster_offset = acb->l2meta.cluster_offset;
/* Need to wait for another request? If so, we are done for now. */
if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
acb, next_depend);
return;
}
assert((acb->cluster_offset & 511) == 0);
qemu_iovec_reset(&acb->hd_qiov);
@ -709,51 +652,40 @@ static void qcow2_aio_write_cb(void *opaque, int ret)
}
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
acb->hd_aiocb = bdrv_aio_writev(bs->file,
(acb->cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->cur_nr_sectors,
qcow2_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto fail;
qemu_co_mutex_unlock(&s->lock);
ret = bdrv_co_writev(bs->file,
(acb->cluster_offset >> 9) + index_in_cluster,
acb->cur_nr_sectors, &acb->hd_qiov);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
return ret;
}
return;
fail:
if (acb->l2meta.nb_clusters != 0) {
QLIST_REMOVE(&acb->l2meta, next_in_flight);
}
done:
acb->common.cb(acb->common.opaque, ret);
qemu_iovec_destroy(&acb->hd_qiov);
qemu_aio_release(acb);
return 1;
}
static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static int qcow2_co_writev(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors,
QEMUIOVector *qiov)
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
int ret;
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, NULL, NULL, 1);
s->cluster_cache_offset = -1; /* disable compressed cache */
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
if (!acb)
return NULL;
qemu_co_mutex_lock(&s->lock);
do {
ret = qcow2_aio_write_cb(acb);
} while (ret > 0);
qemu_co_mutex_unlock(&s->lock);
ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0) {
qemu_iovec_destroy(&acb->hd_qiov);
qemu_aio_release(acb);
return NULL;
}
qemu_iovec_destroy(&acb->hd_qiov);
qemu_aio_release(acb);
return &acb->common;
return ret;
}
static void qcow2_close(BlockDriverState *bs)
@ -881,7 +813,7 @@ static int preallocate(BlockDriverState *bs)
nb_sectors = bdrv_getlength(bs) >> 9;
offset = 0;
QLIST_INIT(&meta.dependent_requests);
qemu_co_queue_init(&meta.dependent_requests);
meta.cluster_offset = 0;
while (nb_sectors) {
@ -899,7 +831,7 @@ static int preallocate(BlockDriverState *bs)
/* There are no dependent requests, but we need to remove our request
* from the list of in-flight requests */
run_dependent_requests(&meta);
run_dependent_requests(bs->opaque, &meta);
/* TODO Preallocate data if requested */
@ -1387,8 +1319,8 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_set_key = qcow2_set_key,
.bdrv_make_empty = qcow2_make_empty,
.bdrv_aio_readv = qcow2_aio_readv,
.bdrv_aio_writev = qcow2_aio_writev,
.bdrv_co_readv = qcow2_co_readv,
.bdrv_co_writev = qcow2_co_writev,
.bdrv_aio_flush = qcow2_aio_flush,
.bdrv_discard = qcow2_discard,

View File

@ -26,6 +26,7 @@
#define BLOCK_QCOW2_H
#include "aes.h"
#include "qemu-coroutine.h"
//#define DEBUG_ALLOC
//#define DEBUG_ALLOC2
@ -114,6 +115,8 @@ typedef struct BDRVQcowState {
int64_t free_cluster_index;
int64_t free_byte_offset;
CoMutex lock;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
@ -146,7 +149,7 @@ typedef struct QCowL2Meta
int nb_available;
int nb_clusters;
struct QCowL2Meta *depends_on;
QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
CoQueue dependent_requests;
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;

View File

@ -179,16 +179,12 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
{
int ret = -EINPROGRESS;
async_context_push();
qed_read_table(s, s->header.l1_table_offset,
s->l1_table, qed_sync_cb, &ret);
while (ret == -EINPROGRESS) {
qemu_aio_wait();
}
async_context_pop();
return ret;
}
@ -205,15 +201,11 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
{
int ret = -EINPROGRESS;
async_context_push();
qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
while (ret == -EINPROGRESS) {
qemu_aio_wait();
}
async_context_pop();
return ret;
}
@ -282,14 +274,11 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
{
int ret = -EINPROGRESS;
async_context_push();
qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
while (ret == -EINPROGRESS) {
qemu_aio_wait();
}
async_context_pop();
return ret;
}
@ -307,13 +296,10 @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
{
int ret = -EINPROGRESS;
async_context_push();
qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
while (ret == -EINPROGRESS) {
qemu_aio_wait();
}
async_context_pop();
return ret;
}

View File

@ -680,16 +680,12 @@ static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
};
QEDRequest request = { .l2_table = NULL };
async_context_push();
qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb);
while (cb.is_allocated == -1) {
qemu_aio_wait();
}
async_context_pop();
qed_unref_l2_cache_entry(request.l2_table);
return cb.is_allocated;

View File

@ -230,13 +230,15 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
}
}
/* We're falling back to POSIX AIO in some cases so init always */
if (paio_init() < 0) {
goto out_free_buf;
}
#ifdef CONFIG_LINUX_AIO
if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
/* We're falling back to POSIX AIO in some cases */
paio_init();
s->aio_ctx = laio_init();
if (!s->aio_ctx) {
goto out_free_buf;
@ -245,9 +247,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
} else
#endif
{
if (paio_init() < 0) {
goto out_free_buf;
}
#ifdef CONFIG_LINUX_AIO
s->use_aio = 0;
#endif
@ -587,7 +586,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
/*
* If O_DIRECT is used the buffer needs to be aligned on a sector
* boundary. Check if this is the case or telll the low-level
* boundary. Check if this is the case or tell the low-level
* driver that it needs to copy the buffer.
*/
if (s->aligned_buf) {
@ -1254,7 +1253,7 @@ static int floppy_media_changed(BlockDriverState *bs)
return ret;
}
static int floppy_eject(BlockDriverState *bs, int eject_flag)
static void floppy_eject(BlockDriverState *bs, int eject_flag)
{
BDRVRawState *s = bs->opaque;
int fd;
@ -1269,8 +1268,6 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag)
perror("FDEJECT");
close(fd);
}
return 0;
}
static BlockDriver bdrv_host_floppy = {
@ -1348,7 +1345,7 @@ static int cdrom_is_inserted(BlockDriverState *bs)
return 0;
}
static int cdrom_eject(BlockDriverState *bs, int eject_flag)
static void cdrom_eject(BlockDriverState *bs, int eject_flag)
{
BDRVRawState *s = bs->opaque;
@ -1359,11 +1356,9 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
perror("CDROMEJECT");
}
return 0;
}
static int cdrom_set_locked(BlockDriverState *bs, int locked)
static void cdrom_set_locked(BlockDriverState *bs, int locked)
{
BDRVRawState *s = bs->opaque;
@ -1374,8 +1369,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
*/
/* perror("CDROM_LOCKDOOR"); */
}
return 0;
}
static BlockDriver bdrv_host_cdrom = {
@ -1464,12 +1457,12 @@ static int cdrom_is_inserted(BlockDriverState *bs)
return raw_getlength(bs) > 0;
}
static int cdrom_eject(BlockDriverState *bs, int eject_flag)
static void cdrom_eject(BlockDriverState *bs, int eject_flag)
{
BDRVRawState *s = bs->opaque;
if (s->fd < 0)
return -ENOTSUP;
return;
(void) ioctl(s->fd, CDIOCALLOW);
@ -1481,17 +1474,15 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
perror("CDIOCCLOSE");
}
if (cdrom_reopen(bs) < 0)
return -ENOTSUP;
return 0;
cdrom_reopen(bs);
}
static int cdrom_set_locked(BlockDriverState *bs, int locked)
static void cdrom_set_locked(BlockDriverState *bs, int locked)
{
BDRVRawState *s = bs->opaque;
if (s->fd < 0)
return -ENOTSUP;
return;
if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
/*
* Note: an error can happen if the distribution automatically
@ -1499,8 +1490,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
*/
/* perror("CDROM_LOCKDOOR"); */
}
return 0;
}
static BlockDriver bdrv_host_cdrom = {

View File

@ -393,41 +393,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
return 0;
}
#if 0
/***********************************************/
/* removable device additional commands */
static int raw_is_inserted(BlockDriverState *bs)
{
return 1;
}
static int raw_media_changed(BlockDriverState *bs)
{
return -ENOTSUP;
}
static int raw_eject(BlockDriverState *bs, int eject_flag)
{
DWORD ret_count;
if (s->type == FTYPE_FILE)
return -ENOTSUP;
if (eject_flag) {
DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
} else {
DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
NULL, 0, NULL, 0, &lpBytesReturned, NULL);
}
}
static int raw_set_locked(BlockDriverState *bs, int locked)
{
return -ENOTSUP;
}
#endif
static int hdev_has_zero_init(BlockDriverState *bs)
{
return 0;

View File

@ -75,15 +75,14 @@ static int raw_is_inserted(BlockDriverState *bs)
return bdrv_is_inserted(bs->file);
}
static int raw_eject(BlockDriverState *bs, int eject_flag)
static void raw_eject(BlockDriverState *bs, int eject_flag)
{
return bdrv_eject(bs->file, eject_flag);
bdrv_eject(bs->file, eject_flag);
}
static int raw_set_locked(BlockDriverState *bs, int locked)
static void raw_set_locked(BlockDriverState *bs, int locked)
{
bdrv_set_locked(bs->file, locked);
return 0;
}
static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)

View File

@ -496,7 +496,7 @@ static ssize_t recvmsg(int s, struct msghdr *msg, int flags)
}
buf = qemu_malloc(size);
ret = recv(s, buf, size, flags);
ret = qemu_recv(s, buf, size, flags);
if (ret < 0) {
goto out;
}

View File

@ -156,6 +156,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
struct vhd_dyndisk_header* dyndisk_header;
uint8_t buf[HEADER_SIZE];
uint32_t checksum;
int err = -1;
if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
goto fail;
@ -176,6 +177,11 @@ static int vpc_open(BlockDriverState *bs, int flags)
bs->total_sectors = (int64_t)
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
if (bs->total_sectors >= 65535 * 16 * 255) {
err = -EFBIG;
goto fail;
}
if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
!= HEADER_SIZE)
goto fail;
@ -222,7 +228,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
return 0;
fail:
return -1;
return err;
}
/*

View File

@ -27,6 +27,7 @@
#include "block.h"
#include "qemu-option.h"
#include "qemu-queue.h"
#include "qemu-coroutine.h"
#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_COMPAT6 4
@ -77,6 +78,11 @@ struct BlockDriver {
int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors);
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
int num_reqs);
int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
@ -112,8 +118,8 @@ struct BlockDriver {
/* removable device specific */
int (*bdrv_is_inserted)(BlockDriverState *bs);
int (*bdrv_media_changed)(BlockDriverState *bs);
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
void (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
void (*bdrv_set_locked)(BlockDriverState *bs, int locked);
/* to control generic scsi devices */
int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);

View File

@ -646,16 +646,13 @@ out:
static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
{
if (!force) {
if (!bdrv_is_removable(bs)) {
qerror_report(QERR_DEVICE_NOT_REMOVABLE,
bdrv_get_device_name(bs));
return -1;
}
if (bdrv_is_locked(bs)) {
qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
return -1;
}
if (!bdrv_is_removable(bs)) {
qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
return -1;
}
if (!force && bdrv_is_locked(bs)) {
qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
return -1;
}
bdrv_close(bs);
return 0;

View File

@ -856,9 +856,6 @@ int main(int argc, char **argv)
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* init debug */
cpu_set_log_filename(log_file);
@ -877,6 +874,11 @@ int main(int argc, char **argv)
cpu_set_log(mask);
}
if (optind >= argc) {
usage();
}
filename = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));

474
bswap.h
View File

@ -11,6 +11,8 @@
#include <machine/bswap.h>
#else
#include "softfloat.h"
#ifdef CONFIG_BYTESWAP_H
#include <byteswap.h>
#else
@ -237,4 +239,476 @@ static inline uint32_t qemu_bswap_len(uint32_t value, int len)
return bswap32(value) >> (32 - 8 * len);
}
typedef union {
float32 f;
uint32_t l;
} CPU_FloatU;
typedef union {
float64 d;
#if defined(HOST_WORDS_BIGENDIAN)
struct {
uint32_t upper;
uint32_t lower;
} l;
#else
struct {
uint32_t lower;
uint32_t upper;
} l;
#endif
uint64_t ll;
} CPU_DoubleU;
typedef union {
floatx80 d;
struct {
uint64_t lower;
uint16_t upper;
} l;
} CPU_LDoubleU;
typedef union {
float128 q;
#if defined(HOST_WORDS_BIGENDIAN)
struct {
uint32_t upmost;
uint32_t upper;
uint32_t lower;
uint32_t lowest;
} l;
struct {
uint64_t upper;
uint64_t lower;
} ll;
#else
struct {
uint32_t lowest;
uint32_t lower;
uint32_t upper;
uint32_t upmost;
} l;
struct {
uint64_t lower;
uint64_t upper;
} ll;
#endif
} CPU_QuadU;
/* unaligned/endian-independent pointer access */
/*
* the generic syntax is:
*
* load: ld{type}{sign}{size}{endian}_p(ptr)
*
* store: st{type}{size}{endian}_p(ptr, val)
*
* Note there are small differences with the softmmu access API!
*
* type is:
* (empty): integer access
* f : float access
*
* sign is:
* (empty): for floats or 32 bit size
* u : unsigned
* s : signed
*
* size is:
* b: 8 bits
* w: 16 bits
* l: 32 bits
* q: 64 bits
*
* endian is:
* (empty): 8 bit access
* be : big endian
* le : little endian
*/
static inline int ldub_p(const void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb_p(const void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb_p(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
/* conservative code for little endian unaligned accesses */
static inline int lduw_le_p(const void *ptr)
{
#ifdef _ARCH_PPC
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
const uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw_le_p(const void *ptr)
{
#ifdef _ARCH_PPC
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
const uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl_le_p(const void *ptr)
{
#ifdef _ARCH_PPC
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
const uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq_le_p(const void *ptr)
{
const uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl_le_p(p);
v2 = ldl_le_p(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw_le_p(void *ptr, int v)
{
#ifdef _ARCH_PPC
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
static inline void stl_le_p(void *ptr, int v)
{
#ifdef _ARCH_PPC
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq_le_p(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl_le_p(p, (uint32_t)v);
stl_le_p(p + 4, v >> 32);
}
/* float access */
static inline float32 ldfl_le_p(const void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_le_p(ptr);
return u.f;
}
static inline void stfl_le_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_le_p(ptr, u.i);
}
static inline float64 ldfq_le_p(const void *ptr)
{
CPU_DoubleU u;
u.l.lower = ldl_le_p(ptr);
u.l.upper = ldl_le_p(ptr + 4);
return u.d;
}
static inline void stfq_le_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_le_p(ptr, u.l.lower);
stl_le_p(ptr + 4, u.l.upper);
}
#else
static inline int lduw_le_p(const void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_le_p(const void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_le_p(const void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_le_p(const void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_le_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_le_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_le_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_le_p(const void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_le_p(const void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_le_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_le_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
static inline int lduw_be_p(const void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return val;
#else
const uint8_t *b = ptr;
return ((b[0] << 8) | b[1]);
#endif
}
static inline int ldsw_be_p(const void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return (int16_t)val;
#else
const uint8_t *b = ptr;
return (int16_t)((b[0] << 8) | b[1]);
#endif
}
static inline int ldl_be_p(const void *ptr)
{
#if defined(__i386__) || defined(__x86_64__)
int val;
asm volatile ("movl %1, %0\n"
"bswap %0\n"
: "=r" (val)
: "m" (*(uint32_t *)ptr));
return val;
#else
const uint8_t *b = ptr;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
#endif
}
static inline uint64_t ldq_be_p(const void *ptr)
{
uint32_t a,b;
a = ldl_be_p(ptr);
b = ldl_be_p((uint8_t *)ptr + 4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_be_p(void *ptr, int v)
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
"movw %w0, %1\n"
: "=q" (v)
: "m" (*(uint16_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 8;
d[1] = v;
#endif
}
static inline void stl_be_p(void *ptr, int v)
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
"movl %0, %1\n"
: "=r" (v)
: "m" (*(uint32_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 24;
d[1] = v >> 16;
d[2] = v >> 8;
d[3] = v;
#endif
}
static inline void stq_be_p(void *ptr, uint64_t v)
{
stl_be_p(ptr, v >> 32);
stl_be_p((uint8_t *)ptr + 4, v);
}
/* float access */
static inline float32 ldfl_be_p(const void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_be_p(ptr);
return u.f;
}
static inline void stfl_be_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_be_p(ptr, u.i);
}
static inline float64 ldfq_be_p(const void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_be_p(ptr);
u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
return u.d;
}
static inline void stfq_be_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_be_p(ptr, u.l.upper);
stl_be_p((uint8_t *)ptr + 4, u.l.lower);
}
#else
static inline int lduw_be_p(const void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_be_p(const void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_be_p(const void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_be_p(const void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_be_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_be_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_be_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_be_p(const void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_be_p(const void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_be_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_be_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
#endif /* BSWAP_H */

View File

@ -115,3 +115,14 @@ int qemu_signalfd(const sigset_t *mask)
return qemu_signalfd_compat(mask);
}
bool qemu_signalfd_available(void)
{
#ifdef CONFIG_SIGNALFD
errno = 0;
syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
return errno != ENOSYS;
#else
return false;
#endif
}

View File

@ -39,5 +39,6 @@ struct qemu_signalfd_siginfo {
};
int qemu_signalfd(const sigset_t *mask);
bool qemu_signalfd_available(void);
#endif

140
configure vendored
View File

@ -113,7 +113,6 @@ curl=""
curses=""
docs=""
fdt=""
kvm=""
nptl=""
sdl=""
vnc="yes"
@ -129,9 +128,10 @@ xen=""
xen_ctrl_version=""
linux_aio=""
attr=""
vhost_net=""
xfs=""
vhost_net="no"
kvm="no"
gprof="no"
debug_tcg="no"
debug_mon="no"
@ -146,6 +146,7 @@ datadir="\${prefix}/share/qemu"
docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
libdir="\${prefix}/lib"
includedir="\${prefix}/include"
sysconfdir="\${prefix}/etc"
confsuffix="/qemu"
slirp="yes"
@ -179,6 +180,8 @@ smartcard=""
smartcard_nss=""
usb_redir=""
opengl=""
zlib="yes"
guest_agent="yes"
# parse CC options first
for opt do
@ -233,7 +236,7 @@ QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
QEMU_CFLAGS="-D_FORTIFY_SOURCE=2 $QEMU_CFLAGS"
QEMU_INCLUDES="-I. -I\$(SRC_PATH)"
QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/fpu"
LDFLAGS="-g $LDFLAGS"
# make source path absolute
@ -475,6 +478,7 @@ fi
: ${make=${MAKE-make}}
: ${install=${INSTALL-install}}
: ${python=${PYTHON-python}}
if test "$mingw32" = "yes" ; then
EXESUF=".exe"
@ -516,6 +520,8 @@ for opt do
;;
--install=*) install="$optarg"
;;
--python=*) python="$optarg"
;;
--extra-cflags=*)
;;
--extra-ldflags=*)
@ -540,6 +546,8 @@ for opt do
;;
--libdir=*) libdir="$optarg"
;;
--includedir=*) includedir="$optarg"
;;
--datadir=*) datadir="$optarg"
;;
--docdir=*) docdir="$optarg"
@ -748,6 +756,12 @@ for opt do
;;
--enable-usb-redir) usb_redir="yes"
;;
--disable-zlib-test) zlib="no"
;;
--enable-guest-agent) guest_agent="yes"
;;
--disable-guest-agent) guest_agent="no"
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@ -837,7 +851,6 @@ if [ "$softmmu" = "yes" ] ; then
default_target_list="\
i386-softmmu \
x86_64-softmmu \
alpha-softmmu \
arm-softmmu \
cris-softmmu \
lm32-softmmu \
@ -924,6 +937,7 @@ echo " --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS"
echo " --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS"
echo " --make=MAKE use specified make [$make]"
echo " --install=INSTALL use specified install [$install]"
echo " --python=PYTHON use specified python [$python]"
echo " --static enable static build [$static]"
echo " --mandir=PATH install man pages in PATH"
echo " --datadir=PATH install firmware in PATH"
@ -1025,6 +1039,8 @@ echo " --disable-smartcard-nss disable smartcard nss support"
echo " --enable-smartcard-nss enable smartcard nss support"
echo " --disable-usb-redir disable usb network redirection support"
echo " --enable-usb-redir enable usb network redirection support"
echo " --disable-guest-agent disable building of the QEMU Guest Agent"
echo " --enable-guest-agent enable building of the QEMU Guest Agent"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@ -1084,6 +1100,15 @@ if test "$solaris" = "yes" ; then
fi
fi
if test "$guest_agent" != "no" ; then
if has $python; then
:
else
echo "Python not found. Use --python=/path/to/python"
exit 1
fi
fi
if test -z "$target_list" ; then
target_list="$default_target_list"
else
@ -1179,18 +1204,20 @@ fi
##########################################
# zlib check
cat > $TMPC << EOF
if test "$zlib" != "no" ; then
cat > $TMPC << EOF
#include <zlib.h>
int main(void) { zlibVersion(); return 0; }
EOF
if compile_prog "" "-lz" ; then
:
else
echo
echo "Error: zlib check failed"
echo "Make sure to have the zlib libs and headers installed."
echo
exit 1
if compile_prog "" "-lz" ; then
:
else
echo
echo "Error: zlib check failed"
echo "Make sure to have the zlib libs and headers installed."
echo
exit 1
fi
fi
##########################################
@ -1494,11 +1521,17 @@ int main(void) {
return 0;
}
EOF
if $pkg_config libpng --modversion >/dev/null 2>&1; then
vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null`
vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null`
else
vnc_png_cflags=""
vnc_png_libs="-lpng"
fi
if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
vnc_png=yes
libs_softmmu="$vnc_png_libs $libs_softmmu"
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
else
if test "$vnc_png" = "yes" ; then
feature_not_found "vnc-png"
@ -1811,14 +1844,16 @@ fi
##########################################
# glib support probe
if $pkg_config --modversion gthread-2.0 gio-2.0 > /dev/null 2>&1 ; then
glib_cflags=`$pkg_config --cflags gthread-2.0 gio-2.0 2>/dev/null`
glib_libs=`$pkg_config --libs gthread-2.0 gio-2.0 2>/dev/null`
libs_softmmu="$glib_libs $libs_softmmu"
libs_tools="$glib_libs $libs_tools"
else
echo "glib-2.0 required to compile QEMU"
exit 1
if test "$guest_agent" != "no" ; then
if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then
glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null`
glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null`
libs_softmmu="$glib_libs $libs_softmmu"
libs_tools="$glib_libs $libs_tools"
else
echo "glib-2.0 required to compile QEMU"
exit 1
fi
fi
##########################################
@ -2498,6 +2533,43 @@ if test "$trace_backend" = "dtrace"; then
fi
fi
##########################################
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
# use i686 as default anyway, but for those that don't, an explicit
# specification is necessary
if test "$vhost_net" = "yes" && test "$cpu" = "i386"; then
cat > $TMPC << EOF
int sfaa(unsigned *ptr)
{
return __sync_fetch_and_and(ptr, 0);
}
int main(int argc, char **argv)
{
int val = 42;
sfaa(&val);
return val;
}
EOF
if ! compile_prog "" "" ; then
CFLAGS+="-march=i486"
fi
fi
##########################################
# check if we have makecontext
ucontext_coroutine=no
if test "$darwin" != "yes"; then
cat > $TMPC << EOF
#include <ucontext.h>
int main(void) { makecontext(0, 0, 0); }
EOF
if compile_prog "" "" ; then
ucontext_coroutine=yes
fi
fi
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
@ -2555,7 +2627,9 @@ if test "$softmmu" = yes ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
tools="qemu-nbd\$(EXESUF) $tools"
if [ "$guest_agent" = "yes" ]; then
tools="qemu-ga\$(EXESUF) $tools"
fi
if [ "$check_utests" = "yes" ]; then
tools="check-qint check-qstring check-qdict check-qlist $tools"
tools="check-qfloat check-qjson $tools"
@ -2578,6 +2652,7 @@ echo "Install prefix $prefix"
echo "BIOS directory `eval echo $datadir`"
echo "binary directory `eval echo $bindir`"
echo "library directory `eval echo $libdir`"
echo "include directory `eval echo $includedir`"
echo "config directory `eval echo $sysconfdir`"
if test "$mingw32" = "no" ; then
echo "Manual directory `eval echo $mandir`"
@ -2591,6 +2666,7 @@ echo "QEMU_CFLAGS $QEMU_CFLAGS"
echo "LDFLAGS $LDFLAGS"
echo "make $make"
echo "install $install"
echo "python $python"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
@ -2655,8 +2731,9 @@ echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
echo "usb net redir $usb_redir"
echo "OpenGL support $opengl"
echo "build guest agent $guest_agent"
if test $sdl_too_old = "yes"; then
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
fi
@ -2672,6 +2749,7 @@ echo all: >> $config_host_mak
echo "prefix=$prefix" >> $config_host_mak
echo "bindir=$bindir" >> $config_host_mak
echo "libdir=$libdir" >> $config_host_mak
echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
echo "datadir=$datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
@ -2743,7 +2821,7 @@ fi
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=y" >> $config_host_mak
fi
if test $profiler = "yes" ; then
if test "$profiler" = "yes" ; then
echo "CONFIG_PROFILER=y" >> $config_host_mak
fi
if test "$slirp" = "yes" ; then
@ -2970,6 +3048,10 @@ if test "$rbd" = "yes" ; then
echo "CONFIG_RBD=y" >> $config_host_mak
fi
if test "$ucontext_coroutine" = "yes" ; then
echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
fi
# USB host support
case "$usb" in
linux)
@ -3003,6 +3085,7 @@ echo "INSTALL=$install" >> $config_host_mak
echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_host_mak
echo "INSTALL_DATA=$install -m0644 -p" >> $config_host_mak
echo "INSTALL_PROG=$install -m0755 -p" >> $config_host_mak
echo "PYTHON=$python" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
echo "CC_I386=$cc_i386" >> $config_host_mak
echo "HOST_CC=$host_cc" >> $config_host_mak
@ -3277,10 +3360,12 @@ case "$target_arch2" in
if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
target_phys_bits=64
echo "CONFIG_XEN=y" >> $config_target_mak
if test "$cpu" = "i386" -o "$cpu" = "x86_64"; then
echo "CONFIG_XEN_MAPCACHE=y" >> $config_target_mak
fi
else
echo "CONFIG_NO_XEN=y" >> $config_target_mak
fi
;;
*)
echo "CONFIG_NO_XEN=y" >> $config_target_mak
esac
case "$target_arch2" in
i386|x86_64|ppcemb|ppc|ppc64|s390x)
@ -3294,7 +3379,7 @@ case "$target_arch2" in
\( "$target_arch2" = "x86_64" -a "$cpu" = "i386" \) -o \
\( "$target_arch2" = "i386" -a "$cpu" = "x86_64" \) \) ; then
echo "CONFIG_KVM=y" >> $config_target_mak
if test $vhost_net = "yes" ; then
if test "$vhost_net" = "yes" ; then
echo "CONFIG_VHOST_NET=y" >> $config_target_mak
fi
fi
@ -3361,7 +3446,6 @@ else
includes="-I\$(SRC_PATH)/tcg/\$(ARCH) $includes"
fi
includes="-I\$(SRC_PATH)/tcg $includes"
includes="-I\$(SRC_PATH)/fpu $includes"
if test "$target_user_only" = "yes" ; then
libdis_config_mak=libdis-user/config.mak

View File

@ -1514,7 +1514,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
chr->init(chr);
}
CharDriverState *text_console_init(QemuOpts *opts)
int text_console_init(QemuOpts *opts, CharDriverState **_chr)
{
CharDriverState *chr;
TextConsole *s;
@ -1546,7 +1546,7 @@ CharDriverState *text_console_init(QemuOpts *opts)
if (!s) {
free(chr);
return NULL;
return -EBUSY;
}
s->chr = chr;
@ -1554,7 +1554,9 @@ CharDriverState *text_console_init(QemuOpts *opts)
s->g_height = height;
chr->opaque = s;
chr->chr_set_echo = text_console_set_echo;
return chr;
*_chr = chr;
return 0;
}
void text_consoles_set_display(DisplayState *ds)

View File

@ -354,7 +354,7 @@ void vga_hw_text_update(console_ch_t *chardata);
int is_graphic_console(void);
int is_fixedsize_console(void);
CharDriverState *text_console_init(QemuOpts *opts);
int text_console_init(QemuOpts *opts, CharDriverState **_chr);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
void console_color_init(DisplayState *ds);
@ -372,6 +372,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen);
void vnc_display_init(DisplayState *ds);
void vnc_display_close(DisplayState *ds);
int vnc_display_open(DisplayState *ds, const char *display);
void vnc_display_add_client(DisplayState *ds, int csock, int skipauth);
int vnc_display_disable_login(DisplayState *ds);
char *vnc_display_local_addr(DisplayState *ds);
#ifdef CONFIG_VNC

131
coroutine-gthread.c Normal file
View File

@ -0,0 +1,131 @@
/*
* GThread coroutine initialization code
*
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
* Copyright (C) 2011 Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include "qemu-common.h"
#include "qemu-coroutine-int.h"
typedef struct {
Coroutine base;
GThread *thread;
bool runnable;
CoroutineAction action;
} CoroutineGThread;
static GCond *coroutine_cond;
static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
static void __attribute__((constructor)) coroutine_init(void)
{
if (!g_thread_supported()) {
g_thread_init(NULL);
}
coroutine_cond = g_cond_new();
}
static void coroutine_wait_runnable_locked(CoroutineGThread *co)
{
while (!co->runnable) {
g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock));
}
}
static void coroutine_wait_runnable(CoroutineGThread *co)
{
g_static_mutex_lock(&coroutine_lock);
coroutine_wait_runnable_locked(co);
g_static_mutex_unlock(&coroutine_lock);
}
static gpointer coroutine_thread(gpointer opaque)
{
CoroutineGThread *co = opaque;
g_static_private_set(&coroutine_key, co, NULL);
coroutine_wait_runnable(co);
co->base.entry(co->base.entry_arg);
qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
return NULL;
}
Coroutine *qemu_coroutine_new(void)
{
CoroutineGThread *co;
co = qemu_mallocz(sizeof(*co));
co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
G_THREAD_PRIORITY_NORMAL, NULL);
if (!co->thread) {
qemu_free(co);
return NULL;
}
return &co->base;
}
void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_);
g_thread_join(co->thread);
qemu_free(co);
}
CoroutineAction qemu_coroutine_switch(Coroutine *from_,
Coroutine *to_,
CoroutineAction action)
{
CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_);
CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_);
g_static_mutex_lock(&coroutine_lock);
from->runnable = false;
from->action = action;
to->runnable = true;
to->action = action;
g_cond_broadcast(coroutine_cond);
if (action != COROUTINE_TERMINATE) {
coroutine_wait_runnable_locked(from);
}
g_static_mutex_unlock(&coroutine_lock);
return from->action;
}
Coroutine *qemu_coroutine_self(void)
{
CoroutineGThread *co = g_static_private_get(&coroutine_key);
if (!co) {
co = qemu_mallocz(sizeof(*co));
co->runnable = true;
g_static_private_set(&coroutine_key, co, (GDestroyNotify)qemu_free);
}
return &co->base;
}
bool qemu_in_coroutine(void)
{
CoroutineGThread *co = g_static_private_get(&coroutine_key);
return co && co->base.caller;
}

230
coroutine-ucontext.c Normal file
View File

@ -0,0 +1,230 @@
/*
* ucontext coroutine initialization code
*
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
* Copyright (C) 2011 Kevin Wolf <kwolf@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* XXX Is there a nicer way to disable glibc's stack check for longjmp? */
#ifdef _FORTIFY_SOURCE
#undef _FORTIFY_SOURCE
#endif
#include <stdlib.h>
#include <setjmp.h>
#include <stdint.h>
#include <pthread.h>
#include <ucontext.h>
#include "qemu-common.h"
#include "qemu-coroutine-int.h"
enum {
/* Maximum free pool size prevents holding too many freed coroutines */
POOL_MAX_SIZE = 64,
};
typedef struct {
Coroutine base;
void *stack;
jmp_buf env;
} CoroutineUContext;
/**
* Per-thread coroutine bookkeeping
*/
typedef struct {
/** Currently executing coroutine */
Coroutine *current;
/** Free list to speed up creation */
QLIST_HEAD(, Coroutine) pool;
unsigned int pool_size;
/** The default coroutine */
CoroutineUContext leader;
} CoroutineThreadState;
static pthread_key_t thread_state_key;
/*
* va_args to makecontext() must be type 'int', so passing
* the pointer we need may require several int args. This
* union is a quick hack to let us do that
*/
union cc_arg {
void *p;
int i[2];
};
static CoroutineThreadState *coroutine_get_thread_state(void)
{
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
if (!s) {
s = qemu_mallocz(sizeof(*s));
s->current = &s->leader.base;
QLIST_INIT(&s->pool);
pthread_setspecific(thread_state_key, s);
}
return s;
}
static void qemu_coroutine_thread_cleanup(void *opaque)
{
CoroutineThreadState *s = opaque;
Coroutine *co;
Coroutine *tmp;
QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) {
qemu_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
qemu_free(co);
}
qemu_free(s);
}
static void __attribute__((constructor)) coroutine_init(void)
{
int ret;
ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
if (ret != 0) {
fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
abort();
}
}
static void coroutine_trampoline(int i0, int i1)
{
union cc_arg arg;
CoroutineUContext *self;
Coroutine *co;
arg.i[0] = i0;
arg.i[1] = i1;
self = arg.p;
co = &self->base;
/* Initialize longjmp environment and switch back the caller */
if (!setjmp(self->env)) {
longjmp(*(jmp_buf *)co->entry_arg, 1);
}
while (true) {
co->entry(co->entry_arg);
qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
}
}
static Coroutine *coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineUContext *co;
ucontext_t old_uc, uc;
jmp_buf old_env;
union cc_arg arg;
/* The ucontext functions preserve signal masks which incurs a system call
* overhead. setjmp()/longjmp() does not preserve signal masks but only
* works on the current stack. Since we need a way to create and switch to
* a new stack, use the ucontext functions for that but setjmp()/longjmp()
* for everything else.
*/
if (getcontext(&uc) == -1) {
abort();
}
co = qemu_mallocz(sizeof(*co));
co->stack = qemu_malloc(stack_size);
co->base.entry_arg = &old_env; /* stash away our jmp_buf */
uc.uc_link = &old_uc;
uc.uc_stack.ss_sp = co->stack;
uc.uc_stack.ss_size = stack_size;
uc.uc_stack.ss_flags = 0;
arg.p = co;
makecontext(&uc, (void (*)(void))coroutine_trampoline,
2, arg.i[0], arg.i[1]);
/* swapcontext() in, longjmp() back out */
if (!setjmp(old_env)) {
swapcontext(&old_uc, &uc);
}
return &co->base;
}
Coroutine *qemu_coroutine_new(void)
{
CoroutineThreadState *s = coroutine_get_thread_state();
Coroutine *co;
co = QLIST_FIRST(&s->pool);
if (co) {
QLIST_REMOVE(co, pool_next);
s->pool_size--;
} else {
co = coroutine_new();
}
return co;
}
void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineThreadState *s = coroutine_get_thread_state();
CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
if (s->pool_size < POOL_MAX_SIZE) {
QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next);
co->base.caller = NULL;
s->pool_size++;
return;
}
qemu_free(co->stack);
qemu_free(co);
}
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
CoroutineAction action)
{
CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
CoroutineThreadState *s = coroutine_get_thread_state();
int ret;
s->current = to_;
ret = setjmp(from->env);
if (ret == 0) {
longjmp(to->env, action);
}
return ret;
}
Coroutine *qemu_coroutine_self(void)
{
CoroutineThreadState *s = coroutine_get_thread_state();
return s->current;
}
bool qemu_in_coroutine(void)
{
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
return s && s->current->caller;
}

92
coroutine-win32.c Normal file
View File

@ -0,0 +1,92 @@
/*
* Win32 coroutine initialization code
*
* Copyright (c) 2011 Kevin Wolf <kwolf@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "qemu-coroutine-int.h"
typedef struct
{
Coroutine base;
LPVOID fiber;
CoroutineAction action;
} CoroutineWin32;
static __thread CoroutineWin32 leader;
static __thread Coroutine *current;
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
CoroutineAction action)
{
CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
current = to_;
to->action = action;
SwitchToFiber(to->fiber);
return from->action;
}
static void CALLBACK coroutine_trampoline(void *co_)
{
Coroutine *co = co_;
while (true) {
co->entry(co->entry_arg);
qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
}
}
Coroutine *qemu_coroutine_new(void)
{
const size_t stack_size = 1 << 20;
CoroutineWin32 *co;
co = qemu_mallocz(sizeof(*co));
co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
return &co->base;
}
void qemu_coroutine_delete(Coroutine *co_)
{
CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
DeleteFiber(co->fiber);
qemu_free(co);
}
Coroutine *qemu_coroutine_self(void)
{
if (!current) {
current = &leader.base;
leader.fiber = ConvertThreadToFiber(NULL);
}
return current;
}
bool qemu_in_coroutine(void)
{
return current && current->caller;
}

446
cpu-all.h
View File

@ -35,8 +35,6 @@
* TARGET_WORDS_BIGENDIAN : same for target cpu
*/
#include "softfloat.h"
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
#endif
@ -114,64 +112,6 @@ static inline void tswap64s(uint64_t *s)
#define bswaptls(s) bswap64s(s)
#endif
typedef union {
float32 f;
uint32_t l;
} CPU_FloatU;
/* NOTE: arm FPA is horrible as double 32 bit words are stored in big
endian ! */
typedef union {
float64 d;
#if defined(HOST_WORDS_BIGENDIAN)
struct {
uint32_t upper;
uint32_t lower;
} l;
#else
struct {
uint32_t lower;
uint32_t upper;
} l;
#endif
uint64_t ll;
} CPU_DoubleU;
typedef union {
floatx80 d;
struct {
uint64_t lower;
uint16_t upper;
} l;
} CPU_LDoubleU;
typedef union {
float128 q;
#if defined(HOST_WORDS_BIGENDIAN)
struct {
uint32_t upmost;
uint32_t upper;
uint32_t lower;
uint32_t lowest;
} l;
struct {
uint64_t upper;
uint64_t lower;
} ll;
#else
struct {
uint32_t lowest;
uint32_t lower;
uint32_t upper;
uint32_t upmost;
} l;
struct {
uint64_t lower;
uint64_t upper;
} ll;
#endif
} CPU_QuadU;
/* CPU memory access without any memory or io remapping */
/*
@ -207,392 +147,8 @@ typedef union {
* user : user mode access using soft MMU
* kernel : kernel mode access using soft MMU
*/
static inline int ldub_p(const void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb_p(const void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb_p(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
/* conservative code for little endian unaligned accesses */
static inline int lduw_le_p(const void *ptr)
{
#ifdef _ARCH_PPC
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
const uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw_le_p(const void *ptr)
{
#ifdef _ARCH_PPC
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
const uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl_le_p(const void *ptr)
{
#ifdef _ARCH_PPC
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
const uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq_le_p(const void *ptr)
{
const uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl_le_p(p);
v2 = ldl_le_p(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw_le_p(void *ptr, int v)
{
#ifdef _ARCH_PPC
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
static inline void stl_le_p(void *ptr, int v)
{
#ifdef _ARCH_PPC
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq_le_p(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl_le_p(p, (uint32_t)v);
stl_le_p(p + 4, v >> 32);
}
/* float access */
static inline float32 ldfl_le_p(const void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_le_p(ptr);
return u.f;
}
static inline void stfl_le_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_le_p(ptr, u.i);
}
static inline float64 ldfq_le_p(const void *ptr)
{
CPU_DoubleU u;
u.l.lower = ldl_le_p(ptr);
u.l.upper = ldl_le_p(ptr + 4);
return u.d;
}
static inline void stfq_le_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_le_p(ptr, u.l.lower);
stl_le_p(ptr + 4, u.l.upper);
}
#else
static inline int lduw_le_p(const void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_le_p(const void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_le_p(const void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_le_p(const void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_le_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_le_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_le_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_le_p(const void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_le_p(const void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_le_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_le_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
static inline int lduw_be_p(const void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return val;
#else
const uint8_t *b = ptr;
return ((b[0] << 8) | b[1]);
#endif
}
static inline int ldsw_be_p(const void *ptr)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
: "m" (*(uint16_t *)ptr));
return (int16_t)val;
#else
const uint8_t *b = ptr;
return (int16_t)((b[0] << 8) | b[1]);
#endif
}
static inline int ldl_be_p(const void *ptr)
{
#if defined(__i386__) || defined(__x86_64__)
int val;
asm volatile ("movl %1, %0\n"
"bswap %0\n"
: "=r" (val)
: "m" (*(uint32_t *)ptr));
return val;
#else
const uint8_t *b = ptr;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
#endif
}
static inline uint64_t ldq_be_p(const void *ptr)
{
uint32_t a,b;
a = ldl_be_p(ptr);
b = ldl_be_p((uint8_t *)ptr + 4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_be_p(void *ptr, int v)
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
"movw %w0, %1\n"
: "=q" (v)
: "m" (*(uint16_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 8;
d[1] = v;
#endif
}
static inline void stl_be_p(void *ptr, int v)
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
"movl %0, %1\n"
: "=r" (v)
: "m" (*(uint32_t *)ptr), "0" (v));
#else
uint8_t *d = (uint8_t *) ptr;
d[0] = v >> 24;
d[1] = v >> 16;
d[2] = v >> 8;
d[3] = v;
#endif
}
static inline void stq_be_p(void *ptr, uint64_t v)
{
stl_be_p(ptr, v >> 32);
stl_be_p((uint8_t *)ptr + 4, v);
}
/* float access */
static inline float32 ldfl_be_p(const void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_be_p(ptr);
return u.f;
}
static inline void stfl_be_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_be_p(ptr, u.i);
}
static inline float64 ldfq_be_p(const void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_be_p(ptr);
u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
return u.d;
}
static inline void stfq_be_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_be_p(ptr, u.l.upper);
stl_be_p((uint8_t *)ptr + 4, u.l.lower);
}
#else
static inline int lduw_be_p(const void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_be_p(const void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_be_p(const void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_be_p(const void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_be_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_be_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_be_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_be_p(const void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_be_p(const void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_be_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_be_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
/* target CPU memory access functions */
/* target-endianness CPU memory access functions */
#if defined(TARGET_WORDS_BIGENDIAN)
#define lduw_p(p) lduw_be_p(p)
#define ldsw_p(p) ldsw_be_p(p)

View File

@ -3,10 +3,6 @@
/* CPU interfaces that are target indpendent. */
#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__ia64__)
#define WORDS_ALIGNED
#endif
#ifdef TARGET_PHYS_ADDR_BITS
#include "targphys.h"
#endif
@ -27,7 +23,15 @@ enum device_endian {
};
/* address in the RAM (different from a physical address) */
#if defined(CONFIG_XEN_BACKEND) && TARGET_PHYS_ADDR_BITS == 64
typedef uint64_t ram_addr_t;
# define RAM_ADDR_MAX UINT64_MAX
# define RAM_ADDR_FMT "%" PRIx64
#else
typedef unsigned long ram_addr_t;
# define RAM_ADDR_MAX ULONG_MAX
# define RAM_ADDR_FMT "%lx"
#endif
/* memory API */

24
cpus.c
View File

@ -636,7 +636,8 @@ void vm_stop(int reason)
#else /* CONFIG_IOTHREAD */
QemuMutex qemu_global_mutex;
static QemuMutex qemu_fair_mutex;
static QemuCond qemu_io_proceeded_cond;
static bool iothread_requesting_mutex;
static QemuThread io_thread;
@ -672,7 +673,7 @@ int qemu_init_main_loop(void)
qemu_cond_init(&qemu_system_cond);
qemu_cond_init(&qemu_pause_cond);
qemu_cond_init(&qemu_work_cond);
qemu_mutex_init(&qemu_fair_mutex);
qemu_cond_init(&qemu_io_proceeded_cond);
qemu_mutex_init(&qemu_global_mutex);
qemu_mutex_lock(&qemu_global_mutex);
@ -755,17 +756,9 @@ static void qemu_tcg_wait_io_event(void)
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
}
qemu_mutex_unlock(&qemu_global_mutex);
/*
* Users of qemu_global_mutex can be starved, having no chance
* to acquire it since this path will get to it first.
* So use another lock to provide fairness.
*/
qemu_mutex_lock(&qemu_fair_mutex);
qemu_mutex_unlock(&qemu_fair_mutex);
qemu_mutex_lock(&qemu_global_mutex);
while (iothread_requesting_mutex) {
qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
}
for (env = first_cpu; env != NULL; env = env->next_cpu) {
qemu_wait_io_event_common(env);
@ -908,12 +901,13 @@ void qemu_mutex_lock_iothread(void)
if (kvm_enabled()) {
qemu_mutex_lock(&qemu_global_mutex);
} else {
qemu_mutex_lock(&qemu_fair_mutex);
iothread_requesting_mutex = true;
if (qemu_mutex_trylock(&qemu_global_mutex)) {
qemu_cpu_kick_thread(first_cpu);
qemu_mutex_lock(&qemu_global_mutex);
}
qemu_mutex_unlock(&qemu_fair_mutex);
iothread_requesting_mutex = false;
qemu_cond_broadcast(&qemu_io_proceeded_cond);
}
}

View File

@ -809,9 +809,6 @@ int main(int argc, char **argv)
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* init debug */
cpu_set_log_filename(log_file);
@ -830,6 +827,11 @@ int main(int argc, char **argv)
cpu_set_log(mask);
}
if (optind >= argc) {
usage();
}
filename = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));

4
dma.h
View File

@ -20,12 +20,12 @@ typedef struct {
target_phys_addr_t len;
} ScatterGatherEntry;
typedef struct {
struct QEMUSGList {
ScatterGatherEntry *sg;
int nsg;
int nalloc;
target_phys_addr_t size;
} QEMUSGList;
};
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,

172
docs/memory.txt Normal file
View File

@ -0,0 +1,172 @@
The memory API
==============
The memory API models the memory and I/O buses and controllers of a QEMU
machine. It attempts to allow modelling of:
- ordinary RAM
- memory-mapped I/O (MMIO)
- memory controllers that can dynamically reroute physical memory regions
to different destinations
The memory model provides support for
- tracking RAM changes by the guest
- setting up coalesced memory for kvm
- setting up ioeventfd regions for kvm
Memory is modelled as an tree (really acyclic graph) of MemoryRegion objects.
The root of the tree is memory as seen from the CPU's viewpoint (the system
bus). Nodes in the tree represent other buses, memory controllers, and
memory regions that have been rerouted. Leaves are RAM and MMIO regions.
Types of regions
----------------
There are four types of memory regions (all represented by a single C type
MemoryRegion):
- RAM: a RAM region is simply a range of host memory that can be made available
to the guest.
- MMIO: a range of guest memory that is implemented by host callbacks;
each read or write causes a callback to be called on the host.
- container: a container simply includes other memory regions, each at
a different offset. Containers are useful for grouping several regions
into one unit. For example, a PCI BAR may be composed of a RAM region
and an MMIO region.
A container's subregions are usually non-overlapping. In some cases it is
useful to have overlapping regions; for example a memory controller that
can overlay a subregion of RAM with MMIO or ROM, or a PCI controller
that does not prevent card from claiming overlapping BARs.
- alias: a subsection of another region. Aliases allow a region to be
split apart into discontiguous regions. Examples of uses are memory banks
used when the guest address space is smaller than the amount of RAM
addressed, or a memory controller that splits main memory to expose a "PCI
hole". Aliases may point to any type of region, including other aliases,
but an alias may not point back to itself, directly or indirectly.
Region names
------------
Regions are assigned names by the constructor. For most regions these are
only used for debugging purposes, but RAM regions also use the name to identify
live migration sections. This means that RAM region names need to have ABI
stability.
Region lifecycle
----------------
A region is created by one of the constructor functions (memory_region_init*())
and destroyed by the destructor (memory_region_destroy()). In between,
a region can be added to an address space by using memory_region_add_subregion()
and removed using memory_region_del_subregion(). Region attributes may be
changed at any point; they take effect once the region becomes exposed to the
guest.
Overlapping regions and priority
--------------------------------
Usually, regions may not overlap each other; a memory address decodes into
exactly one target. In some cases it is useful to allow regions to overlap,
and sometimes to control which of an overlapping regions is visible to the
guest. This is done with memory_region_add_subregion_overlap(), which
allows the region to overlap any other region in the same container, and
specifies a priority that allows the core to decide which of two regions at
the same address are visible (highest wins).
Visibility
----------
The memory core uses the following rules to select a memory region when the
guest accesses an address:
- all direct subregions of the root region are matched against the address, in
descending priority order
- if the address lies outside the region offset/size, the subregion is
discarded
- if the subregion is a leaf (RAM or MMIO), the seach terminates
- if the subregion is a container, the same algorithm is used within the
subregion (after the address is adjusted by the subregion offset)
- if the subregion is an alias, the search is continues at the alias target
(after the address is adjusted by the subregion offset and alias offset)
Example memory map
------------------
system_memory: container@0-2^48-1
|
+---- lomem: alias@0-0xdfffffff ---> #ram (0-0xdfffffff)
|
+---- himem: alias@0x100000000-0x11fffffff ---> #ram (0xe0000000-0xffffffff)
|
+---- vga-window: alias@0xa0000-0xbfffff ---> #pci (0xa0000-0xbffff)
| (prio 1)
|
+---- pci-hole: alias@0xe0000000-0xffffffff ---> #pci (0xe0000000-0xffffffff)
pci (0-2^32-1)
|
+--- vga-area: container@0xa0000-0xbffff
| |
| +--- alias@0x00000-0x7fff ---> #vram (0x010000-0x017fff)
| |
| +--- alias@0x08000-0xffff ---> #vram (0x020000-0x027fff)
|
+---- vram: ram@0xe1000000-0xe1ffffff
|
+---- vga-mmio: mmio@0xe2000000-0xe200ffff
ram: ram@0x00000000-0xffffffff
The is a (simplified) PC memory map. The 4GB RAM block is mapped into the
system address space via two aliases: "lomem" is a 1:1 mapping of the first
3.5GB; "himem" maps the last 0.5GB at address 4GB. This leaves 0.5GB for the
so-called PCI hole, that allows a 32-bit PCI bus to exist in a system with
4GB of memory.
The memory controller diverts addresses in the range 640K-768K to the PCI
address space. This is modeled using the "vga-window" alias, mapped at a
higher priority so it obscures the RAM at the same addresses. The vga window
can be removed by programming the memory controller; this is modelled by
removing the alias and exposing the RAM underneath.
The pci address space is not a direct child of the system address space, since
we only want parts of it to be visible (we accomplish this using aliases).
It has two subregions: vga-area models the legacy vga window and is occupied
by two 32K memory banks pointing at two sections of the framebuffer.
In addition the vram is mapped as a BAR at address e1000000, and an additional
BAR containing MMIO registers is mapped after it.
Note that if the guest maps a BAR outside the PCI hole, it would not be
visible as the pci-hole alias clips it to a 0.5GB range.
Attributes
----------
Various region attributes (read-only, dirty logging, coalesced mmio, ioeventfd)
can be changed during the region lifecycle. They take effect once the region
is made visible (which can be immediately, later, or never).
MMIO Operations
---------------
MMIO regions are provided with ->read() and ->write() callbacks; in addition
various constraints can be supplied to control how these callbacks are called:
- .valid.min_access_size, .valid.max_access_size define the access sizes
(in bytes) which the device accepts; accesses outside this range will
have device and bus specific behaviour (ignored, or machine check)
- .valid.aligned specifies that the device only accepts naturally aligned
accesses. Unaligned accesses invoke device and bus specific behaviour.
- .impl.min_access_size, .impl.max_access_size define the access sizes
(in bytes) supported by the *implementation*; other access sizes will be
emulated using the ones available. For example a 4-byte write will be
emulated using four 1-byte write, is .impl.max_access_size = 1.
- .impl.valid specifies that the *implementation* only supports unaligned
accesses; unaligned accesses will be emulated by two aligned accesses.
- .old_portio and .old_mmio can be used to ease porting from code using
cpu_register_io_memory() and register_ioport(). They should not be used
in new code.

View File

@ -64,6 +64,8 @@ typedef void * host_reg_t;
#error unsupported CPU
#endif
register CPUState *env asm(AREG0);
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)

39
exec-memory.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Internal memory managment interfaces
*
* Copyright 2011 Red Hat, Inc. and/or its affiliates
*
* Authors:
* Avi Kivity <avi@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#ifndef EXEC_MEMORY_H
#define EXEC_MEMORY_H
/*
* Internal interfaces between memory.c/exec.c/vl.c. Do not #include unless
* you're one of them.
*/
#include "memory.h"
#ifndef CONFIG_USER_ONLY
/* Get the root memory region. This interface should only be used temporarily
* until a proper bus interface is available.
*/
MemoryRegion *get_system_memory(void);
/* Set the root memory region. This region is the system memory map. */
void set_system_memory_map(MemoryRegion *mr);
/* Set the I/O memory region. This region is the I/O memory map. */
void set_system_io_map(MemoryRegion *mr);
#endif
#endif

32
exec.c
View File

@ -33,6 +33,8 @@
#include "kvm.h"
#include "hw/xen.h"
#include "qemu-timer.h"
#include "memory.h"
#include "exec-memory.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@ -109,6 +111,9 @@ int phys_ram_fd;
static int in_migration;
RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
static MemoryRegion *system_memory;
#endif
CPUState *first_cpu;
@ -197,6 +202,7 @@ typedef struct PhysPageDesc {
static void *l1_phys_map[P_L1_SIZE];
static void io_mem_init(void);
static void memory_map_init(void);
/* io memory support */
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
@ -571,6 +577,7 @@ void cpu_exec_init_all(unsigned long tb_size)
code_gen_ptr = code_gen_buffer;
page_init();
#if !defined(CONFIG_USER_ONLY)
memory_map_init();
io_mem_init();
#endif
#if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
@ -2863,13 +2870,13 @@ static void *file_ram_alloc(RAMBlock *block,
static ram_addr_t find_ram_offset(ram_addr_t size)
{
RAMBlock *block, *next_block;
ram_addr_t offset = 0, mingap = ULONG_MAX;
ram_addr_t offset = 0, mingap = RAM_ADDR_MAX;
if (QLIST_EMPTY(&ram_list.blocks))
return 0;
QLIST_FOREACH(block, &ram_list.blocks, next) {
ram_addr_t end, next = ULONG_MAX;
ram_addr_t end, next = RAM_ADDR_MAX;
end = block->offset + block->length;
@ -3081,7 +3088,8 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
#endif
}
if (area != vaddr) {
fprintf(stderr, "Could not remap addr: %lx@%lx\n",
fprintf(stderr, "Could not remap addr: "
RAM_ADDR_FMT "@" RAM_ADDR_FMT "\n",
length, addr);
exit(1);
}
@ -3807,6 +3815,18 @@ static void io_mem_init(void)
DEVICE_NATIVE_ENDIAN);
}
static void memory_map_init(void)
{
system_memory = qemu_malloc(sizeof(*system_memory));
memory_region_init(system_memory, "system", UINT64_MAX);
set_system_memory_map(system_memory);
}
MemoryRegion *get_system_memory(void)
{
return system_memory;
}
#endif /* !defined(CONFIG_USER_ONLY) */
/* physical memory access (slow version, mainly for debug) */
@ -3858,7 +3878,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
uint8_t *ptr;
uint32_t val;
target_phys_addr_t page;
unsigned long pd;
ram_addr_t pd;
PhysPageDesc *p;
while (len > 0) {
@ -3898,7 +3918,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
l = 1;
}
} else {
unsigned long addr1;
ram_addr_t addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* RAM case */
ptr = qemu_get_ram_ptr(addr1);
@ -4052,7 +4072,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
target_phys_addr_t page;
unsigned long pd;
PhysPageDesc *p;
ram_addr_t raddr = ULONG_MAX;
ram_addr_t raddr = RAM_ADDR_MAX;
ram_addr_t rlen;
void *ret;

View File

@ -35,6 +35,78 @@ these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
#define SNAN_BIT_IS_ONE 1
#else
#define SNAN_BIT_IS_ONE 0
#endif
/*----------------------------------------------------------------------------
| The pattern for a default generated half-precision NaN.
*----------------------------------------------------------------------------*/
#if defined(TARGET_ARM)
const float16 float16_default_nan = const_float16(0x7E00);
#elif SNAN_BIT_IS_ONE
const float16 float16_default_nan = const_float16(0x7DFF);
#else
const float16 float16_default_nan = const_float16(0xFE00);
#endif
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#if defined(TARGET_SPARC)
const float32 float32_default_nan = const_float32(0x7FFFFFFF);
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
const float32 float32_default_nan = const_float32(0x7FC00000);
#elif SNAN_BIT_IS_ONE
const float32 float32_default_nan = const_float32(0x7FBFFFFF);
#else
const float32 float32_default_nan = const_float32(0xFFC00000);
#endif
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#if defined(TARGET_SPARC)
const float64 float64_default_nan = const_float64(LIT64( 0x7FFFFFFFFFFFFFFF ));
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
const float64 float64_default_nan = const_float64(LIT64( 0x7FF8000000000000 ));
#elif SNAN_BIT_IS_ONE
const float64 float64_default_nan = const_float64(LIT64( 0x7FF7FFFFFFFFFFFF ));
#else
const float64 float64_default_nan = const_float64(LIT64( 0xFFF8000000000000 ));
#endif
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
#if SNAN_BIT_IS_ONE
#define floatx80_default_nan_high 0x7FFF
#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF )
#else
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
#endif
const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high,
floatx80_default_nan_low);
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#if SNAN_BIT_IS_ONE
#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
#else
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
#define float128_default_nan_low LIT64( 0x0000000000000000 )
#endif
const float128 float128_default_nan = make_float128(float128_default_nan_high,
float128_default_nan_low);
/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap

View File

@ -43,7 +43,7 @@ these four paragraphs for those parts of this code that are retained.
#endif
#include <inttypes.h>
#include "config.h"
#include "config-host.h"
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines the most convenient type that holds
@ -68,12 +68,6 @@ typedef int64_t int64;
#define LIT64( a ) a##LL
#define INLINE static inline
#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
#define SNAN_BIT_IS_ONE 1
#else
#define SNAN_BIT_IS_ONE 0
#endif
#define STATUS_PARAM , float_status *status
#define STATUS(field) status->field
#define STATUS_VAR , status
@ -142,6 +136,7 @@ typedef struct {
uint64_t low, high;
#endif
} float128;
#define make_float128(high_, low_) ((float128) { .high = high_, .low = low_ })
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point underflow tininess-detection mode.
@ -248,13 +243,7 @@ float16 float16_maybe_silence_nan( float16 );
/*----------------------------------------------------------------------------
| The pattern for a default generated half-precision NaN.
*----------------------------------------------------------------------------*/
#if defined(TARGET_ARM)
#define float16_default_nan make_float16(0x7E00)
#elif SNAN_BIT_IS_ONE
#define float16_default_nan make_float16(0x7DFF)
#else
#define float16_default_nan make_float16(0xFE00)
#endif
extern const float16 float16_default_nan;
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
@ -357,15 +346,7 @@ INLINE float32 float32_set_sign(float32 a, int sign)
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#if defined(TARGET_SPARC)
#define float32_default_nan make_float32(0x7FFFFFFF)
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
#define float32_default_nan make_float32(0x7FC00000)
#elif SNAN_BIT_IS_ONE
#define float32_default_nan make_float32(0x7FBFFFFF)
#else
#define float32_default_nan make_float32(0xFFC00000)
#endif
extern const float32 float32_default_nan;
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
@ -470,15 +451,7 @@ INLINE float64 float64_set_sign(float64 a, int sign)
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#if defined(TARGET_SPARC)
#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
#elif SNAN_BIT_IS_ONE
#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
#else
#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
#endif
extern const float64 float64_default_nan;
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
@ -561,17 +534,9 @@ INLINE int floatx80_is_any_nan(floatx80 a)
#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL)
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
#if SNAN_BIT_IS_ONE
#define floatx80_default_nan_high 0x7FFF
#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF )
#else
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
#endif
extern const floatx80 floatx80_default_nan;
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
@ -648,15 +613,8 @@ INLINE int float128_is_any_nan(float128 a)
}
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
| The pattern for a default generated quadruple-precision NaN.
*----------------------------------------------------------------------------*/
#if SNAN_BIT_IS_ONE
#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
#else
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
#define float128_default_nan_low LIT64( 0x0000000000000000 )
#endif
extern const float128 float128_default_nan;
#endif /* !SOFTFLOAT_H */

View File

@ -319,7 +319,7 @@ static int get_char(GDBState *s)
int ret;
for(;;) {
ret = recv(s->fd, &ch, 1, 0);
ret = qemu_recv(s->fd, &ch, 1, 0);
if (ret < 0) {
if (errno == ECONNRESET)
s->fd = -1;

View File

@ -1311,8 +1311,6 @@ show virtual to physical memory mappings (i386, SH4 and SPARC only)
show the active virtual memory mappings (i386 only)
@item info jit
show dynamic compiler info
@item info kvm
show KVM information
@item info numa
show NUMA information
@item info kvm

View File

@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*/
/* 64 external IRQ lines. */

320
hw/acpi.c
View File

@ -20,19 +20,30 @@
#include "pc.h"
#include "acpi.h"
struct acpi_table_header
{
char signature [4]; /* ACPI signature (4 ASCII characters) */
struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */
/* XXX why we have 2 length fields here? */
char sig[4]; /* ACPI signature (4 ASCII characters) */
uint32_t length; /* Length of table, in bytes, including header */
uint8_t revision; /* ACPI Specification minor version # */
uint8_t checksum; /* To make sum of entire table == 0 */
char oem_id [6]; /* OEM identification */
char oem_table_id [8]; /* OEM table identification */
char oem_id[6]; /* OEM identification */
char oem_table_id[8]; /* OEM table identification */
uint32_t oem_revision; /* OEM revision number */
char asl_compiler_id [4]; /* ASL compiler vendor ID */
char asl_compiler_id[4]; /* ASL compiler vendor ID */
uint32_t asl_compiler_revision; /* ASL compiler revision number */
} __attribute__((packed));
#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */
static const char dfl_hdr[ACPI_TABLE_HDR_SIZE] =
"\0\0" /* fake _length (2) */
"QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */
"QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
"QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */
;
char *acpi_tables;
size_t acpi_tables_len;
@ -40,163 +51,198 @@ static int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;
sum = 0;
for(i = 0; i < len; i++)
for (i = 0; i < len; i++) {
sum += data[i];
}
return (-sum) & 0xff;
}
/* like strncpy() but zero-fills the tail of destination */
static void strzcpy(char *dst, const char *src, size_t size)
{
size_t len = strlen(src);
if (len >= size) {
len = size;
} else {
memset(dst + len, 0, size - len);
}
memcpy(dst, src, len);
}
/* XXX fixme: this function uses obsolete argument parsing interface */
int acpi_table_add(const char *t)
{
static const char *dfl_id = "QEMUQEMU";
char buf[1024], *p, *f;
struct acpi_table_header acpi_hdr;
unsigned long val;
uint32_t length;
struct acpi_table_header *acpi_hdr_p;
size_t off;
size_t len, start, allen;
bool has_header;
int changed;
int r;
struct acpi_table_header hdr;
memset(&acpi_hdr, 0, sizeof(acpi_hdr));
if (get_param_value(buf, sizeof(buf), "sig", t)) {
strncpy(acpi_hdr.signature, buf, 4);
} else {
strncpy(acpi_hdr.signature, dfl_id, 4);
}
if (get_param_value(buf, sizeof(buf), "rev", t)) {
val = strtoul(buf, &p, 10);
if (val > 255 || *p != '\0')
goto out;
} else {
val = 1;
}
acpi_hdr.revision = (int8_t)val;
if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
strncpy(acpi_hdr.oem_id, buf, 6);
} else {
strncpy(acpi_hdr.oem_id, dfl_id, 6);
}
if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
strncpy(acpi_hdr.oem_table_id, buf, 8);
} else {
strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
}
if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
val = strtol(buf, &p, 10);
if(*p != '\0')
goto out;
} else {
val = 1;
}
acpi_hdr.oem_revision = cpu_to_le32(val);
if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
strncpy(acpi_hdr.asl_compiler_id, buf, 4);
} else {
strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
}
if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
val = strtol(buf, &p, 10);
if(*p != '\0')
goto out;
} else {
val = 1;
}
acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
if (!get_param_value(buf, sizeof(buf), "data", t)) {
buf[0] = '\0';
}
length = sizeof(acpi_hdr);
f = buf;
while (buf[0]) {
struct stat s;
char *n = strchr(f, ':');
if (n)
*n = '\0';
if(stat(f, &s) < 0) {
fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
goto out;
}
length += s.st_size;
if (!n)
break;
*n = ':';
f = n + 1;
r = 0;
r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0;
r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0;
switch (r) {
case 0:
buf[0] = '\0';
/* fallthrough for default behavior */
case 1:
has_header = false;
break;
case 2:
has_header = true;
break;
default:
fprintf(stderr, "acpitable: both data and file are specified\n");
return -1;
}
if (!acpi_tables) {
acpi_tables_len = sizeof(uint16_t);
acpi_tables = qemu_mallocz(acpi_tables_len);
allen = sizeof(uint16_t);
acpi_tables = qemu_mallocz(allen);
} else {
allen = acpi_tables_len;
}
acpi_tables = qemu_realloc(acpi_tables,
acpi_tables_len + sizeof(uint16_t) + length);
p = acpi_tables + acpi_tables_len;
acpi_tables_len += sizeof(uint16_t) + length;
*(uint16_t*)p = cpu_to_le32(length);
p += sizeof(uint16_t);
memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
off = sizeof(acpi_hdr);
start = allen;
acpi_tables = qemu_realloc(acpi_tables, start + ACPI_TABLE_HDR_SIZE);
allen += has_header ? ACPI_TABLE_PFX_SIZE : ACPI_TABLE_HDR_SIZE;
f = buf;
while (buf[0]) {
struct stat s;
int fd;
char *n = strchr(f, ':');
if (n)
*n = '\0';
fd = open(f, O_RDONLY);
/* now read in the data files, reallocating buffer as needed */
if(fd < 0)
goto out;
if(fstat(fd, &s) < 0) {
close(fd);
goto out;
for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) {
int fd = open(f, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno));
return -1;
}
/* off < length is necessary because file size can be changed
under our foot */
while(s.st_size && off < length) {
int r;
r = read(fd, p + off, s.st_size);
if (r > 0) {
off += r;
s.st_size -= r;
} else if ((r < 0 && errno != EINTR) || r == 0) {
for (;;) {
char data[8192];
r = read(fd, data, sizeof(data));
if (r == 0) {
break;
} else if (r > 0) {
acpi_tables = qemu_realloc(acpi_tables, allen + r);
memcpy(acpi_tables + allen, data, r);
allen += r;
} else if (errno != EINTR) {
fprintf(stderr, "can't read file %s: %s\n",
f, strerror(errno));
close(fd);
goto out;
return -1;
}
}
close(fd);
if (!n)
break;
f = n + 1;
}
if (off < length) {
/* don't pass random value in process to guest */
memset(p + off, 0, length - off);
}
acpi_hdr_p = (struct acpi_table_header*)p;
acpi_hdr_p->length = cpu_to_le32(length);
acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
/* increase number of tables */
(*(uint16_t*)acpi_tables) =
cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
return 0;
out:
if (acpi_tables) {
qemu_free(acpi_tables);
acpi_tables = NULL;
/* now fill in the header fields */
f = acpi_tables + start; /* start of the table */
changed = 0;
/* copy the header to temp place to align the fields */
memcpy(&hdr, has_header ? f : dfl_hdr, ACPI_TABLE_HDR_SIZE);
/* length of the table minus our prefix */
len = allen - start - ACPI_TABLE_PFX_SIZE;
hdr._length = cpu_to_le16(len);
if (get_param_value(buf, sizeof(buf), "sig", t)) {
strzcpy(hdr.sig, buf, sizeof(hdr.sig));
++changed;
}
return -1;
/* length of the table including header, in bytes */
if (has_header) {
/* check if actual length is correct */
val = le32_to_cpu(hdr.length);
if (val != len) {
fprintf(stderr,
"warning: acpitable has wrong length,"
" header says %lu, actual size %zu bytes\n",
val, len);
++changed;
}
}
/* we may avoid putting length here if has_header is true */
hdr.length = cpu_to_le32(len);
if (get_param_value(buf, sizeof(buf), "rev", t)) {
val = strtoul(buf, &p, 0);
if (val > 255 || *p) {
fprintf(stderr, "acpitable: \"rev=%s\" is invalid\n", buf);
return -1;
}
hdr.revision = (uint8_t)val;
++changed;
}
if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
strzcpy(hdr.oem_id, buf, sizeof(hdr.oem_id));
++changed;
}
if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
strzcpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id));
++changed;
}
if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
val = strtol(buf, &p, 0);
if (*p) {
fprintf(stderr, "acpitable: \"oem_rev=%s\" is invalid\n", buf);
return -1;
}
hdr.oem_revision = cpu_to_le32(val);
++changed;
}
if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
strzcpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id));
++changed;
}
if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
val = strtol(buf, &p, 0);
if (*p) {
fprintf(stderr, "acpitable: \"%s=%s\" is invalid\n",
"asl_compiler_rev", buf);
return -1;
}
hdr.asl_compiler_revision = cpu_to_le32(val);
++changed;
}
if (!has_header && !changed) {
fprintf(stderr, "warning: acpitable: no table headers are specified\n");
}
/* now calculate checksum of the table, complete with the header */
/* we may as well leave checksum intact if has_header is true */
/* alternatively there may be a way to set cksum to a given value */
hdr.checksum = 0; /* for checksum calculation */
/* put header back */
memcpy(f, &hdr, sizeof(hdr));
if (changed || !has_header || 1) {
((struct acpi_table_header *)f)->checksum =
acpi_checksum((uint8_t *)f + ACPI_TABLE_PFX_SIZE, len);
}
/* increase number of tables */
(*(uint16_t *)acpi_tables) =
cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1);
acpi_tables_len = allen;
return 0;
}
/* ACPI PM1a EVT */

View File

@ -23,6 +23,7 @@
#include "acpi.h"
#include "sysemu.h"
#include "range.h"
#include "ioport.h"
//#define DEBUG
@ -63,6 +64,7 @@ typedef struct PIIX4PMState {
qemu_irq irq;
qemu_irq smi_irq;
int kvm_enabled;
Notifier machine_ready;
/* for pci hotplug */
ACPIGPE gpe;
@ -311,6 +313,19 @@ static void piix4_powerdown(void *opaque, int irq, int power_failing)
acpi_pm1_evt_power_down(pm1a, tmr);
}
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
uint8_t *pci_conf;
pci_conf = s->dev.config;
pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
pci_conf[0x63] = 0x60;
pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
(isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
}
static int piix4_pm_initfn(PCIDevice *dev)
{
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
@ -337,11 +352,6 @@ static int piix4_pm_initfn(PCIDevice *dev)
/* XXX: which specification is used ? The i82731AB has different
mappings */
pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
pci_conf[0x63] = 0x60;
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
(serial_hds[1] != NULL ? 0x90 : 0);
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
@ -354,6 +364,8 @@ static int piix4_pm_initfn(PCIDevice *dev)
qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
pm_smbus_init(&s->dev.qdev, &s->smb);
s->machine_ready.notify = piix4_pm_machine_ready;
qemu_add_machine_init_done_notifier(&s->machine_ready);
qemu_register_reset(piix4_reset, s);
piix4_acpi_system_hot_add_init(dev->bus, s);

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"

View File

@ -34,6 +34,7 @@
#include "rwhandler.h"
#include "apb_pci.h"
#include "sysemu.h"
#include "exec-memory.h"
/* debug APB */
//#define DEBUG_APB
@ -346,6 +347,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
d->bus = pci_register_bus(&d->busdev.qdev, "pci",
pci_apb_set_irq, pci_pbm_map_irq, d,
get_system_memory(),
0, 32);
pci_bus_set_mem_base(d->bus, mem_base);

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL.
* This code is licensed under the LGPL.
*
*/

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*/
/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*/
#include "hw.h"

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*/
/* This file contains implementation code for the RealView EB interrupt

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL
* This code is licensed under the LGPL
*/
#include "hw.h"

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*/
#include "hw.h"

View File

@ -4,7 +4,7 @@
* Copyright (c) 2005-2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*/
#include "sysbus.h"

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
* This code is licensed under the GPL.
*
* The ARMv7M System controller is fairly tightly tied in with the
* NVIC. Much of that is also implemented here.

View File

@ -30,13 +30,14 @@
#include "loader.h"
#include "elf.h"
#include "cris-boot.h"
#include "blockdev.h"
#define D(x)
#define DNAND(x)
struct nand_state_t
{
NANDFlashState *nand;
DeviceState *nand;
unsigned int rdy:1;
unsigned int ale:1;
unsigned int cle:1;
@ -251,6 +252,7 @@ void axisdev88_init (ram_addr_t ram_size,
CPUState *env;
DeviceState *dev;
SysBusDevice *s;
DriveInfo *nand;
qemu_irq irq[30], nmi[2], *cpu_irq;
void *etraxfs_dmac;
struct etraxfs_dma_client *eth[2] = {NULL, NULL};
@ -278,7 +280,9 @@ void axisdev88_init (ram_addr_t ram_size,
/* Attach a NAND flash to CS1. */
nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
nand = drive_get(IF_MTD, 0, 0);
nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
NAND_MFR_STMICRO, 0x39);
nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);

View File

@ -576,7 +576,7 @@ static void baum_close(struct CharDriverState *chr)
qemu_free(baum);
}
CharDriverState *chr_baum_init(QemuOpts *opts)
int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
{
BaumDriverState *baum;
CharDriverState *chr;
@ -629,7 +629,8 @@ CharDriverState *chr_baum_init(QemuOpts *opts)
qemu_chr_generic_open(chr);
return chr;
*_chr = chr;
return 0;
fail:
qemu_free_timer(baum->cellCount_timer);
@ -638,5 +639,5 @@ fail_handle:
qemu_free(handle);
qemu_free(chr);
qemu_free(baum);
return NULL;
return -EIO;
}

View File

@ -23,4 +23,4 @@
*/
/* char device */
CharDriverState *chr_baum_init(QemuOpts *opts);
int chr_baum_init(QemuOpts *opts, CharDriverState **_chr);

View File

@ -4,7 +4,7 @@
*
* Copyright (c) 2008 Jan Kiszka
*
* This code is licenced under the GNU GPL v2.
* This code is licensed under the GNU GPL v2.
*/
#include "hw.h"
#include "bitbang_i2c.h"

View File

@ -42,6 +42,7 @@
#include "mips.h"
#include "pci_host.h"
#include "sysemu.h"
#include "exec-memory.h"
//#define DEBUG_BONITO
@ -773,7 +774,8 @@ PCIBus *bonito_init(qemu_irq *pic)
dev = qdev_create(NULL, "Bonito-pcihost");
pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
pci_bonito_map_irq, pic, 0x28, 32);
pci_bonito_map_irq, pic, get_system_memory(),
0x28, 32);
pcihost->bus = b;
qdev_init_nofail(dev);

View File

@ -19,7 +19,9 @@
*/
#include "qemu-common.h"
#include "usb.h"
#include "qemu-timer.h"
#include "console.h"
#include "hid.h"
#include "bt.h"
enum hid_transaction_req {
@ -86,7 +88,7 @@ struct bt_hid_device_s {
struct bt_l2cap_device_s btdev;
struct bt_l2cap_conn_params_s *control;
struct bt_l2cap_conn_params_s *interrupt;
USBDevice *usbdev;
HIDState hid;
int proto;
int connected;
@ -111,7 +113,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
bt_l2cap_device_done(&s->btdev);
bt_l2cap_device_init(&s->btdev, net);
s->usbdev->info->handle_reset(s->usbdev);
hid_reset(&s->hid);
s->proto = BT_HID_PROTO_REPORT;
s->state = bt_state_ready;
s->dataother.len = 0;
@ -124,23 +126,16 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
static int bt_hid_out(struct bt_hid_device_s *s)
{
USBPacket p;
if (s->data_type == BT_DATA_OUTPUT) {
p.pid = USB_TOKEN_OUT;
p.devep = 1;
p.data = s->dataout.buffer;
p.len = s->dataout.len;
s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
return s->dataout.len;
/* nothing */
;
}
if (s->data_type == BT_DATA_FEATURE) {
/* XXX:
* does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
* or a SET_REPORT? */
p.devep = 0;
;
}
return -1;
@ -148,14 +143,8 @@ static int bt_hid_out(struct bt_hid_device_s *s)
static int bt_hid_in(struct bt_hid_device_s *s)
{
USBPacket p;
p.pid = USB_TOKEN_IN;
p.devep = 1;
p.data = s->datain.buffer;
p.len = sizeof(s->datain.buffer);
s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
sizeof(s->datain.buffer));
return s->datain.len;
}
@ -323,8 +312,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
break;
}
s->proto = parameter;
s->usbdev->info->handle_control(s->usbdev, NULL, SET_PROTOCOL, s->proto, 0, 0,
NULL);
s->hid.protocol = parameter;
ret = BT_HS_SUCCESSFUL;
break;
@ -333,8 +321,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
ret = BT_HS_ERR_INVALID_PARAMETER;
break;
}
s->usbdev->info->handle_control(s->usbdev, NULL, GET_IDLE, 0, 0, 1,
s->control->sdu_out(s->control, 1));
*s->control->sdu_out(s->control, 1) = s->hid.idle;
s->control->sdu_submit(s->control);
break;
@ -344,11 +331,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
break;
}
/* We don't need to know about the Idle Rate here really,
* so just pass it on to the device. */
ret = s->usbdev->info->handle_control(s->usbdev, NULL,
SET_IDLE, data[1], 0, 0, NULL) ?
BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
s->hid.idle = data[1];
/* XXX: Does this generate a handshake? */
break;
@ -385,9 +368,10 @@ static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
bt_hid_control_transaction(hid, data, len);
}
static void bt_hid_datain(void *opaque)
static void bt_hid_datain(HIDState *hs)
{
struct bt_hid_device_s *hid = opaque;
struct bt_hid_device_s *hid =
container_of(hs, struct bt_hid_device_s, hid);
/* If suspended, wake-up and send a wake-up event first. We might
* want to also inspect the input report and ignore event like
@ -450,7 +434,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid)
hid->btdev.device.inquiry_scan = !hid->connected;
if (hid->connected && !prev) {
hid->usbdev->info->handle_reset(hid->usbdev);
hid_reset(&hid->hid);
hid->proto = BT_HID_PROTO_REPORT;
}
@ -518,7 +502,7 @@ static void bt_hid_destroy(struct bt_device_s *dev)
bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
bt_l2cap_device_done(&hid->btdev);
hid->usbdev->info->handle_destroy(hid->usbdev);
hid_free(&hid->hid);
qemu_free(hid);
}
@ -531,7 +515,7 @@ enum peripheral_minor_class {
};
static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
USBDevice *dev, enum peripheral_minor_class minor)
enum peripheral_minor_class minor)
{
struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
uint32_t class =
@ -551,9 +535,8 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
BT_HID_MTU, bt_hid_new_interrupt_ch);
s->usbdev = dev;
s->btdev.device.lmp_name = s->usbdev->product_desc;
usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
s->btdev.device.lmp_name = "BT Keyboard";
s->btdev.device.handle_destroy = bt_hid_destroy;
@ -566,6 +549,5 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
{
USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
return bt_hid_init(net, dev, class_keyboard);
return bt_hid_init(net, class_keyboard);
}

View File

@ -4,7 +4,7 @@
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
* This code is licenced under the GNU LGPL, version 2 or later.
* This code is licensed under the GNU LGPL, version 2 or later.
*/
/*

View File

@ -4,7 +4,7 @@
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
* This code is licenced under the GNU LGPL, version 2 or later.
* This code is licensed under the GNU LGPL, version 2 or later.
*/
#ifndef CCID_H
@ -29,7 +29,6 @@ struct CCIDCardState {
*/
struct CCIDCardInfo {
DeviceInfo qdev;
void (*print)(Monitor *mon, CCIDCardState *card, int indent);
const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
void (*apdu_from_guest)(CCIDCardState *card,
const uint8_t *apdu,

View File

@ -898,7 +898,7 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(s->conf.macaddr));
s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
s->conf.peer = nd->netdev;

View File

@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GNU GPL v2.
* This code is licensed under the GNU GPL v2.
*/
#include "i2c.h"

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"

View File

@ -602,7 +602,7 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory (base, 0x5c, eth->ethregs);
memcpy(eth->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
eth->conf.macaddr = nd->macaddr;
eth->conf.vlan = nd->vlan;
eth->conf.peer = nd->netdev;

View File

@ -18,14 +18,13 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
int be);
/* nand.c */
typedef struct NANDFlashState NANDFlashState;
NANDFlashState *nand_init(int manf_id, int chip_id);
void nand_done(NANDFlashState *s);
void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
void nand_getpins(NANDFlashState *s, int *rb);
void nand_setio(NANDFlashState *s, uint8_t value);
uint8_t nand_getio(NANDFlashState *s);
void nand_getpins(DeviceState *dev, int *rb);
void nand_setio(DeviceState *dev, uint32_t value);
uint32_t nand_getio(DeviceState *dev);
uint32_t nand_getbuswidth(DeviceState *dev);
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
@ -39,7 +38,9 @@ uint8_t nand_getio(NANDFlashState *s);
/* onenand.c */
void onenand_base_update(void *opaque, target_phys_addr_t new);
void onenand_base_unmap(void *opaque);
void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
void *onenand_init(BlockDriverState *bdrv,
uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
int regshift, qemu_irq irq);
void *onenand_raw_otp(void *opaque);
/* ecc.c */

View File

@ -26,6 +26,7 @@
#include "isa.h"
#include "fw_cfg.h"
#include "sysbus.h"
#include "qemu-error.h"
/* debug firmware config */
//#define DEBUG_FW_CFG
@ -56,6 +57,143 @@ struct FWCfgState {
Notifier machine_ready;
};
#define JPG_FILE 0
#define BMP_FILE 1
static FILE *probe_splashfile(char *filename, int *file_sizep, int *file_typep)
{
FILE *fp = NULL;
int fop_ret;
int file_size;
int file_type = -1;
unsigned char buf[2] = {0, 0};
unsigned int filehead_value = 0;
int bmp_bpp;
fp = fopen(filename, "rb");
if (fp == NULL) {
error_report("failed to open file '%s'.", filename);
return fp;
}
/* check file size */
fseek(fp, 0L, SEEK_END);
file_size = ftell(fp);
if (file_size < 2) {
error_report("file size is less than 2 bytes '%s'.", filename);
fclose(fp);
fp = NULL;
return fp;
}
/* check magic ID */
fseek(fp, 0L, SEEK_SET);
fop_ret = fread(buf, 1, 2, fp);
filehead_value = (buf[0] + (buf[1] << 8)) & 0xffff;
if (filehead_value == 0xd8ff) {
file_type = JPG_FILE;
} else {
if (filehead_value == 0x4d42) {
file_type = BMP_FILE;
}
}
if (file_type < 0) {
error_report("'%s' not jpg/bmp file,head:0x%x.",
filename, filehead_value);
fclose(fp);
fp = NULL;
return fp;
}
/* check BMP bpp */
if (file_type == BMP_FILE) {
fseek(fp, 28, SEEK_SET);
fop_ret = fread(buf, 1, 2, fp);
bmp_bpp = (buf[0] + (buf[1] << 8)) & 0xffff;
if (bmp_bpp != 24) {
error_report("only 24bpp bmp file is supported.");
fclose(fp);
fp = NULL;
return fp;
}
}
/* return values */
*file_sizep = file_size;
*file_typep = file_type;
return fp;
}
static void fw_cfg_bootsplash(FWCfgState *s)
{
int boot_splash_time = -1;
const char *boot_splash_filename = NULL;
char *p;
char *filename;
FILE *fp;
int fop_ret;
int file_size;
int file_type = -1;
const char *temp;
/* get user configuration */
QemuOptsList *plist = qemu_find_opts("boot-opts");
QemuOpts *opts = QTAILQ_FIRST(&plist->head);
if (opts != NULL) {
temp = qemu_opt_get(opts, "splash");
if (temp != NULL) {
boot_splash_filename = temp;
}
temp = qemu_opt_get(opts, "splash-time");
if (temp != NULL) {
p = (char *)temp;
boot_splash_time = strtol(p, (char **)&p, 10);
}
}
/* insert splash time if user configurated */
if (boot_splash_time >= 0) {
/* validate the input */
if (boot_splash_time > 0xffff) {
error_report("splash time is big than 65535, force it to 65535.");
boot_splash_time = 0xffff;
}
/* use little endian format */
qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
}
/* insert splash file if user configurated */
if (boot_splash_filename != NULL) {
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
if (filename == NULL) {
error_report("failed to find file '%s'.", boot_splash_filename);
return;
}
/* probing the file */
fp = probe_splashfile(filename, &file_size, &file_type);
if (fp == NULL) {
qemu_free(filename);
return;
}
/* loading file data */
if (boot_splash_filedata != NULL) {
qemu_free(boot_splash_filedata);
}
boot_splash_filedata = qemu_malloc(file_size);
boot_splash_filedata_size = file_size;
fseek(fp, 0L, SEEK_SET);
fop_ret = fread(boot_splash_filedata, 1, file_size, fp);
fclose(fp);
/* insert data */
if (file_type == JPG_FILE) {
fw_cfg_add_file(s, "bootsplash.jpg",
boot_splash_filedata, boot_splash_filedata_size);
} else {
fw_cfg_add_file(s, "bootsplash.bmp",
boot_splash_filedata, boot_splash_filedata_size);
}
qemu_free(filename);
}
}
static void fw_cfg_write(FWCfgState *s, uint8_t value)
{
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
@ -316,7 +454,7 @@ int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data,
return 1;
}
static void fw_cfg_machine_ready(struct Notifier* n)
static void fw_cfg_machine_ready(struct Notifier *n, void *data)
{
uint32_t len;
FWCfgState *s = container_of(n, FWCfgState, machine_ready);
@ -352,7 +490,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
fw_cfg_bootsplash(s);
s->machine_ready.notify = fw_cfg_machine_ready;
qemu_add_machine_init_done_notifier(&s->machine_ready);

View File

@ -61,7 +61,8 @@ static void pci_grackle_reset(void *opaque)
{
}
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
MemoryRegion *address_space)
{
DeviceState *dev;
SysBusDevice *s;
@ -74,7 +75,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
pci_grackle_set_irq,
pci_grackle_map_irq,
pic, 0, 4);
pic, address_space, 0, 4);
pci_create_simple(d->host_state.bus, 0, "grackle");

View File

@ -27,6 +27,7 @@
#include "pci.h"
#include "pci_host.h"
#include "pc.h"
#include "exec-memory.h"
//#define DEBUG
@ -1092,7 +1093,8 @@ PCIBus *gt64120_register(qemu_irq *pic)
d = FROM_SYSBUS(GT64120State, s);
d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
gt64120_pci_set_irq, gt64120_pci_map_irq,
pic, PCI_DEVFN(18, 0), 4);
pic, get_system_memory(),
PCI_DEVFN(18, 0), 4);
d->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, d,
DEVICE_NATIVE_ENDIAN);

403
hw/hid.c Normal file
View File

@ -0,0 +1,403 @@
/*
* QEMU HID devices
*
* Copyright (c) 2005 Fabrice Bellard
* Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "console.h"
#include "qemu-timer.h"
#include "hid.h"
#define HID_USAGE_ERROR_ROLLOVER 0x01
#define HID_USAGE_POSTFAIL 0x02
#define HID_USAGE_ERROR_UNDEFINED 0x03
/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
* above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
static const uint8_t hid_usage_keys[0x100] = {
0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
bool hid_has_events(HIDState *hs)
{
return hs->n > 0;
}
void hid_set_next_idle(HIDState *hs, int64_t curtime)
{
hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
}
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
{
e->xdx = e->ydy = e->dz = 0;
e->buttons_state = buttons;
}
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
int x1, int y1, int z1) {
if (xyrel) {
e->xdx += x1;
e->ydy += y1;
} else {
e->xdx = x1;
e->ydy = y1;
/* Windows drivers do not like the 0/0 position and ignore such
* events. */
if (!(x1 | y1)) {
x1 = 1;
}
}
e->dz += z1;
}
static void hid_pointer_event(void *opaque,
int x1, int y1, int z1, int buttons_state)
{
HIDState *hs = opaque;
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
/* We combine events where feasible to keep the queue small. We shouldn't
* combine anything with the first event of a particular button state, as
* that would change the location of the button state change. When the
* queue is empty, a second event is needed because we don't know if
* the first event changed the button state. */
if (hs->n == QUEUE_LENGTH) {
/* Queue full. Discard old button state, combine motion normally. */
hs->ptr.queue[use_slot].buttons_state = buttons_state;
} else if (hs->n < 2 ||
hs->ptr.queue[use_slot].buttons_state != buttons_state ||
hs->ptr.queue[previous_slot].buttons_state !=
hs->ptr.queue[use_slot].buttons_state) {
/* Cannot or should not combine, so add an empty item to the queue. */
QUEUE_INCR(use_slot);
hs->n++;
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
}
hid_pointer_event_combine(&hs->ptr.queue[use_slot],
hs->kind == HID_MOUSE,
x1, y1, z1);
hs->event(hs);
}
static void hid_keyboard_event(void *opaque, int keycode)
{
HIDState *hs = opaque;
int slot;
if (hs->n == QUEUE_LENGTH) {
fprintf(stderr, "usb-kbd: warning: key event queue full\n");
return;
}
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
hs->kbd.keycodes[slot] = keycode;
hs->event(hs);
}
static void hid_keyboard_process_keycode(HIDState *hs)
{
uint8_t hid_code, key;
int i, keycode, slot;
if (hs->n == 0) {
return;
}
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
keycode = hs->kbd.keycodes[slot];
key = keycode & 0x7f;
hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
hs->kbd.modifiers &= ~(1 << 8);
switch (hid_code) {
case 0x00:
return;
case 0xe0:
if (hs->kbd.modifiers & (1 << 9)) {
hs->kbd.modifiers ^= 3 << 8;
return;
}
case 0xe1 ... 0xe7:
if (keycode & (1 << 7)) {
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
return;
}
case 0xe8 ... 0xef:
hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
return;
}
if (keycode & (1 << 7)) {
for (i = hs->kbd.keys - 1; i >= 0; i--) {
if (hs->kbd.key[i] == hid_code) {
hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
hs->kbd.key[hs->kbd.keys] = 0x00;
break;
}
}
if (i < 0) {
return;
}
} else {
for (i = hs->kbd.keys - 1; i >= 0; i--) {
if (hs->kbd.key[i] == hid_code) {
break;
}
}
if (i < 0) {
if (hs->kbd.keys < sizeof(hs->kbd.key)) {
hs->kbd.key[hs->kbd.keys++] = hid_code;
}
} else {
return;
}
}
}
static inline int int_clamp(int val, int vmin, int vmax)
{
if (val < vmin) {
return vmin;
} else if (val > vmax) {
return vmax;
} else {
return val;
}
}
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
{
int dx, dy, dz, b, l;
int index;
HIDPointerEvent *e;
if (!hs->ptr.mouse_grabbed) {
qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
hs->ptr.mouse_grabbed = 1;
}
/* When the buffer is empty, return the last event. Relative
movements will all be zero. */
index = (hs->n ? hs->head : hs->head - 1);
e = &hs->ptr.queue[index & QUEUE_MASK];
if (hs->kind == HID_MOUSE) {
dx = int_clamp(e->xdx, -127, 127);
dy = int_clamp(e->ydy, -127, 127);
e->xdx -= dx;
e->ydy -= dy;
} else {
dx = e->xdx;
dy = e->ydy;
}
dz = int_clamp(e->dz, -127, 127);
e->dz -= dz;
b = 0;
if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
b |= 0x01;
}
if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
b |= 0x02;
}
if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
b |= 0x04;
}
if (hs->n &&
!e->dz &&
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
/* that deals with this event */
QUEUE_INCR(hs->head);
hs->n--;
}
/* Appears we have to invert the wheel direction */
dz = 0 - dz;
l = 0;
switch (hs->kind) {
case HID_MOUSE:
if (len > l) {
buf[l++] = b;
}
if (len > l) {
buf[l++] = dx;
}
if (len > l) {
buf[l++] = dy;
}
if (len > l) {
buf[l++] = dz;
}
break;
case HID_TABLET:
if (len > l) {
buf[l++] = b;
}
if (len > l) {
buf[l++] = dx & 0xff;
}
if (len > l) {
buf[l++] = dx >> 8;
}
if (len > l) {
buf[l++] = dy & 0xff;
}
if (len > l) {
buf[l++] = dy >> 8;
}
if (len > l) {
buf[l++] = dz;
}
break;
default:
abort();
}
return l;
}
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
{
if (len < 2) {
return 0;
}
hid_keyboard_process_keycode(hs);
buf[0] = hs->kbd.modifiers & 0xff;
buf[1] = 0;
if (hs->kbd.keys > 6) {
memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
} else {
memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
}
return MIN(8, len);
}
int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
{
if (len > 0) {
int ledstate = 0;
/* 0x01: Num Lock LED
* 0x02: Caps Lock LED
* 0x04: Scroll Lock LED
* 0x08: Compose LED
* 0x10: Kana LED */
hs->kbd.leds = buf[0];
if (hs->kbd.leds & 0x04) {
ledstate |= QEMU_SCROLL_LOCK_LED;
}
if (hs->kbd.leds & 0x01) {
ledstate |= QEMU_NUM_LOCK_LED;
}
if (hs->kbd.leds & 0x02) {
ledstate |= QEMU_CAPS_LOCK_LED;
}
kbd_put_ledstate(ledstate);
}
return 0;
}
void hid_reset(HIDState *hs)
{
switch (hs->kind) {
case HID_KEYBOARD:
qemu_add_kbd_event_handler(hid_keyboard_event, hs);
memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
hs->kbd.keys = 0;
break;
case HID_MOUSE:
case HID_TABLET:
memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
break;
}
hs->head = 0;
hs->n = 0;
hs->protocol = 1;
hs->idle = 0;
}
void hid_free(HIDState *hs)
{
switch (hs->kind) {
case HID_KEYBOARD:
qemu_remove_kbd_event_handler();
break;
case HID_MOUSE:
case HID_TABLET:
qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
break;
}
}
void hid_init(HIDState *hs, int kind, HIDEventFunc event)
{
hs->kind = kind;
hs->event = event;
if (hs->kind == HID_MOUSE) {
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
0, "QEMU HID Mouse");
} else if (hs->kind == HID_TABLET) {
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
1, "QEMU HID Tablet");
}
}

58
hw/hid.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef QEMU_HID_H
#define QEMU_HID_H
#define HID_MOUSE 1
#define HID_TABLET 2
#define HID_KEYBOARD 3
typedef struct HIDPointerEvent {
int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
int32_t dz, buttons_state;
} HIDPointerEvent;
#define QUEUE_LENGTH 16 /* should be enough for a triple-click */
#define QUEUE_MASK (QUEUE_LENGTH-1u)
#define QUEUE_INCR(v) ((v)++, (v) &= QUEUE_MASK)
typedef struct HIDState HIDState;
typedef void (*HIDEventFunc)(HIDState *s);
typedef struct HIDMouseState {
HIDPointerEvent queue[QUEUE_LENGTH];
int mouse_grabbed;
QEMUPutMouseEntry *eh_entry;
} HIDMouseState;
typedef struct HIDKeyboardState {
uint32_t keycodes[QUEUE_LENGTH];
uint16_t modifiers;
uint8_t leds;
uint8_t key[16];
int32_t keys;
} HIDKeyboardState;
struct HIDState {
union {
HIDMouseState ptr;
HIDKeyboardState kbd;
};
uint32_t head; /* index into circular queue */
uint32_t n;
int kind;
int32_t protocol;
uint8_t idle;
int64_t next_idle_clock;
HIDEventFunc event;
};
void hid_init(HIDState *hs, int kind, HIDEventFunc event);
void hid_reset(HIDState *hs);
void hid_free(HIDState *hs);
bool hid_has_events(HIDState *hs);
void hid_set_next_idle(HIDState *hs, int64_t curtime);
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
#endif /* QEMU_HID_H */

View File

@ -324,6 +324,7 @@ typedef struct VMStateSubsection {
struct VMStateDescription {
const char *name;
int unmigratable;
int version_id;
int minimum_version_id;
int minimum_version_id_old;

View File

@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL.
* This code is licensed under the LGPL.
*/
#include "i2c.h"

View File

@ -72,6 +72,6 @@ void wm8750_set_bclk_in(void *opaque, int new_hz);
void tmp105_set(i2c_slave *i2c, int temp);
/* lm832x.c */
void lm832x_key_event(i2c_slave *i2c, int key, int state);
void lm832x_key_event(DeviceState *dev, int key, int state);
#endif

View File

@ -13,6 +13,7 @@ ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
/* ide-pci.c */
void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
int secondary_ide_enabled);
PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);

View File

@ -72,6 +72,11 @@
#include <hw/ide/pci.h>
#include <hw/ide/ahci.h>
static const VMStateDescription vmstate_ahci = {
.name = "ahci",
.unmigratable = 1,
};
static int pci_ich9_ahci_init(PCIDevice *dev)
{
struct AHCIPCIState *d;
@ -123,6 +128,7 @@ static PCIDeviceInfo ich_ahci_info[] = {
.qdev.name = "ich9-ahci",
.qdev.alias = "ahci",
.qdev.size = sizeof(AHCIPCIState),
.qdev.vmsd = &vmstate_ahci,
.init = pci_ich9_ahci_init,
.exit = pci_ich9_uninit,
.config_write = pci_ich9_write_config,

View File

@ -149,6 +149,42 @@ static int pci_piix_ide_initfn(PCIDevice *dev)
return 0;
}
static int pci_piix3_xen_ide_unplug(DeviceState *dev)
{
PCIDevice *pci_dev;
PCIIDEState *pci_ide;
DriveInfo *di;
int i = 0;
pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
pci_ide = DO_UPCAST(PCIIDEState, dev, pci_dev);
for (; i < 3; i++) {
di = drive_get_by_index(IF_IDE, i);
if (di != NULL && di->bdrv != NULL && !di->bdrv->removable) {
DeviceState *ds = bdrv_get_attached(di->bdrv);
if (ds) {
bdrv_detach(di->bdrv, ds);
}
bdrv_close(di->bdrv);
pci_ide->bus[di->bus].ifs[di->unit].bs = NULL;
drive_put_ref(di);
}
}
qdev_reset_all(&(pci_ide->dev.qdev));
return 0;
}
PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
{
PCIDevice *dev;
dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
dev->qdev.info->unplug = pci_piix3_xen_ide_unplug;
pci_ide_create_devs(dev, hd_table);
return dev;
}
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
@ -181,6 +217,14 @@ static PCIDeviceInfo piix_ide_info[] = {
.vendor_id = PCI_VENDOR_ID_INTEL,
.device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
.class_id = PCI_CLASS_STORAGE_IDE,
},{
.qdev.name = "piix3-ide-xen",
.qdev.size = sizeof(PCIIDEState),
.qdev.no_user = 1,
.init = pci_piix_ide_initfn,
.vendor_id = PCI_VENDOR_ID_INTEL,
.device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
.class_id = PCI_CLASS_STORAGE_IDE,
},{
.qdev.name = "piix4-ide",
.qdev.size = sizeof(PCIIDEState),

View File

@ -31,6 +31,10 @@ static struct BusInfo ide_bus_info = {
.name = "IDE",
.size = sizeof(IDEBus),
.get_fw_dev_path = idebus_get_fw_dev_path,
.props = (Property[]) {
DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
DEFINE_PROP_END_OF_LIST(),
},
};
void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
@ -174,7 +178,6 @@ static int ide_drive_initfn(IDEDevice *dev)
}
#define DEFINE_IDE_DEV_PROPERTIES() \
DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1), \
DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
DEFINE_PROP_STRING("serial", IDEDrive, dev.serial)

View File

@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "sysbus.h"

View File

@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery, LLC.
* Written by Paul Brook
*
* This code is licenced under the GNU GPL v2
* This code is licensed under the GNU GPL v2
*/
#include "sysbus.h"

View File

@ -474,9 +474,9 @@ static int lm8323_init(i2c_slave *i2c)
return 0;
}
void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
void lm832x_key_event(DeviceState *dev, int key, int state)
{
LM823KbdState *s = (LM823KbdState *) i2c;
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE_FROM_QDEV(dev));
if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
return;

View File

@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL.
* This code is licensed under the LGPL.
*/
/* ??? Need to check if the {read,write}[wl] routines work properly on

View File

@ -4,7 +4,7 @@
*
* Copyright (c) 2008 Jan Kiszka
*
* This code is licenced under the GNU GPL v2.
* This code is licensed under the GNU GPL v2.
*/
#include "sysbus.h"
#include "hw.h"

View File

@ -99,6 +99,7 @@ typedef struct RTCState {
QEMUTimer *coalesced_timer;
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
Notifier clock_reset_notifier;
} RTCState;
static void rtc_set_time(RTCState *s);
@ -572,6 +573,22 @@ static const VMStateDescription vmstate_rtc = {
}
};
static void rtc_notify_clock_reset(Notifier *notifier, void *data)
{
RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
int64_t now = *(int64_t *)data;
rtc_set_date_from_host(&s->dev);
s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);
rtc_timer_update(s, now);
#ifdef TARGET_I386
if (rtc_td_hack) {
rtc_coalesced_timer_update(s);
}
#endif
}
static void rtc_reset(void *opaque)
{
RTCState *s = opaque;
@ -608,6 +625,9 @@ static int rtc_initfn(ISADevice *dev)
s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
s->clock_reset_notifier.notify = rtc_notify_clock_reset;
qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
s->next_second_time =
qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"
#include "net.h"
@ -471,7 +471,7 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(base, 0x400, s->mmio_index);
memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
s->conf.peer = nd->netdev;

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
* This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"

View File

@ -234,11 +234,11 @@ static void softusb_usbdev_datain(void *opaque)
USBPacket p;
p.pid = USB_TOKEN_IN;
p.devep = 1;
p.data = s->kbd_usb_buffer;
p.len = sizeof(s->kbd_usb_buffer);
usb_packet_init(&p);
usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
usb_packet_addbuf(&p, s->kbd_usb_buffer, sizeof(s->kbd_usb_buffer));
s->usbdev->info->handle_data(s->usbdev, &p);
usb_packet_cleanup(&p);
softusb_kbd_changed(s);
}
@ -310,10 +310,12 @@ static int milkymist_softusb_init(SysBusDevice *dev)
usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
/* our two ports */
/* FIXME: claim to support full speed devices. qemu mouse and keyboard
* report themselves as full speed devices. */
usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
USB_SPEED_MASK_LOW);
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
USB_SPEED_MASK_LOW);
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
/* and finally create an usb keyboard */
s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");

View File

@ -258,7 +258,7 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
s->irq = irq;
if (nd) {
memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
s->conf.peer = nd->netdev;

Some files were not shown because too many files have changed in this diff Show More