mirror of https://github.com/xqemu/xqemu.git
Merge branch 'master' of git://git.qemu.org/qemu
This commit is contained in:
commit
a67a47d2b5
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
------------------
|
||||
|
|
22
Makefile
22
Makefile
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
98
async.c
98
async.c
|
@ -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
|
||||
|
|
61
balloon.c
61
balloon.c
|
@ -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;
|
||||
|
|
12
balloon.h
12
balloon.h
|
@ -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
310
block.c
|
@ -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)
|
||||
|
|
7
block.h
7
block.h
|
@ -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);
|
||||
|
|
186
block/qcow.c
186
block/qcow.c
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
240
block/qcow2.c
240
block/qcow2.c
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
10
block_int.h
10
block_int.h
|
@ -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);
|
||||
|
|
17
blockdev.c
17
blockdev.c
|
@ -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;
|
||||
|
|
|
@ -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
474
bswap.h
|
@ -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 */
|
||||
|
|
11
compatfd.c
11
compatfd.c
|
@ -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
|
||||
}
|
||||
|
|
|
@ -39,5 +39,6 @@ struct qemu_signalfd_siginfo {
|
|||
};
|
||||
|
||||
int qemu_signalfd(const sigset_t *mask);
|
||||
bool qemu_signalfd_available(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
446
cpu-all.h
|
@ -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)
|
||||
|
|
12
cpu-common.h
12
cpu-common.h
|
@ -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
24
cpus.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
4
dma.h
|
@ -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,
|
||||
|
|
|
@ -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.
|
|
@ -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)
|
||||
|
|
|
@ -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
32
exec.c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
320
hw/acpi.c
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -23,4 +23,4 @@
|
|||
*/
|
||||
|
||||
/* char device */
|
||||
CharDriverState *chr_baum_init(QemuOpts *opts);
|
||||
int chr_baum_init(QemuOpts *opts, CharDriverState **_chr);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
62
hw/bt-hid.c
62
hw/bt-hid.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
17
hw/flash.h
17
hw/flash.h
|
@ -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 */
|
||||
|
|
142
hw/fw_cfg.c
142
hw/fw_cfg.c
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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 */
|
1
hw/hw.h
1
hw/hw.h
|
@ -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;
|
||||
|
|
2
hw/i2c.c
2
hw/i2c.c
|
@ -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"
|
||||
|
|
2
hw/i2c.h
2
hw/i2c.h
|
@ -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
|
||||
|
|
1
hw/ide.h
1
hw/ide.h
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue